[fix](trx-rs): wire DSP signal strength to Signal strength field and per-vchan SSE
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -362,6 +362,7 @@ let overviewPeakHoldMs = Number(loadSetting("overviewPeakHoldMs", 2000));
|
||||
let decodeHistoryRetentionMin = 24 * 60;
|
||||
let primaryRds = null;
|
||||
let vchanRdsById = new Map();
|
||||
let vchanSignalDbById = new Map();
|
||||
let rdsOverlayEntries = [];
|
||||
|
||||
function currentDecodeHistoryRetentionMs() {
|
||||
@@ -9163,12 +9164,21 @@ function startSpectrumStreaming() {
|
||||
try {
|
||||
const payload = evt.data === "null" ? [] : JSON.parse(evt.data);
|
||||
const next = new Map();
|
||||
const nextSig = new Map();
|
||||
if (Array.isArray(payload)) {
|
||||
payload.forEach((entry) => {
|
||||
if (entry && entry.id) next.set(entry.id, entry.rds ?? null);
|
||||
if (entry && entry.id) {
|
||||
next.set(entry.id, entry.rds ?? null);
|
||||
if (typeof entry.signal_db === "number") nextSig.set(entry.id, entry.signal_db);
|
||||
}
|
||||
});
|
||||
}
|
||||
vchanRdsById = next;
|
||||
vchanSignalDbById = nextSig;
|
||||
if (typeof vchanActiveId !== "undefined" && vchanActiveId && nextSig.has(vchanActiveId)) {
|
||||
sigLastDbm = Math.round(nextSig.get(vchanActiveId));
|
||||
refreshSigStrengthDisplay();
|
||||
}
|
||||
updateRdsPsOverlay(primaryRds);
|
||||
} catch (_) {}
|
||||
});
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
</div>
|
||||
<div class="freq-field sig-strength-col">
|
||||
<div class="sig-strength-display" id="sig-strength" title="Click to change unit">--</div>
|
||||
<div class="label"><span>Sig Strength</span></div>
|
||||
<div class="label"><span>Signal strength</span></div>
|
||||
</div>
|
||||
<div class="freq-field frequency-col">
|
||||
<input class="status-input" id="freq" type="text" value="--" />
|
||||
|
||||
@@ -437,6 +437,9 @@ pub struct VchanRdsEntry {
|
||||
/// Latest RDS data, if decoded.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub rds: Option<RdsData>,
|
||||
/// Channel signal level in dBFS.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub signal_db: Option<f32>,
|
||||
}
|
||||
|
||||
/// Read-only projection of state shared with clients.
|
||||
|
||||
@@ -296,6 +296,7 @@ pub struct ChannelDsp {
|
||||
force_mono_pcm: bool,
|
||||
squelch: VirtualSquelch,
|
||||
noise_blanker: NoiseBlanker,
|
||||
last_signal_db: f32,
|
||||
}
|
||||
|
||||
impl ChannelDsp {
|
||||
@@ -521,6 +522,7 @@ impl ChannelDsp {
|
||||
force_mono_pcm,
|
||||
squelch: VirtualSquelch::new(squelch_cfg),
|
||||
noise_blanker: NoiseBlanker::new(nb_cfg.enabled, nb_cfg.threshold),
|
||||
last_signal_db: -120.0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,6 +617,10 @@ impl ChannelDsp {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn signal_db(&self) -> f32 {
|
||||
self.last_signal_db
|
||||
}
|
||||
|
||||
pub fn reset_rds(&mut self) {
|
||||
if let Some(decoder) = &mut self.wfm_decoder {
|
||||
decoder.reset_rds();
|
||||
@@ -740,6 +746,7 @@ impl ChannelDsp {
|
||||
.sum::<f32>()
|
||||
/ decimated.len() as f32;
|
||||
let signal_db = 10.0 * signal_power.max(1e-12).log10();
|
||||
self.last_signal_db = signal_db;
|
||||
const WFM_OUTPUT_GAIN: f32 = 0.50;
|
||||
let mut audio = if let Some(decoder) = self.wfm_decoder.as_mut() {
|
||||
let mut out = decoder.process_iq(decimated);
|
||||
|
||||
@@ -550,8 +550,21 @@ impl RigCat for SoapySdrRig {
|
||||
fn get_signal_strength<'a>(
|
||||
&'a mut self,
|
||||
) -> Pin<Box<dyn std::future::Future<Output = DynResult<u8>> + Send + 'a>> {
|
||||
// RSSI from real device pending SDR hardware wiring; return 0 for now.
|
||||
Box::pin(async move { Ok(0u8) })
|
||||
Box::pin(async move {
|
||||
let signal_db = self
|
||||
.pipeline
|
||||
.channel_dsps
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(self.primary_channel_idx)
|
||||
.and_then(|dsp| dsp.lock().ok().map(|d| d.signal_db()))
|
||||
.unwrap_or(-120.0);
|
||||
// Map DSP signal power (roughly -120 .. 0 dBFS) to 0..15 range
|
||||
// to match the FT-817 meter scale used by map_signal_strength.
|
||||
let clamped = signal_db.clamp(-120.0, 0.0);
|
||||
let raw = ((clamped + 120.0) / 120.0 * 15.0).round() as u8;
|
||||
Ok(raw.min(15))
|
||||
})
|
||||
}
|
||||
|
||||
// -- TX / unsupported methods -------------------------------------------
|
||||
|
||||
@@ -245,12 +245,19 @@ impl SdrVirtualChannelManager {
|
||||
let dsps = self.pipeline.channel_dsps.read().unwrap();
|
||||
channels
|
||||
.iter()
|
||||
.filter(|ch| matches!(ch.mode, RigMode::WFM))
|
||||
.map(|ch| {
|
||||
let rds = dsps
|
||||
.get(ch.pipeline_slot)
|
||||
.and_then(|dsp| dsp.lock().ok().and_then(|d| d.rds_data()));
|
||||
VchanRdsEntry { id: ch.id, rds }
|
||||
let dsp_guard = dsps.get(ch.pipeline_slot).and_then(|dsp| dsp.lock().ok());
|
||||
let rds = if matches!(ch.mode, RigMode::WFM) {
|
||||
dsp_guard.as_ref().and_then(|d| d.rds_data())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let signal_db = dsp_guard.as_ref().map(|d| d.signal_db());
|
||||
VchanRdsEntry {
|
||||
id: ch.id,
|
||||
rds,
|
||||
signal_db,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user