Commit Graph

1405 Commits

Author SHA1 Message Date
sjg db5fa26bd9 [fix](trx-frontend-http): start browser audio on user gesture
Create and resume the RX AudioContext from the audio button click so Chromium does not leave playback suspended until a later interaction.

Reuse that context when stream metadata arrives instead of recreating it from the WebSocket message path.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 22:52:28 +01:00
sjg 32e1618384 [fix](trx-frontend-http): drop rig_id http aliases
Remove the remaining legacy rig_id aliases across the HTTP frontend and use remote consistently for scheduler and audio requests.

Disable browser caching for the HTML, CSS, and JS assets so clients pick up the parameter rename immediately instead of running stale frontend code.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 22:49:01 +01:00
sjg 7d76606927 [fix](trx-frontend-http): accept remote on audio endpoint
Parse the renamed `remote` query parameter on `/audio` while keeping
`rig_id` as a compatibility alias, and use per-rig stream info for
rig-scoped audio subscriptions.

Add tests covering both query names.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 22:31:04 +01:00
sjg b8ce05d41e [fix](trx-client): isolate selected state per server group
Keep global state and spectrum updates scoped to the server group that
owns the selected short name, so other servers cannot overwrite the UI
or clear the active spectrum stream.

Add regression tests for cross-server selection and spectrum ownership.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 22:23:22 +01:00
sjg fad63be247 [fix](trx-client): keep multi-server rigs in audio cache
Merge per-server GetRigs updates into the shared remote rig cache
instead of replacing it, so audio tasks from other servers are not
torn down on each poll cycle.

Add a regression test covering the multi-server cache update path.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 22:18:50 +01:00
sjg e09f14d2d3 [feat](trx-client): support audio URL overrides
Use full audio endpoint URLs for trx-server audio connections while
preserving server-advertised ports and legacy port-based fallback for
backward compatibility.

Add `server_url` and per-remote `rig_urls` config entries, plus
validation and tests for audio URL parsing and address resolution.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 22:04:14 +01:00
sjg d8444f35f6 [refactor](trx-frontend-http): rename rig_id API fields to remote
Rename HTTP query params, JSON fields, and scheduler payloads to
use remote names consistently while still accepting legacy `rig_id`
inputs through serde aliases.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 21:54:45 +01:00
sjg 2db13da706 [fix](trx-client): use default remote name in config
Use the remote short name for the HTTP frontend default selection and
keep `default_rig_id` as a serde alias for backward compatibility.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 21:54:37 +01:00
sjg 9cd172ce64 [feat](trx-client): support multiple trx-servers from a single client
Introduce [[remotes]] config array where each entry maps a user-chosen
short name to a (server URL, rig_id) pair. Short names replace raw
rig_ids as the universal key throughout frontends, audio routing, and
state management, allowing rig_ids to safely collide across servers.

Entries sharing the same server URL and token share a single TCP
connection. A request routing dispatcher forwards frontend commands to
the correct per-server channel based on the short name.

