[feat](trx-backend-soapysdr): enable hardware AGC by default if available

Query the device for AGC support via has_gain_mode and enable it
automatically at startup. Devices without hardware AGC fall back to
manual gain as before.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
2026-03-17 22:57:20 +01:00
parent cf4c262456
commit 9019acee0e
3 changed files with 29 additions and 5 deletions
@@ -69,6 +69,11 @@ pub trait IqSource: Send + 'static {
None
}
/// Returns `true` when the hardware supports automatic gain control.
fn has_gain_mode(&self) -> bool {
false
}
/// 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> {
@@ -92,8 +92,6 @@ impl SoapySdrRig {
/// - `gain_mode`: `"auto"` or `"manual"`.
/// - `gain_db`: gain in dB; used when `gain_mode == "manual"`.
/// - `max_gain_db`: optional hard ceiling for the applied hardware gain.
/// When `gain_mode == "auto"` hardware AGC is not yet wired, so this
/// value acts as the fallback.
/// - `audio_sample_rate`: output PCM rate (Hz).
/// - `frame_duration_ms`: output frame length (ms).
/// - `initial_freq`: initial dial frequency reported by `get_status`.
@@ -137,8 +135,6 @@ impl SoapySdrRig {
max_gain_db,
);
let agc_enabled = gain_mode == "auto";
let effective_gain_db = max_gain_db
.map(|max_gain| gain_db.min(max_gain))
.unwrap_or(gain_db);
@@ -155,7 +151,7 @@ impl SoapySdrRig {
let hardware_center_hz = initial_freq.hz as i64 - center_offset_hz;
// Create real IQ source from hardware device.
let iq_source = real_iq_source::RealIqSource::new(
let mut iq_source = real_iq_source::RealIqSource::new(
args,
hardware_center_hz as f64,
sdr_sample_rate as f64,
@@ -169,6 +165,23 @@ impl SoapySdrRig {
if let Some(lna) = initial_lna_gain_db {
tracing::info!("SDR LNA gain element present, initial value: {:.1} dB", lna);
}
// Enable hardware AGC by default if the device supports it.
let agc_enabled = if iq_source.has_gain_mode() {
match iq_source.set_gain_mode(true) {
Ok(()) => {
tracing::info!("Hardware AGC enabled by default");
true
}
Err(e) => {
tracing::warn!("Failed to enable hardware AGC: {}", e);
false
}
}
} else {
tracing::debug!("Hardware AGC not supported by this device");
false
};
let iq_source: Box<dyn dsp::IqSource> = Box::new(iq_source);
let primary_channel_count = channels.len();
@@ -191,6 +191,12 @@ impl IqSource for RealIqSource {
.ok()
}
fn has_gain_mode(&self) -> bool {
self.device
.has_gain_mode(soapysdr::Direction::Rx, 0)
.unwrap_or(false)
}
fn set_gain_mode(&mut self, automatic: bool) -> Result<(), String> {
self.device
.set_gain_mode(soapysdr::Direction::Rx, 0, automatic)