When a scheduler-managed decoder is manually disabled from the frontend,
take scheduler control first so the manual change overrides the current
scheduler cycle like a direct frequency change does.
Track decoder enabled state on the toggle buttons and only take over
when the click is actually disabling FT8, FT4, FT2, WSPR, or HF APRS.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Apply scheduler-backed virtual channels as real manual selections so they take control, retune the rig, and restore bookmark decoder state including APRS/PKT. Also remove the inner border from the map decode locator tooltip.\n\nVerification: cargo test -p trx-frontend-http vchan\nVerification: node --check src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Use the currently tuned virtual channel for the website title\ninstead of always showing channel 0 metadata.\n\nVerification: node --check assets/web/app.js\nVerification: node --check assets/web/plugins/vchan.js\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
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>
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>
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>
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>
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>
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>
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>
- 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>
- 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>
Virtual channel display:
- vchan.js: wrap refreshFreqDisplay() so the main freq field always shows
the active virtual channel's frequency instead of channel 0's; expose
vchanSyncAccentUI() to add vchan-ch-active CSS class (colored border) to
#freq and #spectrum-bw-input when on a non-primary channel
- style.css: --vchan-color (#38bdf8 sky-blue), .vchan-ch-active box-shadow,
vchan-picker active button left-border accent
Scheduler multi-channel slots:
- scheduler.rs: add center_hz (Option<u64>) and bookmark_ids (Vec<String>)
to ScheduleEntry; SchedulerStatus gains last_center_hz and
last_bookmark_ids; background task sends SetCenterFreq before SetFreq
when center_hz is set and records extra bookmark_ids in status
- scheduler.js: center-freq input and extra-channel bookmark picker (tag
list with + / × buttons) in the add-entry form; extra channels shown in
the entries table
- index.html: center freq field + extra bookmark picker widgets; table
gains Center freq and Extra channels columns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
When on a non-primary (virtual) channel, redirect freq and mode changes
to the channel metadata API instead of the server:
- vchan.js: add vchanIsOnVirtual(), vchanSetChannelFreq/Mode(); expose
window.vchanInterceptMode() hook; wrap window.setRigFrequency so all
callers (jog, freq input, bookmarks, spectrum click) are automatically
redirected without modification
- app.js: check vchanInterceptMode() in applyModeFromPicker() before
posting /set_mode
- bookmarks.js: check vchanInterceptMode() for mode in bmApply();
setRigFrequency() redirect is automatic via the vchan.js wrapper;
bandwidth and decoder toggles still apply regardless of channel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>