From 5084c19899fa773b8a91410cd9a2677373bf6ace Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 16 Aug 2026 10:24:30 +0200 Subject: [PATCH] [fix](trx-frontend-http): move passband overlay to resolved DIG sideband MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spectrum passband overlay is drawn one-sided per mode, but DIG was hardcoded to upper sideband — so switching the DIG sideband (or tuning DIG/Auto across 10 MHz) left the overlay on the wrong side of the carrier even though the backend had flipped the demodulator. Resolve the DIG overlay direction from the current sideband policy and dial frequency, mirroring the backend: usb → upper, lsb → lower, auto → upper at or above 10 MHz and lower below. The overlay repaints immediately on a policy change (optimistically on the selector, and on confirmed filter state) and tracks frequency as it already did. Non-SDR backends keep the historical upper-sideband overlay. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01UiK871ht2uPFBHtMbxy3wD Signed-off-by: Stan Grams --- .../assets/web/generated/app.js | 20 ++++++++++- .../trx-frontend-http/frontend/src/app.ts | 33 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/generated/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/generated/app.js index 2759354e..ce058897 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/generated/app.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/generated/app.js @@ -3729,10 +3729,19 @@ function visibleBandwidthSpecs(freqHz = lastFreqHz, mode = modeEl ? modeEl.value } return [{ centerHz: freqHz, widthHz: currentBandwidthHz }]; } +function digSidebandDirection() { + if (sdrDigSidebandPolicy === "usb") return 1; + if (sdrDigSidebandPolicy === "lsb") return -1; + if (typeof lastFreqHz === "number" && isFiniteNumber(lastFreqHz)) { + return lastFreqHz >= DIG_AUTO_SIDEBAND_THRESHOLD_HZ ? 1 : -1; + } + return 1; +} function sidebandDirectionForMode(mode = modeEl ? modeEl.value : "") { const modeUpper = String(mode || "").toUpperCase(); if (modeUpper === "LSB" || modeUpper === "CWR") return -1; - if (modeUpper === "USB" || modeUpper === "CW" || modeUpper === "DIG") return 1; + if (modeUpper === "DIG") return sdrDigSidebandSupported ? digSidebandDirection() : 1; + if (modeUpper === "USB" || modeUpper === "CW") return 1; return 0; } function displaySpanForBandwidthSpec(spec, mode = modeEl ? modeEl.value : "") { @@ -4760,10 +4769,15 @@ function render(update) { } if (typeof update.filter.sdr_dig_sideband === "string") { sdrDigSidebandSupported = true; + const prevPolicy = sdrDigSidebandPolicy; + sdrDigSidebandPolicy = update.filter.sdr_dig_sideband; if (sdrDigSidebandEl && document.activeElement !== sdrDigSidebandEl) { sdrDigSidebandEl.value = update.filter.sdr_dig_sideband; } updateWfmControls(); + if (prevPolicy !== sdrDigSidebandPolicy && lastSpectrumData) { + scheduleSpectrumDraw(); + } } } if (typeof update.show_sdr_gain_control === "boolean") { @@ -6634,6 +6648,8 @@ var sdrNbSupported = false; var sdrDigSidebandWrapEl = document.getElementById("sdr-dig-sideband-wrap"); var sdrDigSidebandEl = document.getElementById("sdr-dig-sideband"); var sdrDigSidebandSupported = false; +var sdrDigSidebandPolicy = "auto"; +var DIG_AUTO_SIDEBAND_THRESHOLD_HZ = 1e7; fetch("/audio", { method: "GET" }).then((r) => { if (r.status === 404) audioRow.style.display = "none"; }).catch(() => { @@ -7033,6 +7049,8 @@ function submitSdrDigSideband() { if (!sdrDigSidebandSupported || !sdrDigSidebandEl) return; const policy = sdrDigSidebandEl.value || "auto"; if (policy !== "auto" && policy !== "usb" && policy !== "lsb") return; + sdrDigSidebandPolicy = policy; + if (lastSpectrumData) scheduleSpectrumDraw(); postPath(`/set_sdr_dig_sideband?policy=${encodeURIComponent(policy)}`).catch(() => { }); } diff --git a/src/trx-client/trx-frontend/trx-frontend-http/frontend/src/app.ts b/src/trx-client/trx-frontend/trx-frontend-http/frontend/src/app.ts index 33ce2e05..800a4cee 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/frontend/src/app.ts +++ b/src/trx-client/trx-frontend/trx-frontend-http/frontend/src/app.ts @@ -2450,10 +2450,26 @@ function visibleBandwidthSpecs(freqHz: number | null = lastFreqHz, mode = modeEl return [{ centerHz: freqHz, widthHz: currentBandwidthHz }]; } +// Resolve the DIG passband direction from the current policy and dial +// frequency, mirroring the backend's demodulator resolution so the spectrum +// overlay lands on the same sideband that is actually being demodulated. +function digSidebandDirection() { + if (sdrDigSidebandPolicy === "usb") return 1; + if (sdrDigSidebandPolicy === "lsb") return -1; + // "auto": USB at/above the threshold, LSB below. + if (typeof lastFreqHz === "number" && isFiniteNumber(lastFreqHz)) { + return lastFreqHz >= DIG_AUTO_SIDEBAND_THRESHOLD_HZ ? 1 : -1; + } + return 1; +} + function sidebandDirectionForMode(mode = modeEl ? modeEl.value : "") { const modeUpper = String(mode || "").toUpperCase(); if (modeUpper === "LSB" || modeUpper === "CWR") return -1; - if (modeUpper === "USB" || modeUpper === "CW" || modeUpper === "DIG") return 1; + // On SDR the DIG sideband is configurable; resolve it. On other backends + // keep the historical upper-sideband overlay. + if (modeUpper === "DIG") return sdrDigSidebandSupported ? digSidebandDirection() : 1; + if (modeUpper === "USB" || modeUpper === "CW") return 1; return 0; } @@ -3683,10 +3699,16 @@ function render(update: AppUpdate) { } if (typeof update.filter.sdr_dig_sideband === "string") { sdrDigSidebandSupported = true; + const prevPolicy = sdrDigSidebandPolicy; + sdrDigSidebandPolicy = update.filter.sdr_dig_sideband; if (sdrDigSidebandEl && document.activeElement !== sdrDigSidebandEl) { sdrDigSidebandEl.value = update.filter.sdr_dig_sideband; } updateWfmControls(); + // Repaint the passband overlay if the DIG sideband just changed. + if (prevPolicy !== sdrDigSidebandPolicy && lastSpectrumData) { + scheduleSpectrumDraw(); + } } } if (typeof update.show_sdr_gain_control === "boolean") { @@ -5621,6 +5643,11 @@ let sdrNbSupported = false; const sdrDigSidebandWrapEl = document.getElementById("sdr-dig-sideband-wrap"); const sdrDigSidebandEl = document.getElementById("sdr-dig-sideband") as HTMLSelectElement | null; let sdrDigSidebandSupported = false; +// Current DIG sideband policy ("auto" | "usb" | "lsb"), mirrored from server +// filter state. Drives the spectrum passband overlay direction for DIG. +let sdrDigSidebandPolicy = "auto"; +// Matches DigSidebandPolicy::AUTO_THRESHOLD_HZ on the backend. +const DIG_AUTO_SIDEBAND_THRESHOLD_HZ = 10_000_000; // Hide audio row if audio is not configured on the server fetch("/audio", { method: "GET" }).then((r) => { @@ -6076,6 +6103,10 @@ function submitSdrDigSideband() { if (!sdrDigSidebandSupported || !sdrDigSidebandEl) return; const policy = sdrDigSidebandEl.value || "auto"; if (policy !== "auto" && policy !== "usb" && policy !== "lsb") return; + // Optimistically move the passband overlay to the chosen sideband so the + // display responds instantly, before the server round-trip confirms it. + sdrDigSidebandPolicy = policy; + if (lastSpectrumData) scheduleSpectrumDraw(); postPath(`/set_sdr_dig_sideband?policy=${encodeURIComponent(policy)}`).catch(() => {}); } if (sdrDigSidebandEl) {