From 9019acee0e8242ef2aeb252a7a85fc17cd072283 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Tue, 17 Mar 2026 22:57:20 +0100 Subject: [PATCH] [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 Signed-off-by: Stanislaw Grams --- .../trx-backend-soapysdr/src/dsp.rs | 5 ++++ .../trx-backend-soapysdr/src/lib.rs | 23 +++++++++++++++---- .../src/real_iq_source.rs | 6 +++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs index 0d9febf..4138006 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs @@ -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> { diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/lib.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/lib.rs index 75b5b0b..73ec7d0 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/lib.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/lib.rs @@ -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 = Box::new(iq_source); let primary_channel_count = channels.len(); diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/real_iq_source.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/real_iq_source.rs index 254fde7..b6f928a 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/real_iq_source.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/real_iq_source.rs @@ -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)