Commit Graph

816 Commits

Author SHA1 Message Date
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 b65b85e13c [feat](trx-client): persist 24h decode history across restarts
Add pickledb-backed persistent history store for all decoder types
(AIS, VDES, APRS, CW, FT8, WSPR). History is loaded from
~/.local/cache/trx-rs/history.db at startup and flushed to disk
every 60 seconds. On load, entry timestamps are reconstructed from
stored Unix ms values so 24h pruning continues to work correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 09:43:48 +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 e2c568a98a [fix](trx-frontend-http): async decode history replay to unblock UI
Server emits an SSE sentinel event (history_done) after replaying
stored history. Client buffers all incoming messages until the sentinel
arrives, then drains the buffer in 30-event chunks via setTimeout so
the browser can handle input between batches. Live events after the
sentinel are dispatched immediately as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-07 09:12:13 +01:00
sjg b23f05966f [fix](trx-frontend-http): show CW bar line as it decodes, not after flush
Prepend the in-progress line to the bar render so characters appear
immediately rather than waiting for a newline or 5s gap.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 22:33:02 +01:00
sjg 90d446c8f4 [fix](trx-frontend-http): add cw-bar-overlay to bar overlay CSS selector
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 22:31:22 +01:00
sjg 4272094882 [feat](trx-frontend-http): add CW live bar overlay
Show a live decode bar on the overview strip when in CW/CWR mode,
matching the APRS and AIS bar pattern. Accumulates decoded characters
into lines (split on newline events or >5s gaps), keeps a 15-minute
rolling history, and shows up to 8 recent lines with timestamp and
WPM/tone metadata. Clears on resetCwHistoryView.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 22:28:41 +01:00
sjg 175abe35f9 [fix](trx-frontend-http): guard CW auto UI against concurrent SSE updates
Add cwAutoLocalOverride flag in cw.js to block server-state snapshots
from overriding the checkbox while a user-initiated POST is in-flight.
Expose applyCwAutoUiFromServer for app.js render() to call instead of
applyCwAutoUi, preventing a racing SSE event carrying the old cw_auto
value from immediately undoing the user's toggle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 22:07:05 +01:00
sjg 91562b2a4b [fix](trx-cw): fix window size, dot/dash threshold, and cleanup
- Reduce analysis window from 50ms to 10ms so the decoder can detect
  dits at 25+ WPM (at 25 WPM a dit is 48ms, shorter than the old window)
- Fix dot/dash classification threshold from 2.0× to 1.5× unit_ms;
  ITU Morse dah = 3× dit, so the midpoint boundary is 1.5×
- Replace O(n) on_durations.remove(0) with drain() to trim the window
- Remove pointless emit_text() wrapper; callers now call emit_event()
  directly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 21:30:58 +01:00
