[feat](trx-backend-soapysdr): seed LNA gain from hardware at init
Add read_named_gain to IqSource (default: None) and implement it in RealIqSource via Device::gain_element. Read the "LNA" element before boxing the source so the initial sdr_lna_gain_db reflects the actual hardware state, making the UI control visible and correct on first connect. Devices without an LNA element (e.g. RTL-SDR with "TUNER") return None and the control stays hidden. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
@@ -63,6 +63,12 @@ pub trait IqSource: Send + 'static {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read the current value of a named gain element. Returns `None` for
|
||||
/// sources that do not support named gain elements.
|
||||
fn read_named_gain(&self, _name: &str) -> Option<f64> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Enable or disable hardware automatic gain control. Default
|
||||
/// implementation is a no-op for sources that do not support AGC.
|
||||
fn set_gain_mode(&mut self, _automatic: bool) -> Result<(), String> {
|
||||
|
||||
@@ -10,6 +10,7 @@ pub mod vchan_impl;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use dsp::IqSource as _;
|
||||
use trx_core::radio::freq::{Band, Freq};
|
||||
use trx_core::rig::response::RigError;
|
||||
use trx_core::rig::state::{RigFilterState, SpectrumData, VchanRdsEntry, WfmDenoiseLevel};
|
||||
@@ -155,13 +156,21 @@ impl SoapySdrRig {
|
||||
let hardware_center_hz = initial_freq.hz as i64 - center_offset_hz;
|
||||
|
||||
// Create real IQ source from hardware device.
|
||||
let iq_source: Box<dyn dsp::IqSource> = Box::new(real_iq_source::RealIqSource::new(
|
||||
let iq_source = real_iq_source::RealIqSource::new(
|
||||
args,
|
||||
hardware_center_hz as f64,
|
||||
sdr_sample_rate as f64,
|
||||
bandwidth_hz as f64,
|
||||
effective_gain_db,
|
||||
)?);
|
||||
)?;
|
||||
// Read the initial LNA gain from the hardware before the source is
|
||||
// moved into the pipeline thread. Returns None on devices that do
|
||||
// not expose an "LNA" gain element (e.g. RTL-SDR exposes "TUNER").
|
||||
let initial_lna_gain_db = iq_source.read_named_gain("LNA");
|
||||
if let Some(lna) = initial_lna_gain_db {
|
||||
tracing::info!("SDR LNA gain element present, initial value: {:.1} dB", lna);
|
||||
}
|
||||
let iq_source: Box<dyn dsp::IqSource> = Box::new(iq_source);
|
||||
|
||||
let primary_channel_count = channels.len();
|
||||
let mut all_channels = channels.to_vec();
|
||||
@@ -287,7 +296,7 @@ impl SoapySdrRig {
|
||||
wfm_denoise: WfmDenoiseLevel::Auto,
|
||||
gain_db,
|
||||
max_gain_db,
|
||||
lna_gain_db: None,
|
||||
lna_gain_db: initial_lna_gain_db,
|
||||
agc_enabled,
|
||||
squelch_enabled,
|
||||
squelch_threshold_db,
|
||||
|
||||
@@ -185,6 +185,12 @@ impl IqSource for RealIqSource {
|
||||
.map_err(|e| format!("Failed to set SDR {} gain: {}", name, e))
|
||||
}
|
||||
|
||||
fn read_named_gain(&self, name: &str) -> Option<f64> {
|
||||
self.device
|
||||
.gain_element(soapysdr::Direction::Rx, 0, name)
|
||||
.ok()
|
||||
}
|
||||
|
||||
fn set_gain_mode(&mut self, automatic: bool) -> Result<(), String> {
|
||||
self.device
|
||||
.set_gain_mode(soapysdr::Direction::Rx, 0, automatic)
|
||||
|
||||
Reference in New Issue
Block a user