Commit Graph

1020 Commits

Author SHA1 Message Date
sjg bc153b84ee [debug](trx-server): trace rig task progress
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 13:32:38 +01:00
sjg 12f1d81af8 [debug](trx-server): trace backend control flow
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 13:19:21 +01:00
sjg 1be02ec8ad [debug](trx-server): trace listener and rig task activity
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 11:57:34 +01:00
sjg e5bf7346c8 [debug](trx-backend-soapysdr): trace SDR retune application
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 11:31:27 +01:00
sjg fc954fd27c [fix](trx-frontend-http): stop headless background spectrum polling
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 11:28:41 +01:00
sjg 8be8e798c6 [fix](trx-frontend-http): drop orphaned vchans on disconnect
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 08:14:34 +01:00
sjg 8043a5001c [fix](trx-server): move remaining decoders off async workers
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 08:09:16 +01:00
sjg 73173d29ff [fix](trx-backend-soapysdr): keep vchans across scheduler retunes
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 07:38:56 +01:00
sjg c014f5cdc2 [fix](trx-frontend-http): refresh map sources on live APRS
Rebuild the visible-source chips when live APRS, AIS, or VDES markers are first added so the map filter list updates without a page refresh.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 07:24:09 +01:00
sjg 66987a4070 [fix](trx-client): preserve vchan commands under scheduler churn
Use an unbounded virtual-channel command queue so background decode and scheduler transitions do not silently drop subscribe or remove commands.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 07:10:40 +01:00
sjg c178c56f2e [fix](trx-server): clean up hidden vchans on disconnect
Remove hidden background decode channels when the owning audio client disconnects to avoid stale DSP and decoder buildup.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 07:01:09 +01:00
sjg 69fd24577c [fix](trx-server): move heavy decoders off async workers
Run FT8 and WSPR decode steps in blocking sections so the server listener stays responsive under decode load.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 06:56:54 +01:00
sjg 0179c13000 [fix](trx-server): avoid spectrum hang on overflow
Avoid SoapySDR overflow restart wedge and coalesce concurrent GetSpectrum requests.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 06:45:10 +01:00
sjg 4cac91e36a [fix](trx-frontend-http): show scheduler interleave timing
Replace the misleading scheduler task countdown with the actual time-span interleave switch timing in the main controls row.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 01:08:31 +01:00
sjg be4844c710 [fix](trx-client): speed up remote spectrum polling
Raise remote spectrum polling from 100 ms to 50 ms while keeping the relaxed timeout and subscriber gating.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 01:03:38 +01:00
sjg 4f4cd4647d [fix](trx-client): reduce remote spectrum timeout churn
Relax the remote spectrum timeout, poll at the backend update cadence, and stop polling when no spectrum subscribers are connected.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 00:59:59 +01:00
sjg b679ff0282 [feat](trx-frontend-http): refine map and scheduler controls
Add separate map path toggles, move scheduler handoff into the channels row, and show a live countdown to the next scheduler cycle.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 00:52:00 +01:00
sjg 4cca188d9f [feat](trx-frontend-http): improve scheduler and decode map controls
Remove settings rig pickers, restore the last scheduler cycle on release, fix FT8 locator role parsing, and add toggleable decode contact paths on the map.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 00:45:12 +01:00
sjg f7cbc0cb02 [fix](trx-frontend-http): move scheduler handoff out of channels row
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 00:28:25 +01:00
sjg 5c28ed1269 [feat](trx-frontend-http): add scheduler control handoff
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-13 00:22:18 +01:00
sjg f8fd4572c7 [feat](trx-frontend-http): paginate bookmarks tab
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 23:57:02 +01:00
sjg 963d527dfe [feat](trx-frontend-http): add direct tab routes
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 23:54:25 +01:00
sjg bdd3d29374 [fix](trx-frontend-http): show aprs and ais bookmarks in background decode
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 23:03:57 +01:00
sjg 95fccd3da6 [feat](trx-frontend-http): expand background decode selection
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:57:25 +01:00
sjg 34d0ec8ca8 [feat](trx-server): add aprs and ais background decoders
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:57:18 +01:00
sjg a91a1868d8 [fix](trx-frontend-http): refresh background decode settings UI
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:48:24 +01:00
sjg 2462f1dd47 [feat](trx-frontend-http): add background decode settings
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:42:50 +01:00
sjg 21a534bdb6 [feat](trx-client): support background decode subscriptions
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:42:43 +01:00
sjg 763d4c00b0 [feat](trx-server): support hidden background decode channels
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:42:37 +01:00
sjg 6c9ff33d68 [feat](trx-frontend): add background decode audio commands
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:42:33 +01:00
sjg b83558b1a2 [feat](trx-core): add hidden background channel API
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:42:21 +01:00
sjg 2d014ac45b [docs](trx-rs): refresh top-level docs and config example
Rewrite the README, remove AI-generated planning docs, and regenerate the combined example config.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 22:09:34 +01:00
sjg fc24dc37ed [feat](trx-rs): add settings tab and virtual audio plan
Move Scheduler under a new Settings tab in the HTTP frontend.
Add the virtual-channel audio implementation plan document.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 21:55:54 +01:00
sjg 6d18f5e1d4 [fix](trx-frontend): enable BW drag handles on vchans
Use the active channel frequency for spectrum bandwidth edge hit-testing.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 20:49:43 +01:00
sjg e8326b4822 [fix](trx-frontend): align spectrum RDS overlays vertically
Keep virtual-channel RDS overlays on a shared vertical axis.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 20:44:21 +01:00
sjg add0a93424 [feat](trx-frontend-http): frequency-ordered z-index and hover-to-front for RDS overlay layers
Each RDS PS overlay item (position: absolute within the shared #rds-ps-overlay
container) now receives a z-index derived from its channel frequency: items are
sorted by freq_hz ascending so higher-frequency layers sit on top of
lower-frequency ones by default.

