From 6eb0f3a1161397d0d5241d1036178f98bc74918a Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Tue, 24 Mar 2026 23:04:35 +0100 Subject: [PATCH] [fix](trx-frontend-http): preserve bookmark bandwidth Order bookmark mode and bandwidth updates so WFM bookmarks do\nnot race against the backend mode default.\n\nAlso apply saved bookmark bandwidth in the scheduler path so\nscheduled bookmark replays keep the configured filter width.\n\nTested with:\n- cargo test -p trx-frontend-http\n\nCo-authored-by: OpenAI Codex Signed-off-by: Stan Grams --- .../assets/web/plugins/bookmarks.js | 37 ++++++++++--------- .../trx-frontend-http/src/scheduler.rs | 13 +++++++ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js index 0db185d..766a56d 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js @@ -394,28 +394,31 @@ async function bmApply(bm) { scheduleSpectrumDraw(); } - // --- Fire-and-forget: send mode, bandwidth, and frequency in parallel --- - // The UI is already updated optimistically above; don't block on the - // network round-trips so the bookmark click feels instant. - const modePromise = (async () => { + // Take scheduler control up front, then apply mode before bandwidth so a + // late SetMode cannot revert a saved WFM bookmark bandwidth to 180 kHz. + const tunePromise = (async () => { + if (typeof vchanTakeSchedulerControl === "function") { + await vchanTakeSchedulerControl(); + } + const onVirtual = typeof vchanInterceptMode === "function" && await vchanInterceptMode(bm.mode); if (!onVirtual) { await postPath("/set_mode?mode=" + encodeURIComponent(bm.mode)); } - })(); - const bwPromise = bm.bandwidth_hz ? (async () => { - const bwHandledByVchan = typeof vchanInterceptBandwidth === "function" - && await vchanInterceptBandwidth(bm.bandwidth_hz); - if (!bwHandledByVchan) { - await postPath("/set_bandwidth?hz=" + bm.bandwidth_hz); + + if (bm.bandwidth_hz) { + const bwHandledByVchan = typeof vchanInterceptBandwidth === "function" + && await vchanInterceptBandwidth(bm.bandwidth_hz); + if (!bwHandledByVchan) { + await postPath("/set_bandwidth?hz=" + bm.bandwidth_hz); + } } - })() : Promise.resolve(); - // setRigFrequency is wrapped by vchan.js to redirect to the channel API - // when on a virtual channel, so this call works correctly in both cases. - // It also does its own optimistic update (applyLocalTunedFrequency) but - // that's a no-op since we already set the same value above. - const freqPromise = (async () => { + + // setRigFrequency is wrapped by vchan.js to redirect to the channel API + // when on a virtual channel, so this call works correctly in both cases. + // It also does its own optimistic update (applyLocalTunedFrequency) but + // that's a no-op since we already set the same value above. if (typeof setRigFrequency === "function") { await setRigFrequency(bm.freq_hz); } else { @@ -439,7 +442,7 @@ async function bmApply(bm) { })() : Promise.resolve(); // Don't await — let the network calls settle in the background. // Errors are logged but don't block the UI. - Promise.all([modePromise, bwPromise, freqPromise, decoderPromise]).catch( + Promise.all([tunePromise, decoderPromise]).catch( (err) => console.error("Bookmark apply background error:", err) ); } catch (err) { diff --git a/src/trx-client/trx-frontend/trx-frontend-http/src/scheduler.rs b/src/trx-client/trx-frontend/trx-frontend-http/src/scheduler.rs index 00f1b86..b9899e9 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/src/scheduler.rs +++ b/src/trx-client/trx-frontend/trx-frontend-http/src/scheduler.rs @@ -534,6 +534,19 @@ async fn apply_scheduler_target( ) .await?; + if let Some(bandwidth_hz) = bookmark + .bandwidth_hz + .filter(|bw| *bw > 0 && *bw <= u32::MAX as u64) + .map(|bw| bw as u32) + { + scheduler_send( + rig_tx, + RigCommand::SetBandwidth(bandwidth_hz), + remote.to_string(), + ) + .await?; + } + apply_scheduler_decoders(rig_tx, remote, &bookmark, &extra_bookmarks).await; let status = SchedulerStatus {