[feat](trx-core): add WSPR decode plumbing across stack

Introduce WSPR command/state/protocol/transport wiring and integrate lifecycle, history, and frontend API paths mirroring the FT8 architecture.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
2026-02-12 22:38:05 +01:00
parent 8e59e205a8
commit 63ba6882cd
16 changed files with 310 additions and 5 deletions
+1
View File
@@ -14,6 +14,7 @@ pub const AUDIO_MSG_TX_FRAME: u8 = 0x02;
pub const AUDIO_MSG_APRS_DECODE: u8 = 0x03;
pub const AUDIO_MSG_CW_DECODE: u8 = 0x04;
pub const AUDIO_MSG_FT8_DECODE: u8 = 0x05;
pub const AUDIO_MSG_WSPR_DECODE: u8 = 0x06;
/// Maximum payload size (1 MB) to reject bogus frames early.
const MAX_PAYLOAD_SIZE: u32 = 1_048_576;
+16
View File
@@ -16,6 +16,8 @@ pub enum DecodedMessage {
Cw(CwEvent),
#[serde(rename = "ft8")]
Ft8(Ft8Message),
#[serde(rename = "wspr")]
Wspr(WsprMessage),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -62,3 +64,17 @@ pub struct Ft8Message {
/// Decoded message text
pub message: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WsprMessage {
/// UTC timestamp (milliseconds since epoch)
pub ts_ms: i64,
/// Approximate SNR (dB)
pub snr_db: f32,
/// Time offset within slot (seconds)
pub dt_s: f32,
/// Audio frequency (Hz)
pub freq_hz: f32,
/// Decoded message text
pub message: String,
}
+2
View File
@@ -25,7 +25,9 @@ pub enum RigCommand {
SetCwWpm(u32),
SetCwToneHz(u32),
SetFt8DecodeEnabled(bool),
SetWsprDecodeEnabled(bool),
ResetAprsDecoder,
ResetCwDecoder,
ResetFt8Decoder,
ResetWsprDecoder,
}
+3 -1
View File
@@ -508,9 +508,11 @@ pub fn command_from_rig_command(cmd: RigCommand) -> Box<dyn RigCommandHandler> {
| RigCommand::SetCwWpm(_)
| RigCommand::SetCwToneHz(_)
| RigCommand::SetFt8DecodeEnabled(_)
| RigCommand::SetWsprDecodeEnabled(_)
| RigCommand::ResetAprsDecoder
| RigCommand::ResetCwDecoder
| RigCommand::ResetFt8Decoder => Box::new(GetSnapshotCommand),
| RigCommand::ResetFt8Decoder
| RigCommand::ResetWsprDecoder => Box::new(GetSnapshotCommand),
}
}
+11
View File
@@ -31,6 +31,8 @@ pub struct RigState {
#[serde(default)]
pub ft8_decode_enabled: bool,
#[serde(default)]
pub wspr_decode_enabled: bool,
#[serde(default)]
pub cw_auto: bool,
#[serde(default)]
pub cw_wpm: u32,
@@ -42,6 +44,8 @@ pub struct RigState {
pub cw_decode_reset_seq: u64,
#[serde(default, skip_serializing)]
pub ft8_decode_reset_seq: u64,
#[serde(default, skip_serializing)]
pub wspr_decode_reset_seq: u64,
}
/// Mode supported by the rig.
@@ -113,12 +117,14 @@ impl RigState {
aprs_decode_enabled: false,
cw_decode_enabled: false,
ft8_decode_enabled: false,
wspr_decode_enabled: false,
cw_auto: true,
cw_wpm: 15,
cw_tone_hz: 700,
aprs_decode_reset_seq: 0,
cw_decode_reset_seq: 0,
ft8_decode_reset_seq: 0,
wspr_decode_reset_seq: 0,
}
}
@@ -169,9 +175,11 @@ impl RigState {
cw_wpm: snapshot.cw_wpm,
cw_tone_hz: snapshot.cw_tone_hz,
ft8_decode_enabled: snapshot.ft8_decode_enabled,
wspr_decode_enabled: snapshot.wspr_decode_enabled,
aprs_decode_reset_seq: 0,
cw_decode_reset_seq: 0,
ft8_decode_reset_seq: 0,
wspr_decode_reset_seq: 0,
}
}
@@ -202,6 +210,7 @@ impl RigState {
cw_wpm: self.cw_wpm,
cw_tone_hz: self.cw_tone_hz,
ft8_decode_enabled: self.ft8_decode_enabled,
wspr_decode_enabled: self.wspr_decode_enabled,
})
}
@@ -251,6 +260,8 @@ pub struct RigSnapshot {
#[serde(default)]
pub ft8_decode_enabled: bool,
#[serde(default)]
pub wspr_decode_enabled: bool,
#[serde(default)]
pub cw_auto: bool,
#[serde(default)]
pub cw_wpm: u32,