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>
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>
start == end previously matched nothing (empty range). Now treated as a
24-hour window, making it easy to define a catch-all bookmark without
manually entering 00:00–23:59.
UI shows "All day / —" in the entries table and tooltip hints on both time
inputs explain the convention.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Each ScheduleEntry can now carry its own interleave_min, overriding the
config-level default for that slot in the cycle. The cycle length is the
sum of all active entries' effective durations (weighted), so entries with
longer individual interleave times occupy proportionally more time.
UI: "Interleave (min, optional)" input in the add-entry form; value shown
in the entries table (displays "—" when using the config default).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
When multiple time-span entries are active simultaneously, the scheduler
now cycles through them by slot: slot = floor(utc_min / interleave_min) % count.
The interleave_min field is optional (null disables, first match wins).
UI: "Interleave time (min)" number input in the TimeSpan section with a
hint explaining the behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Implements a scheduler that retunes the rig automatically when no SSE
clients are connected. Two modes are supported:
- Grayline: tunes to per-period bookmarks (dawn/day/dusk/night) based on
an inline NOAA solar algorithm given station lat/lon.
- Time Span: tunes to bookmarks within user-defined UTC windows; midnight-
spanning intervals supported.
Backend:
- SchedulerStore (PickleDB, sch:{rig_id} keys) in scheduler.rs
- spawn_scheduler_task polls every 30 s, checks context.sse_clients == 0,
sends SetFreq + SetMode via RigRequest with rig_id_override
- HTTP API: GET/PUT/DELETE /scheduler/{rig_id}, GET …/status
- sse_clients Arc<AtomicUsize> added to FrontendRuntimeContext and shared
with the SSE counter in build_server (single source of truth)
- /scheduler/ added to Read auth routes (write requires Control)
Frontend:
- Scheduler tab (clock icon, 6th position) with Grayline/TimeSpan UI
- scheduler.js plugin: loads config + bookmarks, live status polling
every 15 s, write controls hidden for Rx-role users
- CSS .sch-* component styles added to style.css
- SCHEDULER.md design document at repo root
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
- Fix 5-tab bottom nav (grid was repeat(4) with 5 tabs; About overflowed)
- Add SVG icons to each tab; show icon+label on mobile bottom nav
- Swipe left/right to switch tabs (excludes jog wheel, spectrum canvas,
map, scrollable containers and form inputs to avoid conflicts)
- Extract navigateToTab() helper used by both click and swipe handlers
- Collapse header subtitles at ≤640px to reclaim vertical space
- Bookmark table → 2-column card layout at ≤640px with ::before labels
- Audio volume labels switch to horizontal row layout at ≤520px;
squelch slider now also spans full width
- Controls tray uses overflow-x: auto (not visible) at ≤760px so
content wider than viewport scrolls rather than overflowing layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
System font stack: replace bare 'sans-serif' with system-ui / -apple-system
/ BlinkMacSystemFont / Segoe UI chain — sharper rendering on all platforms
at zero extra load cost.
Button hover/active: add transition (100ms) + color-mix hover brightening
+ active depression (translateY 1px) to all buttons. Previously buttons had
zero visual feedback on interaction.
Scrollbar styling: thin (6px) custom scrollbars via ::-webkit-scrollbar and
scrollbar-width/color for Firefox. Thumb uses border-color tinted with the
accent on hover — matches each theme automatically via CSS variables.
Phosphor theme: classic green-phosphor CRT aesthetic — near-black background,
#39ff14 neon-green accent, glow text-shadow on the freq display, matching
spectrum/waterfall canvas palette. Both dark and light variants included.
Registered in the style picker select, setStyle() valid list, and
CANVAS_PALETTE.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
- Add "Enable HF APRS" toggle button to the HF APRS tab (same style as
FT8/WSPR); button is disabled during TX like other decoder toggles
- app.js: sync button text/colour from SSE state updates
- hf-aprs.js: connect button click to /toggle_hf_aprs_decode
- bookmarks.js: add "HF APRS" checkbox to Add/Edit Bookmark decoder
section; bmReadDecoders/bmWriteDecoders handle "hf-aprs" key; bmApply
toggles the decoder to match bookmark preference on recall
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Adds a second APRS demodulator path tuned for the HF APRS standard
(300 baud Bell 103-style AFSK, mark=1600 Hz / space=1800 Hz), active
on RigMode::DIG. Shares AX.25 framing, APRS parsing, APRS-IS uplink,
and frontend display with the existing VHF stack.
- trx-aprs: parameterise Demodulator::new(); add AprsDecoder::new_hf()
- trx-core: HfAprs variant in DecodedMessage; hf_aprs_decode_enabled /
hf_aprs_decode_reset_seq in RigState/RigSnapshot; SetHfAprsDecodeEnabled
and ResetHfAprsDecoder commands; handlers.rs fallback arm updated
- trx-protocol: client command variants + bidirectional mapping; test
fixture updated
- trx-server: run_hf_aprs_decoder() task (activates on DIG mode);
hf_aprs history in DecoderHistories; rig_task command dispatch;
aprsfi uplink forwards HfAprs via OR-pattern
- trx-frontend: hf_aprs_history in FrontendRuntimeContext
- trx-frontend-http: prune/record/snapshot/clear helpers; SSE history
replay; toggle_hf_aprs_decode + clear_hf_aprs_decode endpoints;
/hf-aprs.js endpoint; HF APRS tab in web UI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
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>
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>
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>
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>
Fix CW picker redraw when the decoder sub-tab becomes visible to avoid
white/blank canvas rendering.
Widen CW tone picker/input range to 100-10000 Hz and raise CW/CWR
bandwidth max to 9 kHz.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Use an audio-window tone picker for CW with exact click-to-tone mapping.
Make + Add Bookmark inherit the shared button style.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Add a mini waterfall-based CW tone selector in the plugin tab and make CW auto mode apply only to WPM.
Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
Publish decoded VDES positions into the map and revert the VDES burst detector to its original gating thresholds.
Co-authored-by: Stan Grams <sjg@haxx.space>
Signed-off-by: Stan Grams <sjg@haxx.space>
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>
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>
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>
Render AIS vessels with heading-aware ship symbols, keep selected tracks on click, and size the map to fit the viewport cleanly without overextending the page.
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Show AIS vessel tracks only for the selected marker, keep the APRS and AIS history panes viewport-sized with internal scrolling, and tighten the APRS history controls with shorter bookmark-scale buttons.
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Replace the APRS plugin log with a richer history view that adds summaries, filtering, pause/resume, duplicate collapsing, structured rows, row actions, and expandable details.
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Refine the AIS plugin tab with summary cards, clearer vessel rows, and better live-bar deduping, and let long side bookmark names wrap cleanly inside their chips.
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
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>