Commit Graph

361 Commits

Author SHA1 Message Date
sjg 250300395f [fix](trx-server): batch history replay into single TCP write
Replace per-message write + flush-every-64 with a single in-memory blob
that is sent via one write_all + one flush. Add estimated_total_count()
to DecoderHistories for pre-allocation. Eliminates N/64 partial flushes
and repeated small writes that dominated replay latency for large APRS
histories.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-08 18:39:50 +01:00
sjg b4fb42dba4 [fix](trx-server): clear CW history on ResetCwDecoder
ResetCwDecoder already bumped cw_decode_reset_seq but omitted the
history flush that APRS, FT8, and WSPR all perform.  Wire
clear_cw_history() into the handler to match the pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 10:17:39 +01:00
sjg cbf3301664 [fix](trx-server): remove unused clear_cw_history method
No reset event for CW is wired in rig_task.rs, so the method was
dead code and triggered a compiler warning.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 10:16:36 +01:00
sjg 53199642ea [fix](trx-server): fix VDES channel routing and IQ sample rate
Subscribe to the first sdr.channels[] entry configured as VDES or
MARINE instead of always using channel 0.  The ChannelDsp IQ tap only
emits samples when its own mode is VDES/MARINE, so the two must agree.

Fix vdes_sr to mirror channel.rs pipeline_rates(): use
audio_sample_rate.max(96_000) as the target rather than the hardcoded
96_000.  The two diverge when audio_sample_rate > 96_000, causing the
VdesDecoder to use the wrong symbol-to-sample ratio.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 10:14:09 +01:00
sjg 2f1b0609fb [feat](trx-server): persist 24h decode history across restarts
Move persistent history from trx-client to trx-server where decode
events originate. History for AIS, VDES, APRS, CW, FT8, and WSPR is
loaded from ~/.local/cache/trx-rs/history.db at startup and flushed
to disk every 60 seconds. CW events are now also stored in
DecoderHistories and replayed to connecting clients, consistent with
all other decoder types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 09:50:42 +01:00
sjg 1001786a08 [fix](trx-backend-soapysdr): ensure IQ stream recovery after overflow
Two problems prevented reliable recovery after a persistent overflow:

1. Restart storm: once read_error_streak >= 3, every subsequent read
   failure triggered a deactivate/activate cycle, potentially preventing
   the hardware from stabilising. Fix: after a successful restart, reset
   read_error_streak to 1 so the stream gets 2 more failures before the
   next restart attempt.

2. Stuck-deactivated stream: if activate() failed after overflow, the
   stream was left deactivated. Subsequent reads returned non-overflow
   errors which handle_read_error ignored (Ok(false)), so the stream was
   never reactivated. Fix: add a high-streak fallback (>= 10 consecutive
   errors of any kind) that also attempts a full deactivate/activate
   restart, covering the stuck-deactivated case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 09:31:17 +01:00
sjg bfc510e1eb [fix](trx-client,trx-server): fix spectrum death and stuck shutdown after IQ overflow
Two bugs triggered by a SoapySDR IQ overflow:

1. Spectrum dies permanently (trx-client): when GetSpectrum times out
   (300ms SPECTRUM_IO_TIMEOUT), the error was silently swallowed and
   the spectrum buffer cleared. The in-flight response remained in the
   TCP receive buffer, desynchronising all subsequent reads so every
   poll kept failing. Fix: propagate the error so handle_connection
   returns and the outer loop reconnects, restoring TCP sync.

2. CTRL+C hangs trx-server: after IQ overflow, the sdr-iq-read thread
   can get stuck in a blocking SoapySDR/USB call (deactivate/activate
   with no timeout). Tokio received SIGINT and aborted async tasks, but
   the process could not exit while the native thread was blocked in
   uninterruptible I/O. Fix: call std::process::exit(0) after the
   graceful shutdown sequence so the OS forcibly terminates all threads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 09:25:08 +01:00