sjg 4d22fa964d [feat](trx-frontend-http): show AIS tracks only for selection
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 17:29:12 +01:00
sjg edaef98522 [feat](trx-frontend-http): show APRS tracks only for selection
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 17:11:04 +01:00
sjg 7de847b504 [fix](trx-frontend-http): preserve APRS event timestamps
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 16:19:46 +01:00
sjg faaaad6ab9 [fix](trx-frontend-http): defer decode SSE until plugins load
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 16:17:28 +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 e3378d5f49 [fix](trx-client): start decode collector before audio replay
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 16:01:31 +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 ab27f111d5 [fix](trx-client): reconnect on remote poll timeouts
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 15:33:28 +01:00
sjg 8c16f0da41 [fix](trx-frontend-http): preserve decoder history timestamps
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 11:58:07 +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 e5b9fb7aca [refactor](trx-core): add buffered audio write helper
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-06 11:57:55 +01:00
sjg 3d0cdbd181 [docs](trx-rs): document SoapySDR squelch settings
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:43:32 +01:00
sjg 890abcdc24 [feat](trx-frontend-http): add SQL slider and spectrum screenshot hotkey
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:43:28 +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 3188c9b0ad [feat](trx-protocol): add SDR squelch command mapping
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:43:13 +01:00
sjg 5597a8c206 [feat](trx-core): add SDR squelch command and state fields
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:43:09 +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 3f2892e245 [fix](trx-frontend-http): match waterfall BW resize behavior to waveform
Enable BW edge drag initiation on overview/waterfall canvas and align drag/click suppression behavior with waveform interactions.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 22:10:49 +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 9ed93ec0fa [feat](trx-frontend-http): align waterfall click and restore bookmark marker lines
Add click-to-tune behavior on overview waterfall matching spectrum interactions, restore bookmark marker lines in the overlay using category colors, and keep current-tuned frequency marker visually distinct.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 21:56:19 +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 4e6a800391 [fix](trx-frontend-http): fix waterfall updates and bookmark top anchoring
Ensure overview waterfall incremental updates continue on HiDPI and anchor bookmark chips to the top of the full spectrum view (waterfall + waveform).\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 21:45:49 +01:00
sjg c4f0844137 [fix](trx-frontend-http): optimize WebGL rendering and pin bookmarks to top
Improve WebGL runtime performance by caching/downsampling overview waterfall texture updates and batching marker/dashed-line draws; keep bookmark chips anchored at the top of the waterfall area.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 21:41:49 +01:00
sjg 27b90a62c5 [feat](trx-frontend-http): migrate frontend canvas rendering to WebGL
Replace Canvas2D rendering in spectrum, overview, signal overlay, and CW tone picker with a shared WebGL renderer and wire the new asset into frontend HTTP routes.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 21:37:50 +01:00
sjg 633ad92dd6 [fix](trx-frontend-http): decouple signal view from spectrum and fix canvas scaling 2026-03-05 21:14:35 +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 8e8d21b527 [feat](trx-frontend): add longer peak hold durations 2026-03-05 19:34:17 +01:00
sjg 1370234b35 [style](trx-frontend): make signal split slider narrower 2026-03-05 19:33:29 +01:00
sjg 49f44e84a0 [fix](trx): ignore FTx farewell pseudo-locators and narrow split slider 2026-03-05 19:24:54 +01:00
sjg 05e72e21e8 [feat](trx-frontend): reset signal split on slider double-click 2026-03-05 18:34:59 +01:00
sjg 2e6b9f87fb [fix](trx-frontend): compact split slider and center side controls 2026-03-05 18:28:42 +01:00
sjg 083d009aa5 [feat](trx-frontend): add signal split slider and align spectrum side controls
Add a right-side slider to control the waterfall/waveform split and\npersist the selected ratio locally.\n\nRework spectrum height layout so manual resize adjusts total plot height\nwhile split controls the overview/spectrum ratio.\n\nKeep center-frequency arrows and side bookmark stacks vertically centered\nwithin the full spectrum view container.\n\nCo-authored-by: Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 18:17:34 +01:00
sjg 4c69e2bcde [fix](trx-frontend): improve spectrum resize interaction
Make the spectrum resize grip easier to use and style it closer to\nexisting controls.\n\nKeep auto-max behavior by default while allowing manual drag to\nresize beyond viewport fill, enforcing only the minimum height.\n\nCo-authored-by: Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 18:08:16 +01:00
sjg a905fa9678 [fix](trx-frontend): maximize spectrum viewport and add resize grip
Make spectrum plot use maximum available viewport height by default.
Add draggable vertical resize grip with a reasonable minimum height
and double-click reset back to auto-max.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-05 17:45:50 +01:00
sjg bfff095cf0 [fix](trx-core): auto-enable CW decode on CW/CWR mode
When mode is set to CW/CWR, force cw_decode_enabled=true in state
application to avoid stale disabled decode state.
Also route initial mode setup through apply_mode.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-04 23:17:44 +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