From 19d6d2e50b249630bc057cf6f804fbc338e243d5 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 8 Mar 2026 20:17:37 +0100 Subject: [PATCH] [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 Signed-off-by: Stan Grams --- src/decoders/trx-aprs/src/lib.rs | 26 +- src/trx-client/trx-frontend/src/lib.rs | 3 + .../trx-frontend-http/assets/web/app.js | 1 + .../trx-frontend-http/assets/web/index.html | 39 ++ .../assets/web/plugins/hf-aprs.js | 409 ++++++++++++++++++ .../trx-frontend/trx-frontend-http/src/api.rs | 37 ++ .../trx-frontend-http/src/audio.rs | 39 ++ .../trx-frontend-http/src/status.rs | 1 + src/trx-core/src/decode.rs | 2 + src/trx-core/src/rig/command.rs | 2 + src/trx-core/src/rig/controller/handlers.rs | 2 + src/trx-core/src/rig/state.rs | 11 + src/trx-protocol/src/codec.rs | 1 + src/trx-protocol/src/mapping.rs | 8 + src/trx-protocol/src/types.rs | 2 + src/trx-server/src/aprsfi.rs | 2 +- src/trx-server/src/audio.rs | 139 +++++- src/trx-server/src/main.rs | 16 + src/trx-server/src/rig_task.rs | 11 + 19 files changed, 740 insertions(+), 11 deletions(-) create mode 100644 src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/hf-aprs.js diff --git a/src/decoders/trx-aprs/src/lib.rs b/src/decoders/trx-aprs/src/lib.rs index 03f7003..9c46ddc 100644 --- a/src/decoders/trx-aprs/src/lib.rs +++ b/src/decoders/trx-aprs/src/lib.rs @@ -44,9 +44,6 @@ fn crc16ccitt(bytes: &[u8]) -> u16 { // Correlation demodulator (one instance) // --------------------------------------------------------------------------- -const BAUD: f32 = 1200.0; -const MARK: f32 = 1200.0; -const SPACE: f32 = 2200.0; const TWO_PI: f32 = std::f32::consts::TAU; const PLL_GAIN: f32 = 0.4; @@ -98,9 +95,9 @@ struct RawFrame { } impl Demodulator { - fn new(sample_rate: u32, window_factor: f32) -> Self { + fn new(sample_rate: u32, baud: f32, mark_hz: f32, space_hz: f32, window_factor: f32) -> Self { let sr = sample_rate as f32; - let samples_per_bit = sr / BAUD; + let samples_per_bit = sr / baud; let corr_len = (samples_per_bit * window_factor).round().max(2.0) as usize; let energy_window = (sr * 0.05).round() as usize; @@ -111,8 +108,8 @@ impl Demodulator { energy_window, mark_phase: 0.0, space_phase: 0.0, - mark_phase_inc: TWO_PI * MARK / sr, - space_phase_inc: TWO_PI * SPACE / sr, + mark_phase_inc: TWO_PI * mark_hz / sr, + space_phase_inc: TWO_PI * space_hz / sr, corr_len, mark_i_buf: vec![0.0; corr_len], mark_q_buf: vec![0.0; corr_len], @@ -541,11 +538,22 @@ pub struct AprsDecoder { } impl AprsDecoder { + /// VHF APRS: Bell 202, 1200 baud, mark=1200 Hz, space=2200 Hz. pub fn new(sample_rate: u32) -> Self { Self { demodulators: vec![ - Demodulator::new(sample_rate, 1.0), - Demodulator::new(sample_rate, 0.5), + Demodulator::new(sample_rate, 1200.0, 1200.0, 2200.0, 1.0), + Demodulator::new(sample_rate, 1200.0, 1200.0, 2200.0, 0.5), + ], + } + } + + /// HF APRS: 300 baud, mark=1600 Hz, space=1800 Hz (200 Hz shift). + pub fn new_hf(sample_rate: u32) -> Self { + Self { + demodulators: vec![ + Demodulator::new(sample_rate, 300.0, 1600.0, 1800.0, 1.0), + Demodulator::new(sample_rate, 300.0, 1600.0, 1800.0, 0.5), ], } } diff --git a/src/trx-client/trx-frontend/src/lib.rs b/src/trx-client/trx-frontend/src/lib.rs index d5a8cde..f796dc5 100644 --- a/src/trx-client/trx-frontend/src/lib.rs +++ b/src/trx-client/trx-frontend/src/lib.rs @@ -144,6 +144,8 @@ pub struct FrontendRuntimeContext { pub vdes_history: Arc>>, /// APRS decode history (timestamp, packet) pub aprs_history: Arc>>, + /// HF APRS decode history (timestamp, packet) + pub hf_aprs_history: Arc>>, /// CW decode history (timestamp, event) pub cw_history: Arc>>, /// FT8 decode history (timestamp, message) @@ -207,6 +209,7 @@ impl FrontendRuntimeContext { ais_history: Arc::new(Mutex::new(VecDeque::new())), vdes_history: Arc::new(Mutex::new(VecDeque::new())), aprs_history: Arc::new(Mutex::new(VecDeque::new())), + hf_aprs_history: Arc::new(Mutex::new(VecDeque::new())), cw_history: Arc::new(Mutex::new(VecDeque::new())), ft8_history: Arc::new(Mutex::new(VecDeque::new())), wspr_history: Arc::new(Mutex::new(VecDeque::new())), diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js index 5ddf03a..b421d20 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js @@ -5986,6 +5986,7 @@ function dispatchDecodeMessage(msg) { if (msg.type === "ais" && window.onServerAis) window.onServerAis(msg); if (msg.type === "vdes" && window.onServerVdes) window.onServerVdes(msg); if (msg.type === "aprs" && window.onServerAprs) window.onServerAprs(msg); + if (msg.type === "hf_aprs" && window.onServerHfAprs) window.onServerHfAprs(msg); if (msg.type === "cw" && window.onServerCw) window.onServerCw(msg); if (msg.type === "ft8" && window.onServerFt8) window.onServerFt8(msg); if (msg.type === "wspr" && window.onServerWspr) window.onServerWspr(msg); diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html index 6eb6b16..b979e9c 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html @@ -85,6 +85,7 @@
+
+