Legacy [remote] config and CLI --url are preserved via automatic
fallback to a single-entry remotes list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-23 21:00:31 +01:00
sjg 1e438acaf7 [feat](trx-frontend-http): show rig name and location in page title
Include active rig display name and nearest city in the browser tab
title: "freq - rig name - city, country - trx-rs v<version>".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 14:20:09 +01:00
sjg 6c8d294f6a [chore](docs): upgrade docs
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 14:15:51 +01:00
sjg eb97d8379d [chore](trx-rs): remove MANUAL.md - moved to docs/ (wiki submodule)
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 14:15:25 +01:00
sjg 182240faa8 [docs](trx-rs): add threshold selection guide to MANUAL.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 14:14:04 +01:00
sjg a5a654d508 [docs](trx-rs): add noise blanker section to MANUAL.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 14:11:26 +01:00
sjg 1f6e3bb142 [feat](trx-frontend-http): add noise blanker controls to SDR settings UI
Add checkbox to enable/disable NB and number input for threshold (1-100).
Controls are hidden by default and shown when the server reports NB support
via SSE filter state updates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 14:05:14 +01:00
sjg 189d27bac8 [feat](trx-rs): add configurable noise blanker for SoapySDR backend
IQ-domain impulse noise blanker using exponential-smoothing RMS tracker. Samples exceeding threshold × running RMS are replaced with the last clean sample. Configurable via [sdr.noise_blanker] in TOML config and runtime via POST /set_sdr_noise_blanker API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 13:54:17 +01:00
sjg 01a6b331f6 [fix](trx-frontend-http): invalidate bookmark colors on style change too
The bookmark color palette is derived from CSS variables (--accent-yellow,
--accent-green, etc.) which change on both dark/light theme toggle AND
palette style change (arctic, lime, etc.). The previous fix only covered
setTheme; extract invalidateBookmarkColors() and call it from setStyle
as well so bookmark chips recolour on any visual change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 12:12:09 +01:00
sjg f9f06a1db1 [fix](trx-frontend-http): force style recalc before reading bookmark theme colors
getComputedStyle may return stale CSS variable values if the browser
has not flushed the style recalculation after changing data-theme. Force
a recalc by reading a property value first. Also clear cached bookmark
DOM keys so the next draw pass rebuilds chips from scratch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 09:42:41 +01:00
sjg 2d1f635019 [fix](trx-frontend-http): directly re-apply bookmark chip colors on theme change
Bumping bmRevision and scheduling a spectrum draw was not enough because
the spectrum draw path only runs when spectrum data is present. Instead,
directly update --bm-cat-bg/--bm-cat-fg on all existing bookmark chips
from the new theme palette so colors update immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 09:29:50 +01:00
sjg 4d09636793 [fix](trx-frontend-http): guard scheduleSpectrumDraw from TDZ during init
scheduleSpectrumDraw references a let-bound variable that hasn't been
initialized yet when setTheme runs at startup. Wrap in try/catch so the
early call is silently skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 09:25:38 +01:00
sjg 84259a01f4 [fix](trx-frontend-http): redraw bookmark colors on theme change
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 09:20:32 +01:00
sjg 4ad5bf863d [fix](trx-client): update per-rig state channel on command response
send_command only updated the global state_tx watch channel, but SSE
sessions subscribe to per-rig rig_states channels. Per-rig channels were
only updated during the poll cycle (default 750ms). Now send_command also
pushes state to the per-rig channel immediately, eliminating up to 750ms
of latency for confirmed frequency/mode/state changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 09:09:59 +01:00
sjg 3ad5f7a3b7 [fix](trx-frontend-http): make vchan wrapper fire-and-forget on freq change
The vchan setRigFrequency wrapper was awaiting vchanTakeSchedulerControl()
(HTTP PUT to /scheduler-control) and vchanSetChannelFreq() (HTTP PUT to
channel freq endpoint) before calling the original setRigFrequency. This
added a full HTTP round-trip of latency to every frequency change. Make
both fire-and-forget: optimistic local update happens first, network calls
run in background.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 08:57:50 +01:00
sjg faf86faff9 [fix](trx-frontend-http): make setRigFrequency fire-and-forget
The HTTP round-trip for set_freq blocks on the server processing the
command (mpsc → TCP → rig hardware → response). With optimistic local
updates, CSS overlay, and SSE snap-back guard already in place, there is
no reason to await the network call. All callers (jog, freq input, spectrum
click, RDS AF tune) now return immediately after the optimistic update.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 08:31:01 +01:00
sjg 7f9ecad34c [fix](trx-frontend-http): prevent SSE from snapping freq back during optimistic update
When the user changes frequency, applyLocalTunedFrequency sets lastFreqHz
optimistically. But the SSE state stream could push back the old server
frequency before set_freq completes, causing the marker to snap back then
forward. Add a sequence-guarded _freqOptimisticHz that suppresses stale
SSE frequency updates while a set_freq is in flight.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 08:20:58 +01:00
sjg 54df7cf0f9 [feat](trx-frontend-http): GPU-composited CSS overlay for instant freq/BW updates
Replace synchronous drawSignalOverlay() calls in freq/BW change handlers
with lightweight CSS div elements repositioned via transform: translateX().
This is GPU-composited with zero layout/paint cost, making frequency and
bandwidth changes appear instantaneous. The full WebGL overlay catches up
on the next requestAnimationFrame.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 08:09:36 +01:00
sjg dc2c8b6eb1 [fix](trx-frontend-http): instant spectrum overlay on freq/bw changes
Call drawSignalOverlay() synchronously on frequency and bandwidth changes instead of deferring entirely to requestAnimationFrame. Also make bookmark apply fire-and-forget so the click handler returns immediately after optimistic UI updates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 07:51:30 +01:00
sjg 5821531a93 [feat](trx-client): per-rig audio TCP connections
Replace single-connection relay with per-rig audio manager that spawns independent TCP connections for each rig. Each rig gets its own broadcast channel, stream info, and vchan command routing. Selected rig mirrors to global channels for backward compat. Also fix bookmark apply to update spectrum marker instantly and fire all requests in parallel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 07:37:59 +01:00
sjg 5d905bff87 [fix](trx-frontend-http): stop per-rig audio fallback to global broadcast
When ?rig_id= is specified on /audio, don't fall back to the global broadcast (which carries whichever rig is connected). Return 404 for rigs without an active audio connection instead of silently delivering the wrong rig's audio. Also create per-rig audio channels for all known rigs eagerly so connected rigs are instantly subscribable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 07:26:26 +01:00
sjg bf754f573a [fix](trx-frontend-http): filter SSE channel events by rig and fix audio hang
Channel SSE events were broadcast to all tabs regardless of rig, causing tabs to display wrong rig's channels. Per-rig audio info_rx override caused WebSocket to hang waiting for stream info that never arrives.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 07:17:26 +01:00
sjg 9900314c8c [feat](trx-client): add per-rig spectrum and audio streams
Each browser tab can now subscribe to a specific rig's spectrum and
audio independently via ?rig_id= query params on /spectrum and /audio.
The remote client polls spectrum for all rigs with active subscribers
and routes responses to per-rig watch channels. Virtual channel
commands are routed through per-rig senders with global fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 06:59:54 +01:00
sjg 6fb7b61c1c [feat](trx-frontend-http): auto-subscribe new sessions to primary channel
When a new tab connects and receives the initial channels event,
automatically subscribe to channel 0 (primary) so the session joins
the same tuned channel as other users on that rig. Uses a lightweight
auto-join that skips scheduler control takeover since audio isn't
started yet at this point.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 06:15:47 +01:00
sjg 0e195bd3c6 [fix](trx-frontend-http): remove global state mutation from select_rig
select_rig no longer mutates remote_active_rig_id — only the per-session
mapping is updated. This eliminates cross-tab leaking entirely: each tab
carries its own rig_id via the session manager, /events?rig_id, and
/status?rig_id query params.

