From 3ad5f7a3b715e5c6104b29cef29c465d51f41c05 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 22 Mar 2026 08:57:50 +0100 Subject: [PATCH] [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 Signed-off-by: Stan Grams --- .../assets/web/plugins/vchan.js | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js index a6facf5..9e87e88 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js @@ -433,7 +433,7 @@ function vchanSyncAccentUI() { // Saved reference to the original refreshFreqDisplay from app.js. let _origRefreshFreqDisplay = null; -async function vchanSetChannelFreq(freqHz) { +function vchanSetChannelFreq(freqHz) { if (!vchanRigId || !vchanActiveId) return; // Validate against current SDR capture window. if (typeof lastSpectrumData !== "undefined" && lastSpectrumData && @@ -450,20 +450,16 @@ async function vchanSetChannelFreq(freqHz) { return; } } - try { - await vchanTakeSchedulerControl(); - const resp = await fetch( - `/channels/${encodeURIComponent(vchanRigId)}/${encodeURIComponent(vchanActiveId)}/freq`, - { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ freq_hz: Math.round(freqHz) }), - } - ); - if (!resp.ok) console.warn("vchan: set freq failed", resp.status); - } catch (e) { - console.error("vchan: set freq error", e); - } + // Fire-and-forget: scheduler control + channel freq PUT run in background. + vchanTakeSchedulerControl(); + fetch( + `/channels/${encodeURIComponent(vchanRigId)}/${encodeURIComponent(vchanActiveId)}/freq`, + { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ freq_hz: Math.round(freqHz) }), + } + ).catch(e => console.error("vchan: set freq error", e)); } async function vchanSetChannelBandwidth(bwHz) { @@ -524,13 +520,22 @@ window.vchanInterceptBandwidth = async function(bwHz) { // the server when on a non-primary channel. (function() { const _orig = window.setRigFrequency; - window.setRigFrequency = async function(freqHz) { + window.setRigFrequency = function(freqHz) { if (vchanIsOnVirtual()) { - await vchanSetChannelFreq(freqHz); + // Optimistic local update first, then fire-and-forget channel API. + if (typeof applyLocalTunedFrequency === "function") { + if (typeof _freqOptimisticSeq !== "undefined") { + ++_freqOptimisticSeq; + _freqOptimisticHz = Math.round(freqHz); + } + applyLocalTunedFrequency(Math.round(freqHz)); + } + vchanSetChannelFreq(freqHz); return; } - await vchanTakeSchedulerControl(); - if (typeof _orig === "function") return _orig(freqHz); + // Scheduler control is fire-and-forget — don't block the freq change. + vchanTakeSchedulerControl(); + if (typeof _orig === "function") _orig(freqHz); }; })();