sjg 69b2aee753 [fix](trx-server): preserve decoder history timestamps
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 16:08:34 +01:00
sjg f9c0fa6981 [fix](trx-server): add rig task timeouts to avoid stalls
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 15:45:10 +01:00
sjg 18d3a00c07 [fix](trx-server): optimize replay and stamp APRS history time
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 11:58:02 +01:00
sjg 8bd779a239 [feat](trx-server): wire SDR squelch through server config and rig task
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:43:23 +01:00
sjg 3eb5a615b9 [feat](trx-backend-soapysdr): extend squelch and boost high denoise
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:43:19 +01:00
sjg 3d9003feb2 [feat](trx-server): add per-rig enable switch in multi-rig config
Add [[rigs]].enable (default true) and skip disabled rigs during\nresolution/uniqueness checks.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:15:45 +01:00
sjg 5dcc117e61 [fix](trx-backend-soapysdr): disable hidden AIS DSP outside AIS modes
Add per-channel processing gating and disable hidden AIS channel DSP unless mode is AIS or MARINE, reducing continuous IQ read-loop CPU load in normal operation.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:01:21 +01:00
sjg 8be3b273bc [fix](trx-backend-soapysdr): reduce sdr-iq-read CPU spin on idle reads
Skip IQ fanout buffer cloning when no subscribers exist and apply backoff on repeated zero-length reads to avoid hot-loop CPU spikes.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 21:50:17 +01:00
sjg a041dd4505 [fix](trx-backend-ft817): bound lock/unlock reads to prevent set_mode timeout 2026-03-05 20:44:32 +01:00
sjg ccef359034 [fix](trx): speed up web load and harden FT817/Soapy recovery 2026-03-05 20:36:46 +01:00
sjg bc0d9a6273 [fix](ftx): treat second callsign as source in directed traffic 2026-03-05 20:23:22 +01:00
sjg bf74044c05 [fix](trx): normalize FT8 history freq and add map locator links 2026-03-05 19:48:20 +01:00
sjg 49f44e84a0 [fix](trx): ignore FTx farewell pseudo-locators and narrow split slider 2026-03-05 19:24:54 +01:00
sjg 14d58ce989 [fix](trx-server): hard-gate CW decode to CW/CWR modes
Enforce CW decode processing only when mode is CW/CWR and decoder
is enabled, even within the receive loop, and remove CW path RMS
zero-gating to preserve weak tone decoding.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-04 23:14:23 +01:00
sjg f3f0b1dfd3 [fix](trx-server): accept CW tone range up to 10 kHz
Expand server-side CW tone command clamping to 100-10000 Hz to match
frontend controls and picker behavior.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-04 23:05:03 +01:00
sjg 878b50cad7 [fix](trx-server): gate near-silent audio before decode
Apply an RMS gate to near-silent decoder input frames and zero them
before APRS/CW/FT8/WSPR processing to avoid false decodes from
unsquelched/no-signal noise.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-04 22:58:02 +01:00
sjg e3a5fee666 [style](trx-backend-soapysdr): format WFM code
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 19:41:30 +01:00
sjg 087ebb33bb [style](trx-backend-ft817): format mode setup
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 19:41:20 +01:00
sjg 8042624c39 [style](trx-server): format audio and startup code
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 19:41:17 +01:00
sjg 1825a0a003 [fix](trx-server): honor CW decode enable flag
Gate the CW decoder task on cw_decode_enabled in both startup and state changes.
This restores the UI toggle and prevents decode activity when CW decode is off.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 02:33:33 +01:00
sjg acecaff810 [fix](trx-backend-ft817): reject unsupported modes
Make FT-817 mode setting fail for unsupported modes instead of silently mapping SDR-only modes onto FM.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 02:12:49 +01:00
sjg 564f25fc6d [fix](trx-backend-ft817): hide unsupported decode modes
Remove SDR-only decoder modes from the FT-817 supported mode list so they are not shown in that rig's mode picker.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 02:10:52 +01:00
sjg 7188d38610 [fix](trx-backend-soapysdr): boost AM audio further
Raise the AM audio AGC target and headroom again so the restored envelope demod path plays at a stronger level.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 02:02:15 +01:00
sjg 605531184b [fix](trx-backend-soapysdr): raise AM audio gain
Retune the AM audio AGC target, timing, and headroom so the restored envelope demod path plays back at a stronger level.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 01:59:50 +01:00
sjg c1ed936c2e [fix](trx-backend-soapysdr): restore simple AM demodulation
Revert the recent AM coherent detector experiment and restore the original envelope detector path.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 01:58:11 +01:00
sjg e2e4d34f30 [fix](trx-backend-soapysdr): reduce AM demod distortion
Remove half-wave clipping from the AM coherent detector output and slow the carrier-reference tracking to reduce audible distortion.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 01:55:30 +01:00
sjg 298b7247f8 [feat](trx-backend-soapysdr): improve AM coherent demodulation
Replace the raw AM envelope detector with a limiter-derived coherent detector and update backend tests for the current channel DSP constructor.

Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 01:48:22 +01:00
sjg 696ba09049 [fix](trx-rs): improve marine decode paths
Finish the pending MARINE frontend and decoder activation wiring, and lower the VDES detector power floors so weak signals are eligible for burst detection in the same power domain used by the IQ path.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 01:16:14 +01:00
sjg 10f5a147dc [fix](trx-vdes): preserve higher SDR iq rate
Keep the SoapySDR VDES and MARINE IQ path at a much higher channel sample rate instead of collapsing toward the normal audio rate, so the decoder receives usable complex baseband for the 76.8 ksps VDES signal.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 01:13:06 +01:00
sjg 9fe293e056 [feat](trx-rs): expose marine mode and ft8 live bar
Add an FT8 live overlay bar, align APRS top controls with the other decoder tabs, advertise MARINE in the SoapySDR mode list, and make the VDES decoder emit raw unsynced diagnostic frames instead of dropping weak bursts outright.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 01:01:00 +01:00
sjg c8d81ed353 [feat](trx-rs): add marine mode scaffolding and VDES fallback
Keep weak VDES bursts visible by emitting unsynced diagnostic frames instead of dropping them, remove receiver badges from FT8 and WSPR history rows, and carry the current MARINE composite-mode scaffolding through the shared mode enums and backend mappings.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 00:54:31 +01:00
sjg 5e84fe2a82 [feat](trx-rs): add VDES hard-decision FEC stage
Improve the VDES decoder with sync/rotation metadata and a first hard-decision rate-1/2 Viterbi stage after deinterleaving, then surface the extra lock state in the VDES frontend. Also fix the strict clippy findings in AIS, frontend bookmarks, and the server audio stack signature.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 00:39:41 +01:00
sjg 6e558303a7 [feat](trx-rs): split VDES frontend and decoder path
Add a dedicated VDES plugin tab and live bar, stop reusing the AIS vessel UI, and serve a separate VDES frontend script. Rework the SDR backend so VDES receives a single 100 kHz IQ tap, then replace the fake AIS-clone decoder path with an early M.2092-1 oriented complex-baseband scaffold using burst detection, coarse pi/4-QPSK slicing, and TER-MCS-1.100 frame heuristics.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-03-03 00:32:32 +01:00
sjg 92423f1e02 [feat](trx-rs): add VDES decoder mode support
Add a new trx-vdes decoder path alongside AIS, wire VDES through the server/frontend decode pipeline, and fix the web map so AIS vessel symbols load correctly and the TRX receiver marker appears when location data arrives.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 00:05:16 +01:00
sjg c778d4b9a8 [feat](trx-rs): add AIS decoder mode and frontend
Add dual-channel AIS decode support across the SoapySDR backend, server decode pipeline, and frontend plugins, including the new AIS tab, live bar, and map filtering.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-02 22:42:12 +01:00
sjg 832fac1d64 [fix](trx-rs): refine wfm denoise and favicon handling
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:26:04 +01:00
sjg 616ff1b79e [feat](trx-backend-soapysdr): add wfm denoise levels
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:22:02 +01:00
sjg 31238098ca [fix](trx-backend-soapysdr): raise wfm output gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:07:29 +01:00
sjg 623aad10d1 [fix](trx-backend-soapysdr): preserve more stereo under denoise
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:06:15 +01:00
sjg fb52558652 [feat](trx-backend-soapysdr): adapt wfm stereo separation gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:01:08 +01:00
sjg d569db6643 [fix](trx-backend-soapysdr): fine tune wfm phase trim
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:53:12 +01:00
sjg 2b1764b90e [fix](trx-backend-soapysdr): restore neutral wfm stereo trim
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:50:54 +01:00
sjg a1a8aaeb9d [fix](trx-backend-soapysdr): rebalance wfm output gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:48:51 +01:00