[feat](trx-rs): add HF APRS decoder (300 baud, 1600/1800 Hz AFSK)

Adds a second APRS demodulator path tuned for the HF APRS standard
(300 baud Bell 103-style AFSK, mark=1600 Hz / space=1800 Hz), active
on RigMode::DIG.  Shares AX.25 framing, APRS parsing, APRS-IS uplink,
and frontend display with the existing VHF stack.

- trx-aprs: parameterise Demodulator::new(); add AprsDecoder::new_hf()
- trx-core: HfAprs variant in DecodedMessage; hf_aprs_decode_enabled /
  hf_aprs_decode_reset_seq in RigState/RigSnapshot; SetHfAprsDecodeEnabled
  and ResetHfAprsDecoder commands; handlers.rs fallback arm updated
- trx-protocol: client command variants + bidirectional mapping; test
  fixture updated
- trx-server: run_hf_aprs_decoder() task (activates on DIG mode);
  hf_aprs history in DecoderHistories; rig_task command dispatch;
  aprsfi uplink forwards HfAprs via OR-pattern
- trx-frontend: hf_aprs_history in FrontendRuntimeContext
- trx-frontend-http: prune/record/snapshot/clear helpers; SSE history
  replay; toggle_hf_aprs_decode + clear_hf_aprs_decode endpoints;
  /hf-aprs.js endpoint; HF APRS tab in web UI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-03-08 20:17:37 +01:00
parent ee821a71b1
commit 19d6d2e50b
19 changed files with 740 additions and 11 deletions
+2
View File
@@ -16,6 +16,8 @@ pub enum DecodedMessage {
Vdes(VdesMessage),
#[serde(rename = "aprs")]
Aprs(AprsPacket),
#[serde(rename = "hf_aprs")]
HfAprs(AprsPacket),
#[serde(rename = "cw")]
Cw(CwEvent),
#[serde(rename = "ft8")]
+2
View File
@@ -22,6 +22,7 @@ pub enum RigCommand {
Lock,
Unlock,
SetAprsDecodeEnabled(bool),
SetHfAprsDecodeEnabled(bool),
SetCwDecodeEnabled(bool),
SetCwAuto(bool),
SetCwWpm(u32),
@@ -29,6 +30,7 @@ pub enum RigCommand {
SetFt8DecodeEnabled(bool),
SetWsprDecodeEnabled(bool),
ResetAprsDecoder,
ResetHfAprsDecoder,
ResetCwDecoder,
ResetFt8Decoder,
ResetWsprDecoder,
@@ -510,6 +510,8 @@ pub fn command_from_rig_command(cmd: RigCommand) -> Box<dyn RigCommandHandler> {
| RigCommand::SetCwToneHz(_)
| RigCommand::SetFt8DecodeEnabled(_)
| RigCommand::SetWsprDecodeEnabled(_)
| RigCommand::SetHfAprsDecodeEnabled(_)
| RigCommand::ResetHfAprsDecoder
| RigCommand::ResetAprsDecoder
| RigCommand::ResetCwDecoder
| RigCommand::ResetFt8Decoder
+11
View File
@@ -31,6 +31,8 @@ pub struct RigState {
#[serde(default)]
pub aprs_decode_enabled: bool,
#[serde(default)]
pub hf_aprs_decode_enabled: bool,
#[serde(default)]
pub cw_decode_enabled: bool,
#[serde(default)]
pub ft8_decode_enabled: bool,
@@ -53,6 +55,8 @@ pub struct RigState {
#[serde(default, skip_serializing)]
pub aprs_decode_reset_seq: u64,
#[serde(default, skip_serializing)]
pub hf_aprs_decode_reset_seq: u64,
#[serde(default, skip_serializing)]
pub cw_decode_reset_seq: u64,
#[serde(default, skip_serializing)]
pub ft8_decode_reset_seq: u64,
@@ -132,6 +136,7 @@ impl RigState {
server_longitude: None,
pskreporter_status: None,
aprs_decode_enabled: false,
hf_aprs_decode_enabled: false,
cw_decode_enabled: true,
ft8_decode_enabled: false,
wspr_decode_enabled: false,
@@ -141,6 +146,7 @@ impl RigState {
filter: None,
spectrum: None,
aprs_decode_reset_seq: 0,
hf_aprs_decode_reset_seq: 0,
cw_decode_reset_seq: 0,
ft8_decode_reset_seq: 0,
wspr_decode_reset_seq: 0,
@@ -193,6 +199,7 @@ impl RigState {
server_longitude: snapshot.server_longitude,
pskreporter_status: snapshot.pskreporter_status,
aprs_decode_enabled: snapshot.aprs_decode_enabled,
hf_aprs_decode_enabled: snapshot.hf_aprs_decode_enabled,
cw_decode_enabled: snapshot.cw_decode_enabled,
cw_auto: snapshot.cw_auto,
cw_wpm: snapshot.cw_wpm,
@@ -202,6 +209,7 @@ impl RigState {
filter: snapshot.filter,
spectrum: None, // spectrum flows through /api/spectrum, not persistent state
aprs_decode_reset_seq: 0,
hf_aprs_decode_reset_seq: 0,
cw_decode_reset_seq: 0,
ft8_decode_reset_seq: 0,
wspr_decode_reset_seq: 0,
@@ -232,6 +240,7 @@ impl RigState {
server_longitude: self.server_longitude,
pskreporter_status: self.pskreporter_status.clone(),
aprs_decode_enabled: self.aprs_decode_enabled,
hf_aprs_decode_enabled: self.hf_aprs_decode_enabled,
cw_decode_enabled: self.cw_decode_enabled,
cw_auto: self.cw_auto,
cw_wpm: self.cw_wpm,
@@ -384,6 +393,8 @@ pub struct RigSnapshot {
#[serde(default)]
pub aprs_decode_enabled: bool,
#[serde(default)]
pub hf_aprs_decode_enabled: bool,
#[serde(default)]
pub cw_decode_enabled: bool,
#[serde(default)]
pub ft8_decode_enabled: bool,