[fix](trx-backend-soapysdr,trx-frontend-http): keep rds state on bw changes
Co-authored-by: Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -366,9 +366,10 @@ let sigMeasurePeak = null;
|
||||
let lastFreqHz = null;
|
||||
let centerFreqDirty = false;
|
||||
let jogUnit = loadSetting("jogUnit", 1000); // base unit: 1, 1000, 1000000
|
||||
let jogMult = loadSetting("jogMult", 1); // multiplier: 1, 10, 100
|
||||
let jogStep = Math.max(jogUnit * jogMult, 1);
|
||||
let jogMult = loadSetting("jogMult", 1); // divisor: 1, 10, 100
|
||||
let jogStep = Math.max(Math.round(jogUnit / jogMult), 1);
|
||||
let minFreqStepHz = 1;
|
||||
let lastModeName = "";
|
||||
const VFO_COLORS = ["var(--accent-green)", "var(--accent-yellow)"];
|
||||
function vfoColor(idx) {
|
||||
if (idx < VFO_COLORS.length) return VFO_COLORS[idx];
|
||||
@@ -1053,7 +1054,7 @@ function updateJogStepSupport(cap) {
|
||||
Number.isFinite(current) && current >= minFreqStepHz ? current : Math.max(steps[0], minFreqStepHz);
|
||||
|
||||
jogUnit = steps.reduce((best, s) => (Math.abs(s - desired) < Math.abs(best - desired) ? s : best), steps[0]);
|
||||
jogStep = Math.max(jogUnit * jogMult, minFreqStepHz);
|
||||
jogStep = Math.max(Math.round(jogUnit / jogMult), minFreqStepHz);
|
||||
saveSetting("jogUnit", jogUnit);
|
||||
saveSetting("jogStep", jogStep);
|
||||
|
||||
@@ -1240,7 +1241,12 @@ function render(update) {
|
||||
}
|
||||
if (update.status && update.status.mode) {
|
||||
const mode = normalizeMode(update.status.mode);
|
||||
modeEl.value = mode ? mode.toUpperCase() : "";
|
||||
const modeUpper = mode ? mode.toUpperCase() : "";
|
||||
modeEl.value = modeUpper;
|
||||
if (modeUpper === "WFM" && lastModeName !== "WFM") {
|
||||
setJogDivisor(10);
|
||||
}
|
||||
lastModeName = modeUpper;
|
||||
updateWfmControls();
|
||||
// When filter panel is active (SDR backend), update the BW slider range
|
||||
// to match the new mode — but only if the server hasn't already sent a
|
||||
@@ -1716,7 +1722,7 @@ const jogStepEl = document.getElementById("jog-step");
|
||||
const jogMultEl = document.getElementById("jog-mult");
|
||||
|
||||
function applyJogStep() {
|
||||
jogStep = Math.max(jogUnit * jogMult, minFreqStepHz);
|
||||
jogStep = Math.max(Math.round(jogUnit / jogMult), minFreqStepHz);
|
||||
saveSetting("jogUnit", jogUnit);
|
||||
saveSetting("jogMult", jogMult);
|
||||
saveSetting("jogStep", jogStep);
|
||||
@@ -1724,6 +1730,17 @@ function applyJogStep() {
|
||||
refreshCenterFreqDisplay();
|
||||
}
|
||||
|
||||
function setJogDivisor(divisor) {
|
||||
const next = divisor === 10 || divisor === 100 ? divisor : 1;
|
||||
jogMult = next;
|
||||
if (jogMultEl) {
|
||||
jogMultEl.querySelectorAll("button[data-mult]").forEach((b) => {
|
||||
b.classList.toggle("active", parseInt(b.dataset.mult, 10) === jogMult);
|
||||
});
|
||||
}
|
||||
applyJogStep();
|
||||
}
|
||||
|
||||
async function jogFreq(direction) {
|
||||
if (lastLocked) { showHint("Locked", 1500); return; }
|
||||
if (lastFreqHz === null) return;
|
||||
@@ -1835,7 +1852,7 @@ if (jogMultEl) {
|
||||
multBtns.forEach((b) => b.classList.toggle("active", b === activeMult));
|
||||
}
|
||||
}
|
||||
jogStep = Math.max(jogUnit * jogMult, minFreqStepHz);
|
||||
jogStep = Math.max(Math.round(jogUnit / jogMult), minFreqStepHz);
|
||||
}
|
||||
|
||||
async function applyModeFromPicker() {
|
||||
@@ -1850,6 +1867,9 @@ async function applyModeFromPicker() {
|
||||
try {
|
||||
await postPath(`/set_mode?mode=${encodeURIComponent(mode)}`);
|
||||
showHint("Mode set", 1500);
|
||||
if (mode.toUpperCase() === "WFM") {
|
||||
setJogDivisor(10);
|
||||
}
|
||||
// Apply sensible default bandwidth for the new mode and push to server.
|
||||
await applyBwDefaultForMode(mode, true);
|
||||
} catch (err) {
|
||||
|
||||
@@ -124,11 +124,11 @@
|
||||
</div>
|
||||
<div class="freq-field mult-col">
|
||||
<div class="jog-mult" id="jog-mult">
|
||||
<button type="button" data-mult="1" class="active">1×</button>
|
||||
<button type="button" data-mult="10">10×</button>
|
||||
<button type="button" data-mult="100">100×</button>
|
||||
<button type="button" data-mult="1" class="active">1</button>
|
||||
<button type="button" data-mult="10">1/10</button>
|
||||
<button type="button" data-mult="100">1/100</button>
|
||||
</div>
|
||||
<div class="label"><span>Unit Multiplier</span></div>
|
||||
<div class="label"><span>Unit Divisor</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -332,8 +332,8 @@ impl ChannelDsp {
|
||||
(decim_factor, channel_sample_rate)
|
||||
}
|
||||
|
||||
fn rebuild_filters(&mut self) {
|
||||
let (_, channel_sample_rate) = Self::pipeline_rates(
|
||||
fn rebuild_filters(&mut self, reset_wfm_decoder: bool) {
|
||||
let (next_decim_factor, channel_sample_rate) = Self::pipeline_rates(
|
||||
&self.mode,
|
||||
self.sdr_sample_rate,
|
||||
self.audio_sample_rate,
|
||||
@@ -354,13 +354,8 @@ impl ChannelDsp {
|
||||
};
|
||||
self.lpf_i = BlockFirFilter::new(cutoff_norm, self.fir_taps, IQ_BLOCK_SIZE);
|
||||
self.lpf_q = BlockFirFilter::new(cutoff_norm, self.fir_taps, IQ_BLOCK_SIZE);
|
||||
self.decim_factor = Self::pipeline_rates(
|
||||
&self.mode,
|
||||
self.sdr_sample_rate,
|
||||
self.audio_sample_rate,
|
||||
self.audio_bandwidth_hz,
|
||||
)
|
||||
.0;
|
||||
let rate_changed = self.decim_factor != next_decim_factor;
|
||||
self.decim_factor = next_decim_factor;
|
||||
self.decim_counter = 0;
|
||||
self.resample_phase = 0.0;
|
||||
self.resample_phase_inc = if self.sdr_sample_rate == 0 {
|
||||
@@ -368,16 +363,18 @@ impl ChannelDsp {
|
||||
} else {
|
||||
self.audio_sample_rate as f64 / self.sdr_sample_rate as f64
|
||||
};
|
||||
self.wfm_decoder = if self.mode == RigMode::WFM {
|
||||
Some(WfmStereoDecoder::new(
|
||||
channel_sample_rate,
|
||||
self.audio_sample_rate,
|
||||
self.output_channels,
|
||||
self.wfm_deemphasis_us,
|
||||
))
|
||||
if self.mode == RigMode::WFM {
|
||||
if reset_wfm_decoder || rate_changed || self.wfm_decoder.is_none() {
|
||||
self.wfm_decoder = Some(WfmStereoDecoder::new(
|
||||
channel_sample_rate,
|
||||
self.audio_sample_rate,
|
||||
self.output_channels,
|
||||
self.wfm_deemphasis_us,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.wfm_decoder = None;
|
||||
}
|
||||
self.frame_buf.clear();
|
||||
}
|
||||
|
||||
@@ -466,7 +463,7 @@ impl ChannelDsp {
|
||||
self.mode = mode.clone();
|
||||
self.audio_bandwidth_hz = default_bandwidth_for_mode(mode);
|
||||
self.demodulator = Demodulator::for_mode(mode);
|
||||
self.rebuild_filters();
|
||||
self.rebuild_filters(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,12 +487,12 @@ impl ChannelDsp {
|
||||
pub fn set_filter(&mut self, bandwidth_hz: u32, taps: usize) {
|
||||
self.audio_bandwidth_hz = bandwidth_hz;
|
||||
self.fir_taps = taps.max(1);
|
||||
self.rebuild_filters();
|
||||
self.rebuild_filters(false);
|
||||
}
|
||||
|
||||
pub fn set_wfm_deemphasis(&mut self, deemphasis_us: u32) {
|
||||
self.wfm_deemphasis_us = deemphasis_us;
|
||||
self.rebuild_filters();
|
||||
self.rebuild_filters(true);
|
||||
}
|
||||
|
||||
pub fn rds_data(&self) -> Option<RdsData> {
|
||||
|
||||
Reference in New Issue
Block a user