Hovering any layer temporarily assigns it the maximum z-index (entry count + 10)
to bring it to the front; mouseleave restores the frequency-derived default
stored in data-default-z.

Also reverts the incorrectly applied vchan picker layer changes from the
previous commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 20:12:23 +01:00
sjg 1fe7dc88c6 [feat](trx-frontend-http): add frequency layers display for virtual channels
Render virtual channels as absolutely-positioned layer strips inside a
shared relative container (#vchan-freq-layers). Layers are sorted by
frequency ascending so higher-frequency channels receive a higher z-index
and sit on top by default. Hovering any layer temporarily assigns it the
maximum z-index to bring it to the front; leaving restores the original
stacking order. Each layer is offset by 11 px vertically so all channels
remain visible as a staggered card stack.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-12 20:04:27 +01:00
sjg 93ff35a824 Add per-channel RDS overlays for WFM vchans 2026-03-11 22:39:02 +01:00
sjg 21972c27d2 [test](trx-client): fix fixtures for updated rig snapshot
Update test fixtures to include hf_aprs_decode_enabled and use the current spectrum watch sender type in remote client tests.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 21:41:39 +01:00
sjg daa0631b35 [feat](trx-client): support virtual channel bandwidth control
Add client-side command plumbing, HTTP endpoint handling, and frontend interception so bandwidth changes are applied per active virtual channel and survive reconnects.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 21:41:32 +01:00
sjg 717228a635 [feat](trx-server): handle virtual channel bandwidth updates
Handle AUDIO_MSG_VCHAN_BW in the audio server path and apply per-channel filter bandwidth through the SoapySDR virtual channel manager.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 21:41:26 +01:00
sjg 502e97049a [feat](trx-core): add virtual channel bandwidth control
Add virtual-channel bandwidth control to the shared core API and audio protocol constants for client/server coordination.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 21:41:17 +01:00
sjg 894739bbab [chore](trx-rs): resolve all compiler and clippy warnings
- trx-server/rig_handle: remove dead vchan_manager field (was set but
  never read after the virtual-channel refactor)
- trx-server/listener: remove now-missing vchan_manager initializer
- trx-server/main: remove vchan_manager_for_handle intermediates that
  only fed the dropped field
- trx-server/audio: suppress too_many_arguments on run_audio_listener
- trx-frontend-http/server: suppress too_many_arguments on build_server
- trx-core/vchan: update module doc comment to not reference the
  removed RigHandle::vchan_manager field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 21:01:38 +01:00
sjg 19ab3b3931 [feat](trx-rs): remove MARINE mode (superseded by virtual channels)
MARINE was a composite mode that ran both AIS and VDES decoders
simultaneously. It is now fully replaced by allocating two virtual
channels — one tuned to the AIS frequencies and one to VDES — each
decoded independently.

- trx-core/state: remove RigMode::MARINE variant
- trx-protocol/codec: remove MARINE parse/serialize
- trx-backend-ft817: remove MARINE from unsupported-mode guard
- trx-backend-ft450d: remove MARINE from FM CAT code mapping
- trx-backend-soapysdr: remove MARINE from bandwidth table, supported
  modes list, AIS channel activity check, parse_rig_mode, vchan_impl
  bandwidth table, demod selection, dsp/channel bandwidth / sample-rate
  / IQ-tap guards
- trx-server/audio: remove MARINE from AIS and VDES decoder activation
- trx-server/rig_task: remove MARINE from audio-streaming mode list
- trx-server/main: remove MARINE from bandwidth table, mode parser,
  VDES channel subscription match
- app.js: remove isMarineMode(), MARINE entry in MODE_BW_SPECS, MARINE
  bandwidth specs block in visibleBandwidthSpecs(), MARINE from
  decoder status mode lists, MARINE BW-edge drag guard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 20:58:20 +01:00
sjg 60267d450b [feat](trx-rs): persistent multi-channel virtual channels with OOB eviction
Allow users to allocate multiple virtual channels independently of
browser tab count. Channels survive SDR center-frequency retuning as
long as they stay within the capture bandwidth; channels that fall
outside the SDR span are automatically destroyed.

Changes:
- trx-core: add AUDIO_MSG_VCHAN_DESTROYED (0x12) wire constant;
  add default subscribe_destroyed() to VirtualChannelManager trait
- trx-backend-soapysdr: update_center_hz() detects OOB channels,
  removes them, fires destroyed_tx broadcast; add destroyed_sender()
  and subscribe_destroyed() override
- trx-server/audio: recv_destroyed() helper avoids select! busy-loop
  for non-SDR backends; send AUDIO_MSG_VCHAN_DESTROYED to client when
  a channel is evicted server-side
- trx-client/audio_client: persist active_subs across TCP reconnects,
  re-subscribe on reconnect; handle AUDIO_MSG_VCHAN_DESTROYED by
  pruning vchan_audio map and forwarding UUID via vchan_destroyed_tx
- trx-frontend/lib: add vchan_destroyed broadcast field to
  FrontendRuntimeContext
- trx-client/main: wire vchan_destroyed_tx into audio client and
  frontend runtime context
- trx-frontend-http/vchan: remove per-session one-channel limit in
  allocate(); replace auto-evict in release_session_on_rig() with
  subscriber-count-only update; add remove_by_uuid() for server-
  triggered OOB destruction (skips redundant VChanAudioCmd::Remove)
- trx-frontend-http/server: spawn background task that forwards
  vchan_destroyed broadcast to ClientChannelManager.remove_by_uuid()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 20:50:49 +01:00
sjg 4e93dcc82a [fix](trx-frontend-http): fix virtual channel audio streaming
Three bugs prevented vchan audio from working reliably:

1. vchan.js: `vchanReconnectAudio` returned before updating
   `_audioChannelOverride` when audio was inactive. Switching to
   a virtual channel with audio off then starting audio manually
   would connect to the primary channel instead. Move the override
   update before the rxActive guard so it always reflects the
   active channel.

2. audio.rs: `audio_ws` returned 404 immediately if the channel
   was not yet in `vchan_audio`. The entry is populated when
   `AUDIO_MSG_VCHAN_ALLOCATED` arrives from the audio TCP client,
   which can lag the HTTP allocation by up to ~100 ms. Replace the
   instant 404 with a 2-second polling loop (50 ms intervals) so
   the WebSocket upgrade waits for the channel to be ready.

3. vchan.rs: `release_session_on_rig` evicted zero-subscriber
   channels silently — no `VChanAudioCmd::Remove` was sent.
   Collect evicted channel IDs before retain() and send Remove
   commands so the server-side DSP pipeline and Opus encoder are
   torn down properly on session disconnect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 20:24:48 +01:00
sjg 6131d7a1d6 [feat](trx-rs): per-virtual-channel audio streaming
Add end-to-end audio routing for virtual DSP channels:

Server (trx-server):
- New wire protocol: AUDIO_MSG_RX_FRAME_CH (0x0b), VCHAN_ALLOCATED (0x0c),
  VCHAN_SUB (0x0d), VCHAN_UNSUB (0x0e), VCHAN_FREQ (0x0f), VCHAN_MODE (0x10),
  VCHAN_REMOVE (0x11) frame types in trx-core audio.rs
- Add frame helpers: write_vchan_uuid_msg, write_vchan_audio_frame,
  parse_vchan_audio_frame, parse_vchan_uuid_msg
- Add ensure_channel_pcm() to VirtualChannelManager trait; implement in
  SdrVirtualChannelManager with create-or-subscribe semantics using client UUID
- Extend audio.rs handle_audio_client: VChanCmd dispatcher, per-channel Opus
  encoder tasks, VCHAN_SUB/UNSUB/FREQ/MODE/REMOVE reader loop handlers
- Thread vchan_manager through run_audio_listener / spawn_rig_audio_stack

Client (trx-client):
- Add VChanAudioCmd enum to trx-frontend; add vchan_audio and vchan_audio_cmd
  fields to FrontendRuntimeContext
- Extend audio_client: demux AUDIO_MSG_RX_FRAME_CH to per-channel broadcasters,
  handle VCHAN_ALLOCATED; forward VChanAudioCmd over TCP write loop
- Wire vchan_cmd_tx/rx channel in main.rs; pass vchan_audio map to audio_client
- ClientChannelManager.set_audio_cmd() / send_audio_cmd(): dispatch
  Subscribe/Remove/SetFreq/SetMode on allocate/delete/freq/mode operations
- Wire audio_cmd sender in server.rs serve() after creating vchan_mgr

HTTP frontend:
- /audio?channel_id=<uuid>: route WebSocket to per-channel Opus broadcaster
- vchan.js: vchanReconnectAudio() stops/restarts RX audio on channel switch;
  _audioChannelOverride in app.js selects primary vs virtual WS endpoint
- app.js: _audioChannelOverride variable; startRxAudio appends channel param

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 08:06:18 +01:00
sjg 28036ab589 [feat](trx-frontend-http): sync mode picker to active virtual channel
- Add vchanSyncModeDisplay() in vchan.js; called from vchanSyncAccentUI()
  and vchanSubscribe() so the mode picker always reflects the active
  virtual channel's mode on switch and on channel-list refresh
- Guard the rig-state mode picker update in render() so it is skipped
  when vchanIsOnVirtual() is true, preventing primary-channel mode from
  overwriting the virtual channel selection

Note: per-channel audio and decoder output require server-side protocol
changes (separate Opus streams per virtual channel) and are not yet
implemented.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 07:37:52 +01:00
sjg 3d284abab6 [fix](trx-frontend-http): center BW overlay on active virtual channel freq
When subscribed to a non-primary virtual channel the bandwidth overlay
was still anchored to lastFreqHz (channel 0).  Resolve the effective
center from the active vchan when vchanIsOnVirtual() is true.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 07:30:24 +01:00
sjg 4bb7248257 [feat](trx-frontend-http): draw virtual channel markers on spectrum + OOB error
- Draw sky-blue dashed/solid lines on spectrum overlay for each vchan
- Active virtual channel gets a solid line; inactive ones are dashed
- Validate freq against SDR capture window in vchanSetChannelFreq and
  show a showHint error when tuning out of bandwidth

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-11 07:27:51 +01:00