The global remote_active_rig_id now only serves as the startup default
for brand-new sessions that have no rig_id yet.

Also fix the About section to show the per-tab lastActiveRigId instead
of the server's global active_rig_id.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 00:20:34 +01:00
sjg f3d8d349b1 [fix](trx-frontend-http): make /status respect per-tab rig selection
pollFreshSnapshot() fetches GET /status on every SSE connect/reconnect,
but /status always returned the global selected rig's state, overwriting
the per-tab display with whichever rig was last switched to globally.

Now pollFreshSnapshot passes rig_id as a query param and the /status
endpoint uses the per-rig watch channel when provided, matching the
/events behavior for true per-tab rig isolation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 00:14:43 +01:00
sjg 0836c815e4 [fix](trx-frontend-http): restore global rig update in select_rig
The previous commit conditionally skipped updating remote_active_rig_id
when session_id was provided, but the remote client reads the global to
route commands to the correct rig on trx-server. Restore the
unconditional global update; cross-tab SSE isolation is handled by the
rig_id query param on /events and the JS-side guard in applyRigList.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 00:08:41 +01:00
sjg c332172900 [fix](trx-frontend-http): pass rig_id to SSE endpoint on reconnect
After select_rig stopped mutating the global remote_active_rig_id for
session-aware clients, SSE reconnects would fall back to the old global
default instead of the newly selected rig. Now connect() passes
lastActiveRigId as a rig_id query param to /events, and the server
prefers it over the global default when present.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 00:04:36 +01:00
sjg b9e1601730 [fix](trx-frontend-http): use green color for active header play button
The .audio-active state was using --accent-green which is actually
orange (#c24b1a). Match the regular play button's hardcoded #00d17f
green so the header button visually matches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 00:02:25 +01:00
sjg 7f13cdf08a [fix](trx-frontend-http): prevent rig switch from leaking across tabs
select_rig was unconditionally updating the global remote_active_rig_id,
causing all SSE sessions to see the changed rig. Now only the per-session
mapping is updated when session_id is provided; the global default is
only changed for non-session-aware clients.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 00:00:49 +01:00
sjg 12a3c62917 [fix](trx-frontend-http): fix play button icon not filling header button
Bump selector specificity to .header-bar-btn.header-audio-btn so the
padding: 0 rule wins over the generic .header-bar-btn padding, and
switch the SVG to width/height: 100% so it expands to fill the button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-22 00:00:44 +01:00
sjg f78097b0ed [feat](trx-rs): per-rig watch channels for independent SSE streams
Add per-rig watch::Sender<RigState> map to FrontendRuntimeContext,
populated by refresh_remote_snapshot for every rig returned by GetRigs.
The SSE /events endpoint now subscribes to the session's rig-specific
watch channel instead of the single global one, allowing different
browser tabs to independently view different rigs. The JS frontend
reconnects SSE on rig switch to pick up the new channel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 23:55:55 +01:00
sjg f023369c7d [style](trx-frontend-http): enlarge play button icon to fill header button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 23:40:56 +01:00
sjg ea362c9cdd [feat](trx-frontend-http): per-session SSE rig selection
Add SessionRigManager to track per-SSE-session rig_id so different
browser tabs can independently select rigs without interfering.
The /events SSE stream filters state updates by session rig (falling
back to the global active rig), and /select_rig accepts an optional
session_id to update the per-session mapping.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 23:38:24 +01:00
sjg dffaed6216 [fix](trx-frontend-http): restore select_rig call and simplify play button icon
Rig switch needs the server call so SSE/audio follow the selected rig. Play button now uses a fixed triangle icon sized to match header controls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 23:17:17 +01:00
sjg 730dbcc20d [feat](trx-frontend-http): add audio play/stop toggle button in header
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 23:13:01 +01:00
sjg 5a12a321b2 [fix](trx-frontend-http): make rig switch purely client-side, no /select_rig call
The /select_rig endpoint sets global server state which affects all tabs. Since postPath() already sends rig_id with every command, the rig picker now just sets the local lastActiveRigId variable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 23:07:36 +01:00
sjg 3412827704 [fix](trx-frontend-http): skip auto-appending rig_id when already in URL
postPath() was duplicating rig_id on /select_rig calls, causing deserialization failure and silently dropping the rig switch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 22:59:48 +01:00
sjg 38f4a71c97 [feat](trx-frontend-http): per-tab rig selection via rig_id on all commands
All POST command endpoints now accept an optional ?rig_id= parameter so each browser tab can independently target a specific rig. The JS frontend tracks the active rig per-tab and auto-appends rig_id to every request.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 22:34:37 +01:00
sjg 6079407257 [fix](trx-frontend-http): widen card bookmark gutter so side stacks are not clipped
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 21:58:49 +01:00
sjg bc596dd9a1 [feat](trx-server): make VFO priming optional via behavior.vfo_prime config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 21:45:59 +01:00
sjg 2a720573f4 [fix](trx-frontend-http): show side bookmark stacks on desktop, hide only on mobile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-21 21:27:27 +01:00