[fix](trx-rs): keep SDR center frequency stable in-band
Signed-off-by: Stan Grams <sjg@haxx.space> Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
@@ -173,6 +173,7 @@ function applyAuthRestrictions() {
|
|||||||
const powerBtn = document.getElementById("power-btn");
|
const powerBtn = document.getElementById("power-btn");
|
||||||
const lockBtn = document.getElementById("lock-btn");
|
const lockBtn = document.getElementById("lock-btn");
|
||||||
const freqInput = document.getElementById("freq");
|
const freqInput = document.getElementById("freq");
|
||||||
|
const centerFreqInput = document.getElementById("center-freq");
|
||||||
const modeSelect = document.getElementById("mode");
|
const modeSelect = document.getElementById("mode");
|
||||||
const txLimitInput = document.getElementById("tx-limit");
|
const txLimitInput = document.getElementById("tx-limit");
|
||||||
const txLimitBtn = document.getElementById("tx-limit-btn");
|
const txLimitBtn = document.getElementById("tx-limit-btn");
|
||||||
@@ -193,6 +194,7 @@ function applyAuthRestrictions() {
|
|||||||
|
|
||||||
// Disable frequency/mode inputs
|
// Disable frequency/mode inputs
|
||||||
if (freqInput) freqInput.disabled = true;
|
if (freqInput) freqInput.disabled = true;
|
||||||
|
if (centerFreqInput) centerFreqInput.disabled = true;
|
||||||
if (modeSelect) modeSelect.disabled = true;
|
if (modeSelect) modeSelect.disabled = true;
|
||||||
if (txLimitInput) txLimitInput.disabled = true;
|
if (txLimitInput) txLimitInput.disabled = true;
|
||||||
|
|
||||||
@@ -260,18 +262,22 @@ function applyCapabilities(caps) {
|
|||||||
|
|
||||||
// Spectrum panel (SDR-only)
|
// Spectrum panel (SDR-only)
|
||||||
const spectrumPanel = document.getElementById("spectrum-panel");
|
const spectrumPanel = document.getElementById("spectrum-panel");
|
||||||
|
const centerFreqField = document.getElementById("center-freq-field");
|
||||||
if (spectrumPanel) {
|
if (spectrumPanel) {
|
||||||
if (caps.filter_controls) {
|
if (caps.filter_controls) {
|
||||||
spectrumPanel.style.display = "";
|
spectrumPanel.style.display = "";
|
||||||
|
if (centerFreqField) centerFreqField.style.display = "";
|
||||||
startSpectrumPolling();
|
startSpectrumPolling();
|
||||||
} else {
|
} else {
|
||||||
spectrumPanel.style.display = "none";
|
spectrumPanel.style.display = "none";
|
||||||
|
if (centerFreqField) centerFreqField.style.display = "none";
|
||||||
stopSpectrumPolling();
|
stopSpectrumPolling();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const freqEl = document.getElementById("freq");
|
const freqEl = document.getElementById("freq");
|
||||||
|
const centerFreqEl = document.getElementById("center-freq");
|
||||||
const wavelengthEl = document.getElementById("wavelength");
|
const wavelengthEl = document.getElementById("wavelength");
|
||||||
const modeEl = document.getElementById("mode");
|
const modeEl = document.getElementById("mode");
|
||||||
const bandLabel = document.getElementById("band-label");
|
const bandLabel = document.getElementById("band-label");
|
||||||
@@ -316,6 +322,7 @@ let sigMeasureAccumMs = 0;
|
|||||||
let sigMeasureWeighted = 0;
|
let sigMeasureWeighted = 0;
|
||||||
let sigMeasurePeak = null;
|
let sigMeasurePeak = null;
|
||||||
let lastFreqHz = null;
|
let lastFreqHz = null;
|
||||||
|
let centerFreqDirty = false;
|
||||||
let jogStep = loadSetting("jogStep", 1000);
|
let jogStep = loadSetting("jogStep", 1000);
|
||||||
let minFreqStepHz = 1;
|
let minFreqStepHz = 1;
|
||||||
const VFO_COLORS = ["var(--accent-green)", "var(--accent-yellow)"];
|
const VFO_COLORS = ["var(--accent-green)", "var(--accent-yellow)"];
|
||||||
@@ -619,6 +626,11 @@ function refreshFreqDisplay() {
|
|||||||
refreshWavelengthDisplay(lastFreqHz);
|
refreshWavelengthDisplay(lastFreqHz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function refreshCenterFreqDisplay() {
|
||||||
|
if (!centerFreqEl || !lastSpectrumData || centerFreqDirty) return;
|
||||||
|
centerFreqEl.value = formatFreqForStep(lastSpectrumData.center_hz, jogStep);
|
||||||
|
}
|
||||||
|
|
||||||
function parseFreqInput(val, defaultStep) {
|
function parseFreqInput(val, defaultStep) {
|
||||||
if (!val) return null;
|
if (!val) return null;
|
||||||
const trimmed = val.trim().toLowerCase();
|
const trimmed = val.trim().toLowerCase();
|
||||||
@@ -701,6 +713,7 @@ function updateJogStepSupport(cap) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
refreshFreqDisplay();
|
refreshFreqDisplay();
|
||||||
|
refreshCenterFreqDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeMode(modeVal) {
|
function normalizeMode(modeVal) {
|
||||||
@@ -751,7 +764,7 @@ function formatSignal(sUnits) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setDisabled(disabled) {
|
function setDisabled(disabled) {
|
||||||
[freqEl, modeEl, pttBtn, powerBtn, txLimitInput, txLimitBtn, lockBtn].forEach((el) => {
|
[freqEl, centerFreqEl, modeEl, pttBtn, powerBtn, txLimitInput, txLimitBtn, lockBtn].forEach((el) => {
|
||||||
if (el) el.disabled = disabled;
|
if (el) el.disabled = disabled;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1299,6 +1312,32 @@ async function applyFreqFromInput() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function applyCenterFreqFromInput() {
|
||||||
|
if (!centerFreqEl) return;
|
||||||
|
const parsedRaw = parseFreqInput(centerFreqEl.value, jogStep);
|
||||||
|
const parsed = alignFreqToRigStep(parsedRaw);
|
||||||
|
if (parsed === null) {
|
||||||
|
showHint("Central freq missing", 1500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!freqAllowed(parsed)) {
|
||||||
|
showHint("Out of supported bands", 1500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
centerFreqDirty = false;
|
||||||
|
centerFreqEl.disabled = true;
|
||||||
|
showHint("Setting central frequency…");
|
||||||
|
try {
|
||||||
|
await postPath(`/set_center_freq?hz=${parsed}`);
|
||||||
|
showHint("Central freq set", 1500);
|
||||||
|
} catch (err) {
|
||||||
|
showHint("Set central freq failed", 2000);
|
||||||
|
console.error(err);
|
||||||
|
} finally {
|
||||||
|
centerFreqEl.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
freqEl.addEventListener("keydown", (e) => {
|
freqEl.addEventListener("keydown", (e) => {
|
||||||
freqDirty = true;
|
freqDirty = true;
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
@@ -1306,6 +1345,15 @@ freqEl.addEventListener("keydown", (e) => {
|
|||||||
applyFreqFromInput();
|
applyFreqFromInput();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (centerFreqEl) {
|
||||||
|
centerFreqEl.addEventListener("keydown", (e) => {
|
||||||
|
centerFreqDirty = true;
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
applyCenterFreqFromInput();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
freqEl.addEventListener("wheel", (e) => {
|
freqEl.addEventListener("wheel", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const direction = e.deltaY < 0 ? 1 : -1;
|
const direction = e.deltaY < 0 ? 1 : -1;
|
||||||
@@ -1394,6 +1442,7 @@ jogStepEl.addEventListener("click", (e) => {
|
|||||||
btn.classList.add("active");
|
btn.classList.add("active");
|
||||||
saveSetting("jogStep", jogStep);
|
saveSetting("jogStep", jogStep);
|
||||||
refreshFreqDisplay();
|
refreshFreqDisplay();
|
||||||
|
refreshCenterFreqDisplay();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Restore active jog step button from saved setting
|
// Restore active jog step button from saved setting
|
||||||
@@ -2416,6 +2465,7 @@ async function fetchSpectrum() {
|
|||||||
if (resp.status === 204) { lastSpectrumData = null; clearSpectrumCanvas(); return; }
|
if (resp.status === 204) { lastSpectrumData = null; clearSpectrumCanvas(); return; }
|
||||||
if (!resp.ok) return;
|
if (!resp.ok) return;
|
||||||
lastSpectrumData = await resp.json();
|
lastSpectrumData = await resp.json();
|
||||||
|
refreshCenterFreqDisplay();
|
||||||
drawSpectrum(lastSpectrumData);
|
drawSpectrum(lastSpectrumData);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,10 @@
|
|||||||
<input class="status-input" id="freq" type="text" value="--" />
|
<input class="status-input" id="freq" type="text" value="--" />
|
||||||
<div class="label"><span>Frequency</span></div>
|
<div class="label"><span>Frequency</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="freq-field frequency-col" id="center-freq-field" style="display:none;">
|
||||||
|
<input class="status-input" id="center-freq" type="text" value="--" />
|
||||||
|
<div class="label"><span>Central Frequency</span></div>
|
||||||
|
</div>
|
||||||
<div class="freq-field unit-col">
|
<div class="freq-field unit-col">
|
||||||
<div class="jog-step" id="jog-step">
|
<div class="jog-step" id="jog-step">
|
||||||
<button type="button" data-step="1000000">MHz</button>
|
<button type="button" data-step="1000000">MHz</button>
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ button:disabled { opacity: 0.6; cursor: not-allowed; }
|
|||||||
.inline { display: flex; gap: 0.5rem; align-items: center; }
|
.inline { display: flex; gap: 0.5rem; align-items: center; }
|
||||||
.freq-inline {
|
.freq-inline {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.freq-field {
|
.freq-field {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -253,7 +254,7 @@ button:disabled { opacity: 0.6; cursor: not-allowed; }
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.frequency-col #freq {
|
.frequency-col input.status-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 3.35rem;
|
height: 3.35rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
@@ -355,6 +355,14 @@ pub async fn set_freq(
|
|||||||
send_command(&rig_tx, RigCommand::SetFreq(Freq { hz: query.hz })).await
|
send_command(&rig_tx, RigCommand::SetFreq(Freq { hz: query.hz })).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/set_center_freq")]
|
||||||
|
pub async fn set_center_freq(
|
||||||
|
query: web::Query<FreqQuery>,
|
||||||
|
rig_tx: web::Data<mpsc::Sender<RigRequest>>,
|
||||||
|
) -> Result<HttpResponse, Error> {
|
||||||
|
send_command(&rig_tx, RigCommand::SetCenterFreq(Freq { hz: query.hz })).await
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct ModeQuery {
|
pub struct ModeQuery {
|
||||||
pub mode: String,
|
pub mode: String,
|
||||||
@@ -633,6 +641,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||||||
.service(lock_panel)
|
.service(lock_panel)
|
||||||
.service(unlock_panel)
|
.service(unlock_panel)
|
||||||
.service(set_freq)
|
.service(set_freq)
|
||||||
|
.service(set_center_freq)
|
||||||
.service(set_mode)
|
.service(set_mode)
|
||||||
.service(set_ptt)
|
.service(set_ptt)
|
||||||
.service(set_tx_limit)
|
.service(set_tx_limit)
|
||||||
|
|||||||
@@ -591,6 +591,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_route_access_control_paths() {
|
fn test_route_access_control_paths() {
|
||||||
assert_eq!(RouteAccess::from_path("/set_freq"), RouteAccess::Control);
|
assert_eq!(RouteAccess::from_path("/set_freq"), RouteAccess::Control);
|
||||||
|
assert_eq!(
|
||||||
|
RouteAccess::from_path("/set_center_freq"),
|
||||||
|
RouteAccess::Control
|
||||||
|
);
|
||||||
assert_eq!(RouteAccess::from_path("/set_mode"), RouteAccess::Control);
|
assert_eq!(RouteAccess::from_path("/set_mode"), RouteAccess::Control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::RigMode;
|
|||||||
pub enum RigCommand {
|
pub enum RigCommand {
|
||||||
GetSnapshot,
|
GetSnapshot,
|
||||||
SetFreq(Freq),
|
SetFreq(Freq),
|
||||||
|
SetCenterFreq(Freq),
|
||||||
SetMode(RigMode),
|
SetMode(RigMode),
|
||||||
SetPtt(bool),
|
SetPtt(bool),
|
||||||
PowerOn,
|
PowerOn,
|
||||||
|
|||||||
@@ -491,6 +491,7 @@ pub fn command_from_rig_command(cmd: RigCommand) -> Box<dyn RigCommandHandler> {
|
|||||||
match cmd {
|
match cmd {
|
||||||
RigCommand::GetSnapshot => Box::new(GetSnapshotCommand),
|
RigCommand::GetSnapshot => Box::new(GetSnapshotCommand),
|
||||||
RigCommand::SetFreq(freq) => Box::new(SetFreqCommand::new(freq)),
|
RigCommand::SetFreq(freq) => Box::new(SetFreqCommand::new(freq)),
|
||||||
|
RigCommand::SetCenterFreq(_) => Box::new(GetSnapshotCommand),
|
||||||
RigCommand::SetMode(mode) => Box::new(SetModeCommand::new(mode)),
|
RigCommand::SetMode(mode) => Box::new(SetModeCommand::new(mode)),
|
||||||
RigCommand::SetPtt(ptt) => Box::new(SetPttCommand::new(ptt)),
|
RigCommand::SetPtt(ptt) => Box::new(SetPttCommand::new(ptt)),
|
||||||
RigCommand::PowerOn => Box::new(PowerOnCommand),
|
RigCommand::PowerOn => Box::new(PowerOnCommand),
|
||||||
|
|||||||
@@ -88,6 +88,16 @@ pub trait RigCat: Rig + Send {
|
|||||||
freq: Freq,
|
freq: Freq,
|
||||||
) -> Pin<Box<dyn Future<Output = DynResult<()>> + Send + 'a>>;
|
) -> Pin<Box<dyn Future<Output = DynResult<()>> + Send + 'a>>;
|
||||||
|
|
||||||
|
fn set_center_freq<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
_freq: Freq,
|
||||||
|
) -> Pin<Box<dyn Future<Output = DynResult<()>> + Send + 'a>> {
|
||||||
|
Box::pin(std::future::ready(Err(
|
||||||
|
Box::new(response::RigError::not_supported("set_center_freq"))
|
||||||
|
as Box<dyn std::error::Error + Send + Sync>,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
fn set_mode<'a>(
|
fn set_mode<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
mode: RigMode,
|
mode: RigMode,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ pub fn client_command_to_rig(cmd: ClientCommand) -> RigCommand {
|
|||||||
}
|
}
|
||||||
ClientCommand::GetState => RigCommand::GetSnapshot,
|
ClientCommand::GetState => RigCommand::GetSnapshot,
|
||||||
ClientCommand::SetFreq { freq_hz } => RigCommand::SetFreq(Freq { hz: freq_hz }),
|
ClientCommand::SetFreq { freq_hz } => RigCommand::SetFreq(Freq { hz: freq_hz }),
|
||||||
|
ClientCommand::SetCenterFreq { freq_hz } => RigCommand::SetCenterFreq(Freq { hz: freq_hz }),
|
||||||
ClientCommand::SetMode { mode } => RigCommand::SetMode(parse_mode(&mode)),
|
ClientCommand::SetMode { mode } => RigCommand::SetMode(parse_mode(&mode)),
|
||||||
ClientCommand::SetPtt { ptt } => RigCommand::SetPtt(ptt),
|
ClientCommand::SetPtt { ptt } => RigCommand::SetPtt(ptt),
|
||||||
ClientCommand::PowerOn => RigCommand::PowerOn,
|
ClientCommand::PowerOn => RigCommand::PowerOn,
|
||||||
@@ -59,6 +60,7 @@ pub fn rig_command_to_client(cmd: RigCommand) -> ClientCommand {
|
|||||||
match cmd {
|
match cmd {
|
||||||
RigCommand::GetSnapshot => ClientCommand::GetState,
|
RigCommand::GetSnapshot => ClientCommand::GetState,
|
||||||
RigCommand::SetFreq(freq) => ClientCommand::SetFreq { freq_hz: freq.hz },
|
RigCommand::SetFreq(freq) => ClientCommand::SetFreq { freq_hz: freq.hz },
|
||||||
|
RigCommand::SetCenterFreq(freq) => ClientCommand::SetCenterFreq { freq_hz: freq.hz },
|
||||||
RigCommand::SetMode(mode) => ClientCommand::SetMode {
|
RigCommand::SetMode(mode) => ClientCommand::SetMode {
|
||||||
mode: mode_to_string(&mode),
|
mode: mode_to_string(&mode),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub enum ClientCommand {
|
|||||||
GetState,
|
GetState,
|
||||||
GetRigs,
|
GetRigs,
|
||||||
SetFreq { freq_hz: u64 },
|
SetFreq { freq_hz: u64 },
|
||||||
|
SetCenterFreq { freq_hz: u64 },
|
||||||
SetMode { mode: String },
|
SetMode { mode: String },
|
||||||
SetPtt { ptt: bool },
|
SetPtt { ptt: bool },
|
||||||
PowerOn,
|
PowerOn,
|
||||||
|
|||||||
@@ -449,6 +449,13 @@ async fn process_command(
|
|||||||
let _ = ctx.state_tx.send(ctx.state.clone());
|
let _ = ctx.state_tx.send(ctx.state.clone());
|
||||||
return snapshot_from(ctx.state);
|
return snapshot_from(ctx.state);
|
||||||
}
|
}
|
||||||
|
RigCommand::SetCenterFreq(freq) => {
|
||||||
|
if let Err(e) = ctx.rig.set_center_freq(freq).await {
|
||||||
|
return Err(RigError::communication(format!("set_center_freq: {e}")));
|
||||||
|
}
|
||||||
|
*ctx.poll_pause_until = Some(Instant::now() + Duration::from_millis(200));
|
||||||
|
return snapshot_from(ctx.state);
|
||||||
|
}
|
||||||
RigCommand::GetSpectrum => {
|
RigCommand::GetSpectrum => {
|
||||||
// Fetch current spectrum and embed it in a one-shot snapshot.
|
// Fetch current spectrum and embed it in a one-shot snapshot.
|
||||||
ctx.state.spectrum = ctx.rig.get_spectrum();
|
ctx.state.spectrum = ctx.rig.get_spectrum();
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ pub struct SoapySdrRig {
|
|||||||
/// How many Hz below the dial frequency the SDR hardware is actually tuned.
|
/// How many Hz below the dial frequency the SDR hardware is actually tuned.
|
||||||
/// The DSP mixer compensates for this offset to demodulate the dial frequency.
|
/// The DSP mixer compensates for this offset to demodulate the dial frequency.
|
||||||
center_offset_hz: i64,
|
center_offset_hz: i64,
|
||||||
|
/// Actual hardware center frequency currently tuned on the SDR.
|
||||||
|
center_hz: i64,
|
||||||
/// Used to send hardware retune commands to the IQ read loop.
|
/// Used to send hardware retune commands to the IQ read loop.
|
||||||
retune_cmd: Arc<std::sync::Mutex<Option<f64>>>,
|
retune_cmd: Arc<std::sync::Mutex<Option<f64>>>,
|
||||||
}
|
}
|
||||||
@@ -94,14 +96,13 @@ impl SoapySdrRig {
|
|||||||
let hardware_center_hz = initial_freq.hz as i64 - center_offset_hz;
|
let hardware_center_hz = initial_freq.hz as i64 - center_offset_hz;
|
||||||
|
|
||||||
// Create real IQ source from hardware device.
|
// Create real IQ source from hardware device.
|
||||||
let iq_source: Box<dyn dsp::IqSource> =
|
let iq_source: Box<dyn dsp::IqSource> = Box::new(real_iq_source::RealIqSource::new(
|
||||||
Box::new(real_iq_source::RealIqSource::new(
|
args,
|
||||||
args,
|
hardware_center_hz as f64,
|
||||||
hardware_center_hz as f64,
|
sdr_sample_rate as f64,
|
||||||
sdr_sample_rate as f64,
|
bandwidth_hz as f64,
|
||||||
bandwidth_hz as f64,
|
gain_db,
|
||||||
gain_db,
|
)?);
|
||||||
)?);
|
|
||||||
|
|
||||||
let pipeline = dsp::SdrPipeline::start(
|
let pipeline = dsp::SdrPipeline::start(
|
||||||
iq_source,
|
iq_source,
|
||||||
@@ -172,6 +173,7 @@ impl SoapySdrRig {
|
|||||||
fir_taps,
|
fir_taps,
|
||||||
spectrum_buf,
|
spectrum_buf,
|
||||||
center_offset_hz,
|
center_offset_hz,
|
||||||
|
center_hz: hardware_center_hz,
|
||||||
retune_cmd,
|
retune_cmd,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -242,10 +244,34 @@ impl RigCat for SoapySdrRig {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
tracing::debug!("SoapySdrRig: set_freq -> {} Hz", freq.hz);
|
tracing::debug!("SoapySdrRig: set_freq -> {} Hz", freq.hz);
|
||||||
self.freq = freq;
|
self.freq = freq;
|
||||||
// Retune the hardware center to keep the dial frequency off-DC.
|
let half_span_hz = i128::from(self.pipeline.sdr_sample_rate) / 2;
|
||||||
let hardware_hz = freq.hz as i64 - self.center_offset_hz;
|
let current_center_hz = i128::from(self.center_hz);
|
||||||
|
let target_hz = i128::from(freq.hz);
|
||||||
|
let within_current_span = target_hz >= current_center_hz - half_span_hz
|
||||||
|
&& target_hz <= current_center_hz + half_span_hz;
|
||||||
|
|
||||||
|
if !within_current_span {
|
||||||
|
// Only retune when the requested dial frequency leaves the
|
||||||
|
// currently captured SDR bandwidth.
|
||||||
|
let hardware_hz = freq.hz as i64 - self.center_offset_hz;
|
||||||
|
self.center_hz = hardware_hz;
|
||||||
|
if let Ok(mut cmd) = self.retune_cmd.lock() {
|
||||||
|
*cmd = Some(hardware_hz as f64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_center_freq<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
freq: Freq,
|
||||||
|
) -> Pin<Box<dyn std::future::Future<Output = DynResult<()>> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
tracing::debug!("SoapySdrRig: set_center_freq -> {} Hz", freq.hz);
|
||||||
|
self.center_hz = freq.hz as i64;
|
||||||
if let Ok(mut cmd) = self.retune_cmd.lock() {
|
if let Ok(mut cmd) = self.retune_cmd.lock() {
|
||||||
*cmd = Some(hardware_hz as f64);
|
*cmd = Some(self.center_hz as f64);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
@@ -402,11 +428,9 @@ impl RigCat for SoapySdrRig {
|
|||||||
|
|
||||||
fn get_spectrum(&self) -> Option<SpectrumData> {
|
fn get_spectrum(&self) -> Option<SpectrumData> {
|
||||||
let bins = self.spectrum_buf.lock().ok()?.clone()?;
|
let bins = self.spectrum_buf.lock().ok()?.clone()?;
|
||||||
// Report the actual hardware center frequency, not the dial frequency.
|
|
||||||
let center_hz = (self.freq.hz as i64 - self.center_offset_hz) as u64;
|
|
||||||
Some(SpectrumData {
|
Some(SpectrumData {
|
||||||
bins,
|
bins,
|
||||||
center_hz,
|
center_hz: self.center_hz.max(0) as u64,
|
||||||
sample_rate: self.pipeline.sdr_sample_rate,
|
sample_rate: self.pipeline.sdr_sample_rate,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user