diff --git a/Cargo.toml b/Cargo.toml index 16260d3..8683722 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/FutureSDR/seify" [features] default = ["soapy", "dummy"] -aaronia_http = ["dep:ureq", "dep:serde_json"] +aaronia_http = ["dep:ureq"] bladerf1 = ["dep:libbladerf-rs"] dummy = [] hackrfone = ["dep:seify-hackrfone"] @@ -33,12 +33,12 @@ thiserror = "2.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] once_cell = "1.21" -libbladerf-rs = { version = "0.3.0", optional = true, features = ["bladerf1", "xb100", "xb200", "xb300"] } +libbladerf-rs = { version = "0.4.1", optional = true, features = ["bladerf1", "xb100", "xb200", "xb300"] } +# libbladerf-rs = { path="../libbladerf-rs", optional = true, features = ["bladerf1", "xb100", "xb200", "xb300"] } seify-rtlsdr = { path = "crates/rtl-sdr-rs", version = "0.0.3", optional = true } seify-hackrfone = { path = "crates/seify-hackrfone", version = "0.1.0", optional = true } soapysdr = { version = "0.5", optional = true } ureq = { version = "3.3", features = ["json"], optional = true } -serde_json = { version = "1.0", optional = true } [dev-dependencies] clap = { version = "4.6", features = ["derive"] } diff --git a/examples/rx_threaded.rs b/examples/rx_threaded.rs index 95023ee..37e6886 100644 --- a/examples/rx_threaded.rs +++ b/examples/rx_threaded.rs @@ -68,7 +68,13 @@ pub fn main() -> Result<(), Box> { if terminate.load(Ordering::Relaxed) { break; } - let r_buff = r.slice().unwrap(); + let r_buff = match r.slice() { + Some(b) => b, + None => { + std::thread::sleep(std::time::Duration::from_millis(10)); + continue; + } + }; let l = r_buff.len(); println!("received {l} samples"); r.consume(l); diff --git a/src/impls/bladerf1.rs b/src/impls/bladerf1.rs index 0963644..94cbd73 100644 --- a/src/impls/bladerf1.rs +++ b/src/impls/bladerf1.rs @@ -1,11 +1,13 @@ use crate::{Args, Direction, Error, Range, RangeItem}; -use libbladerf_rs::bladerf1::board::stream::SampleFormat; +use libbladerf_rs::bladerf1::hardware::lms6002d::dc_calibration::DcCalModule; use libbladerf_rs::bladerf1::hardware::lms6002d::gain::GainStage; use libbladerf_rs::bladerf1::{ - BladeRf1, ExpansionBoard, GainDb, GainMode, RxStream, TuningMode, TxStream, + BladeRf1, ExpansionBoard, GainDb, GainMode, RfLinkSession, RxStream, SampleFormat, TuningMode, + TxStream, }; use libbladerf_rs::channel::Channel; use libbladerf_rs::range::{Range as BladeRfRange, RangeItem as BladeRfRangeItem}; +use libbladerf_rs::Buffer; use num_complex::Complex32; #[cfg(target_os = "linux")] use std::os::fd::{FromRawFd, OwnedFd}; @@ -13,57 +15,76 @@ use std::sync::{Arc, Mutex}; use std::thread::sleep; use std::time::Duration; -fn convert_bytes_to_complex32(format: SampleFormat, src: &[u8], dst: &mut [Complex32]) -> usize { - match format { - SampleFormat::Sc16Q11 => { - let len = src.len() / 4; - let len = len.min(dst.len()); - for (chunk, out) in src.chunks_exact(4).take(len).zip(dst.iter_mut()) { - let i_val = i16::from_le_bytes([chunk[0], chunk[1]]) as f32 / 2048.0; - let q_val = i16::from_le_bytes([chunk[2], chunk[3]]) as f32 / 2048.0; - *out = Complex32::new(i_val, q_val); - } - len - } - SampleFormat::Sc8Q7 => { - let len = src.len() / 2; - let len = len.min(dst.len()); - for (chunk, out) in src.chunks_exact(2).take(len).zip(dst.iter_mut()) { - let i_val = (chunk[0] as i8) as f32 / 128.0; - let q_val = (chunk[1] as i8) as f32 / 128.0; - *out = Complex32::new(i_val, q_val); - } - len - } - SampleFormat::Sc16Q11Packed => { - let groups = src.len() / 6; - let len = (groups * 2).min(dst.len()); - for (group_idx, chunk) in src.chunks_exact(6).enumerate() { - let out_idx = group_idx * 2; - if out_idx + 1 >= len { - break; - } - let w0 = u16::from_le_bytes([chunk[0], chunk[1]]); - let w1 = u16::from_le_bytes([chunk[2], chunk[3]]); - let w2 = u16::from_le_bytes([chunk[4], chunk[5]]); - let i0 = (((w0 & 0x0FFF) as i16) << 4) >> 4; - let q0 = ((((w1 & 0x00FF) as i16) << 8) >> 4) | (((w0 & 0xF000) as i16) >> 12); - dst[out_idx] = Complex32::new(i0 as f32 / 2048.0, q0 as f32 / 2048.0); - let i1 = ((((w2 & 0x000F) as i16) << 12) >> 4) | (((w1 & 0xFF00) as i16) >> 8); - let q1 = ((w2 & 0xFFF0) as i16) >> 4; - dst[out_idx + 1] = Complex32::new(i1 as f32 / 2048.0, q1 as f32 / 2048.0); - } - len - } - _ => unimplemented!("unsupported sample format: {format:?}"), +const BUFFER_SIZE: usize = 65536; +const BUFFER_COUNT: usize = 8; +const INV_2048: f32 = 1.0 / 2048.0; +const INV_128: f32 = 1.0 / 128.0; + +fn ch(channel: usize) -> Result { + Channel::try_from(channel as u8).map_err(|_| Error::ValueError) +} + +fn bladerf_err(e: libbladerf_rs::Error) -> Error { + match e { + libbladerf_rs::Error::NotFound => Error::NotFound, + libbladerf_rs::Error::Timeout => Error::DeviceError, + libbladerf_rs::Error::Io(io) => Error::Io(io), + libbladerf_rs::Error::Argument(_) => Error::ValueError, + libbladerf_rs::Error::Unsupported(_) => Error::NotSupported, + libbladerf_rs::Error::StreamClosed => Error::DeviceError, + e => Error::Misc(e.to_string()), } } -fn convert_complex32_to_bytes(format: SampleFormat, src: &[Complex32], dst: &mut [u8]) -> usize { +fn convert_sc16q11_to_complex32(src: &[u8], dst: &mut [Complex32]) -> usize { + let len = (src.len() / 4).min(dst.len()); + for (chunk, out) in src.chunks_exact(4).take(len).zip(dst.iter_mut()) { + let i_val = i16::from_le_bytes([chunk[0], chunk[1]]) as f32 * INV_2048; + let q_val = i16::from_le_bytes([chunk[2], chunk[3]]) as f32 * INV_2048; + *out = Complex32::new(i_val, q_val); + } + len +} + +fn convert_sc8q7_to_complex32(src: &[u8], dst: &mut [Complex32]) -> usize { + let len = (src.len() / 2).min(dst.len()); + for (chunk, out) in src.chunks_exact(2).take(len).zip(dst.iter_mut()) { + let i_val = (chunk[0] as i8) as f32 * INV_128; + let q_val = (chunk[1] as i8) as f32 * INV_128; + *out = Complex32::new(i_val, q_val); + } + len +} + +fn convert_sc16q11_packed_to_complex32(src: &[u8], dst: &mut [Complex32]) -> usize { + let groups = src.len() / 6; + let num_samples = (groups * 2).min(dst.len()); + for i in 0..num_samples / 2 { + let si = 6 * i; + let w0 = u16::from_le_bytes([src[si], src[si + 1]]); + let w1 = u16::from_le_bytes([src[si + 2], src[si + 3]]); + let w2 = u16::from_le_bytes([src[si + 4], src[si + 5]]); + let i0 = sign_extend_12(w0 & 0x0FFF) * INV_2048; + let q0 = sign_extend_12((w0 >> 12) | ((w1 & 0x00FF) << 4)) * INV_2048; + let i1 = sign_extend_12((w1 >> 8) | ((w2 & 0x000F) << 8)) * INV_2048; + let q1 = sign_extend_12(w2 >> 4) * INV_2048; + dst[i * 2] = Complex32::new(i0, q0); + dst[i * 2 + 1] = Complex32::new(i1, q1); + } + num_samples +} + +#[inline(always)] +const fn sign_extend_12(val: u16) -> f32 { + ((val << 4) as i16 >> 4) as f32 +} + +fn convert_bytes_to_complex32(format: SampleFormat, src: &[u8], dst: &mut [Complex32]) -> usize { match format { - SampleFormat::Sc16Q11 => convert_complex32_to_sc16q11(src, dst), - SampleFormat::Sc8Q7 => convert_complex32_to_sc8q7(src, dst), - _ => unimplemented!("unsupported TX sample format: {format:?}"), + SampleFormat::Sc16Q11 => convert_sc16q11_to_complex32(src, dst), + SampleFormat::Sc8Q7 => convert_sc8q7_to_complex32(src, dst), + SampleFormat::Sc16Q11Packed => convert_sc16q11_packed_to_complex32(src, dst), + _ => unimplemented!("unsupported sample format: {format:?}"), } } @@ -89,6 +110,14 @@ fn convert_complex32_to_sc8q7(src: &[Complex32], dst: &mut [u8]) -> usize { len } +fn convert_complex32_to_bytes(format: SampleFormat, src: &[Complex32], dst: &mut [u8]) -> usize { + match format { + SampleFormat::Sc16Q11 => convert_complex32_to_sc16q11(src, dst), + SampleFormat::Sc8Q7 => convert_complex32_to_sc8q7(src, dst), + _ => unimplemented!("unsupported TX sample format: {format:?}"), + } +} + impl From for RangeItem { fn from(val: BladeRfRangeItem) -> Self { match val { @@ -101,23 +130,7 @@ impl From for RangeItem { impl From for Range { fn from(val: BladeRfRange) -> Self { - Range { - items: val.items.into_iter().map(Into::into).collect(), - } - } -} - -fn ch(channel: usize) -> Channel { - Channel::try_from(channel as u8).unwrap() -} - -fn bladerf_err(e: libbladerf_rs::Error) -> Error { - match e { - libbladerf_rs::Error::NotFound => Error::NotFound, - libbladerf_rs::Error::Timeout => Error::DeviceError, - libbladerf_rs::Error::Io(io) => Error::Io(io), - libbladerf_rs::Error::Argument(_) => Error::ValueError, - e => Error::Misc(e.to_string()), + Range::new(val.iter().cloned().map(Into::into).collect()) } } @@ -127,7 +140,8 @@ pub struct BladeRf { impl BladeRf { fn init_and_wrap(mut bladerf: BladeRf1) -> Result { - bladerf.initialize(false).map_err(bladerf_err)?; + let mut session = bladerf.rf_link_session().map_err(bladerf_err)?; + session.initialize(false).map_err(bladerf_err)?; Ok(Self { inner: Arc::new(Mutex::new(bladerf)), }) @@ -163,7 +177,7 @@ impl BladeRf { } let bus_id: Result = args.get("bus_id"); - let address = args.get("address"); + let address: Result = args.get("address"); match (bus_id, address) { (Ok(bus_id), Ok(address)) => { let bladerf = @@ -185,89 +199,153 @@ impl BladeRf { } pub fn enable_expansion_board(&mut self, board_type: ExpansionBoard) -> Result<(), Error> { - self.inner - .lock() - .unwrap() - .expansion_attach(board_type) - .map_err(bladerf_err) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + session.expansion_attach(board_type).map_err(bladerf_err) + } + + pub fn calibrate_dc(&mut self, module: DcCalModule) -> Result<(), Error> { + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + session.calibrate_dc(module).map_err(bladerf_err) } } pub struct RxStreamer { - streamer: RxStream, + streamer: Option, dev: Arc>, format: SampleFormat, - buffer_size: usize, - active: bool, + pending: Option<(Buffer, usize)>, } pub struct TxStreamer { - streamer: TxStream, + streamer: Option, dev: Arc>, format: SampleFormat, - buffer_size: usize, - active: bool, } -macro_rules! impl_streamer_common { - () => { - fn mtu(&self) -> Result { - Ok(self.buffer_size) - } +impl crate::RxStreamer for RxStreamer { + fn mtu(&self) -> Result { + self.streamer + .as_ref() + .ok_or(Error::Inactive)? + .buffer_size() + .map_err(bladerf_err) + } - fn activate_at(&mut self, time_ns: Option) -> Result<(), Error> { - if let Some(t) = time_ns { - sleep(Duration::from_nanos(t as u64)); - } - self.active = true; - Ok(()) + fn activate_at(&mut self, time_ns: Option) -> Result<(), Error> { + if let Some(t) = time_ns { + sleep(Duration::from_nanos(t as u64)); } + let mut dev = self.dev.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + self.streamer + .as_mut() + .ok_or(Error::Inactive)? + .start(&mut session) + .map_err(bladerf_err) + } - fn deactivate_at(&mut self, time_ns: Option) -> Result<(), Error> { - if let Some(t) = time_ns { - sleep(Duration::from_nanos(t as u64)); - } - if self.active { - self.streamer - .close(&mut *self.dev.lock().unwrap()) - .map_err(bladerf_err)?; - self.active = false; - } - Ok(()) + fn deactivate_at(&mut self, time_ns: Option) -> Result<(), Error> { + if let Some(t) = time_ns { + sleep(Duration::from_nanos(t as u64)); } - }; -} - -impl crate::RxStreamer for RxStreamer { - impl_streamer_common!(); + if let Some(streamer) = self.streamer.as_mut() { + let mut dev = self.dev.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + streamer.stop(&mut session).map_err(bladerf_err)?; + } + Ok(()) + } fn read(&mut self, buffers: &mut [&mut [Complex32]], timeout_us: i64) -> Result { debug_assert_eq!(buffers.len(), 1); - + let streamer = self.streamer.as_mut().ok_or(Error::Inactive)?; let bytes_per_sample = self.format.sample_size(); + let output = &mut buffers[0]; + let mut written = 0; + + if let Some((buf, mut offset)) = self.pending.take() { + let samples_available = (buf.len() - offset) / bytes_per_sample; + let samples_to_produce = output.len().min(samples_available); + convert_bytes_to_complex32( + self.format, + &buf[offset..offset + samples_to_produce * bytes_per_sample], + &mut output[..samples_to_produce], + ); + offset += samples_to_produce * bytes_per_sample; + written += samples_to_produce; + if offset < buf.len() { + self.pending = Some((buf, offset)); + } else { + streamer.recycle(buf); + } + } - let dma_buffer = self - .streamer + if written >= output.len() { + return Ok(written); + } + + let remaining = &mut output[written..]; + + let dma_buffer = streamer .read(Some(Duration::from_micros(timeout_us as u64))) .map_err(bladerf_err)?; let samples_available = dma_buffer.len() / bytes_per_sample; - let samples_to_produce = buffers[0].len().min(samples_available); + let samples_to_produce = remaining.len().min(samples_available); convert_bytes_to_complex32( self.format, &dma_buffer[..samples_to_produce * bytes_per_sample], - &mut buffers[0][..samples_to_produce], + &mut remaining[..samples_to_produce], ); - self.streamer.recycle(dma_buffer); + if samples_available > samples_to_produce { + let offset = samples_to_produce * bytes_per_sample; + self.pending = Some((dma_buffer, offset)); + } else { + streamer.recycle(dma_buffer); + } - Ok(samples_to_produce) + written += samples_to_produce; + Ok(written) } } impl crate::TxStreamer for TxStreamer { - impl_streamer_common!(); + fn mtu(&self) -> Result { + self.streamer + .as_ref() + .ok_or(Error::Inactive)? + .buffer_size() + .map_err(bladerf_err) + } + + fn activate_at(&mut self, time_ns: Option) -> Result<(), Error> { + if let Some(t) = time_ns { + sleep(Duration::from_nanos(t as u64)); + } + let mut dev = self.dev.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + self.streamer + .as_mut() + .ok_or(Error::Inactive)? + .start(&mut session) + .map_err(bladerf_err) + } + + fn deactivate_at(&mut self, time_ns: Option) -> Result<(), Error> { + if let Some(t) = time_ns { + sleep(Duration::from_nanos(t as u64)); + } + if let Some(streamer) = self.streamer.as_mut() { + let mut dev = self.dev.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + streamer.stop(&mut session).map_err(bladerf_err)?; + } + Ok(()) + } fn write( &mut self, @@ -277,13 +355,14 @@ impl crate::TxStreamer for TxStreamer { timeout_us: i64, ) -> Result { debug_assert_eq!(buffers.len(), 1); - + let streamer = self.streamer.as_mut().ok_or(Error::Inactive)?; + let buffer_size = streamer.buffer_size().map_err(bladerf_err)?; let bytes_per_sample = self.format.sample_size(); - let samples_to_write = buffers[0].len(); + let max_samples = buffer_size / bytes_per_sample; + let samples_to_write = buffers[0].len().min(max_samples); let bytes_needed = samples_to_write * bytes_per_sample; - let mut dma_buffer = self - .streamer + let mut dma_buffer = streamer .get_buffer(Some(Duration::from_micros(timeout_us as u64))) .map_err(bladerf_err)?; @@ -293,12 +372,9 @@ impl crate::TxStreamer for TxStreamer { &mut dma_buffer[..bytes_needed], ); - self.streamer + streamer .submit(dma_buffer, bytes_needed) .map_err(bladerf_err)?; - self.streamer - .wait_completion(Some(Duration::from_micros(timeout_us as u64))) - .map_err(bladerf_err)?; Ok(samples_to_write) } @@ -325,45 +401,6 @@ impl crate::TxStreamer for TxStreamer { } } -const BUFFER_SIZE: usize = 65536; -const BUFFER_COUNT: usize = 8; - -impl BladeRf { - fn create_rx_streamer(&self, format: SampleFormat) -> RxStreamer { - let mut dev = self.inner.lock().unwrap(); - let streamer = RxStream::builder(&mut *dev) - .buffer_size(BUFFER_SIZE) - .buffer_count(BUFFER_COUNT) - .format(format) - .build() - .expect("Failed to create RX streamer"); - RxStreamer { - streamer, - dev: self.inner.clone(), - format, - buffer_size: BUFFER_SIZE, - active: true, - } - } - - fn create_tx_streamer(&self, format: SampleFormat) -> TxStreamer { - let mut dev = self.inner.lock().unwrap(); - let streamer = TxStream::builder(&mut *dev) - .buffer_size(BUFFER_SIZE) - .buffer_count(BUFFER_COUNT) - .format(format) - .build() - .expect("Failed to create TX streamer"); - TxStreamer { - streamer, - dev: self.inner.clone(), - format, - buffer_size: BUFFER_SIZE, - active: true, - } - } -} - impl crate::DeviceTrait for BladeRf { type RxStreamer = RxStreamer; type TxStreamer = TxStreamer; @@ -410,7 +447,20 @@ impl crate::DeviceTrait for BladeRf { log::error!("BladeRF1 only supports one RX channel!"); return Err(Error::ValueError); } - Ok(self.create_rx_streamer(SampleFormat::Sc16Q11)) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + let streamer = RxStream::builder(&mut session) + .buffer_size(BUFFER_SIZE) + .buffer_count(BUFFER_COUNT) + .format(SampleFormat::Sc16Q11) + .build() + .map_err(bladerf_err)?; + Ok(RxStreamer { + streamer: Some(streamer), + dev: Arc::clone(&self.inner), + format: SampleFormat::Sc16Q11, + pending: None, + }) } fn tx_streamer(&self, channels: &[usize], _args: Args) -> Result { @@ -418,7 +468,19 @@ impl crate::DeviceTrait for BladeRf { log::error!("BladeRF1 only supports one TX channel!"); return Err(Error::ValueError); } - Ok(self.create_tx_streamer(SampleFormat::Sc16Q11)) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + let streamer = TxStream::builder(&mut session) + .buffer_size(BUFFER_SIZE) + .buffer_count(BUFFER_COUNT) + .format(SampleFormat::Sc16Q11) + .build() + .map_err(bladerf_err)?; + Ok(TxStreamer { + streamer: Some(streamer), + dev: Arc::clone(&self.inner), + format: SampleFormat::Sc16Q11, + }) } fn antennas(&self, _direction: Direction, _channel: usize) -> Result, Error> { @@ -439,12 +501,9 @@ impl crate::DeviceTrait for BladeRf { } fn supports_agc(&self, _direction: Direction, channel: usize) -> Result { - Ok(self - .inner - .lock() - .unwrap() - .get_gain_modes(ch(channel)) - .is_ok()) + let mut dev = self.inner.lock().unwrap(); + let session = dev.rf_link_session().map_err(bladerf_err)?; + Ok(session.get_gain_modes(ch(channel)?).is_ok()) } fn enable_agc(&self, _direction: Direction, channel: usize, agc: bool) -> Result<(), Error> { @@ -453,45 +512,48 @@ impl crate::DeviceTrait for BladeRf { } else { GainMode::Mgc }; - self.inner - .lock() - .unwrap() - .set_gain_mode(ch(channel), mode) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + session + .set_gain_mode(ch(channel)?, mode) .map_err(bladerf_err) } fn agc(&self, _direction: Direction, _channel: usize) -> Result { - Ok(self.inner.lock().unwrap().get_gain_mode().is_ok()) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + Ok(session.get_gain_mode().is_ok()) } fn gain_elements(&self, _direction: Direction, channel: usize) -> Result, Error> { - Ok(BladeRf1::get_gain_stages(ch(channel)) + Ok(RfLinkSession::get_gain_stages(ch(channel)?) .iter() .map(|s| <&str>::from(*s).to_string()) .collect()) } fn set_gain(&self, _direction: Direction, channel: usize, gain: f64) -> Result<(), Error> { - self.inner - .lock() - .unwrap() - .set_gain(ch(channel), GainDb::from(gain as i8)) + let range = RfLinkSession::get_gain_range(ch(channel)?); + let min = range.min().unwrap_or(f64::MIN); + let max = range.max().unwrap_or(f64::MAX); + let clamped = gain.clamp(min, max); + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + session + .set_gain(ch(channel)?, GainDb::from(clamped as i8)) .map_err(bladerf_err) } fn gain(&self, _direction: Direction, channel: usize) -> Result, Error> { + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; Ok(Some( - self.inner - .lock() - .unwrap() - .get_gain(ch(channel)) - .map_err(bladerf_err)? - .db as f64, + session.get_gain(ch(channel)?).map_err(bladerf_err)?.db() as f64, )) } fn gain_range(&self, _direction: Direction, channel: usize) -> Result { - Ok(BladeRf1::get_gain_range(ch(channel)).into()) + Ok(RfLinkSession::get_gain_range(ch(channel)?).into()) } fn set_gain_element( @@ -502,10 +564,14 @@ impl crate::DeviceTrait for BladeRf { gain: f64, ) -> Result<(), Error> { let stage = GainStage::try_from(name).map_err(|_| Error::ValueError)?; - self.inner - .lock() - .unwrap() - .set_gain_stage(stage, GainDb::from(gain as i8)) + let range = RfLinkSession::get_gain_stage_range(stage); + let min = range.min().unwrap_or(f64::MIN); + let max = range.max().unwrap_or(f64::MAX); + let clamped = gain.clamp(min, max); + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + session + .set_gain_stage(stage, GainDb::from(clamped as i8)) .map_err(bladerf_err) } @@ -516,13 +582,10 @@ impl crate::DeviceTrait for BladeRf { name: &str, ) -> Result, Error> { let stage = GainStage::try_from(name).map_err(|_| Error::ValueError)?; + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; Ok(Some( - self.inner - .lock() - .unwrap() - .get_gain_stage(stage) - .map_err(bladerf_err)? - .db as f64, + session.get_gain_stage(stage).map_err(bladerf_err)?.db() as f64, )) } @@ -533,26 +596,19 @@ impl crate::DeviceTrait for BladeRf { name: &str, ) -> Result { let stage = GainStage::try_from(name).map_err(|_| Error::ValueError)?; - Ok(BladeRf1::get_gain_stage_range(stage).into()) + Ok(RfLinkSession::get_gain_stage_range(stage).into()) } fn frequency_range(&self, _direction: Direction, _channel: usize) -> Result { - Ok(self - .inner - .lock() - .unwrap() - .get_frequency_range() - .map_err(bladerf_err)? - .into()) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + Ok(session.get_frequency_range().map_err(bladerf_err)?.into()) } fn frequency(&self, _direction: Direction, channel: usize) -> Result { - Ok(self - .inner - .lock() - .unwrap() - .get_frequency(ch(channel)) - .map_err(bladerf_err)? as f64) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + Ok(session.get_frequency(ch(channel)?).map_err(bladerf_err)? as f64) } fn set_frequency( @@ -563,18 +619,29 @@ impl crate::DeviceTrait for BladeRf { _args: Args, ) -> Result<(), Error> { let mut dev = self.inner.lock().unwrap(); - let f_range = dev.get_frequency_range().map_err(bladerf_err)?; + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + let f_range = session.get_frequency_range().map_err(bladerf_err)?; if frequency < f_range.min().unwrap() { log::trace!("Frequency {frequency} requires XB200 expansion board"); - if dev.expansion_get_attached().map_err(bladerf_err)? != ExpansionBoard::Xb200 { + if session.expansion_get_attached().map_err(bladerf_err)? != ExpansionBoard::Xb200 { log::debug!("Automatically attaching XB200 expansion board"); - dev.expansion_attach(ExpansionBoard::Xb200) + session + .expansion_attach(ExpansionBoard::Xb200) .map_err(bladerf_err)?; } } log::trace!("Setting frequency to {frequency}"); - dev.set_frequency(ch(channel), frequency as u64, TuningMode::Fpga) - .map_err(bladerf_err) + let ch = ch(channel)?; + if session + .set_frequency(ch, frequency as u64, TuningMode::Fpga) + .is_err() + { + log::warn!("FPGA retune failed, falling back to host tuning"); + session + .set_frequency(ch, frequency as u64, TuningMode::Host) + .map_err(bladerf_err)?; + } + Ok(()) } fn frequency_components( @@ -614,12 +681,9 @@ impl crate::DeviceTrait for BladeRf { } fn sample_rate(&self, _direction: Direction, channel: usize) -> Result { - Ok(self - .inner - .lock() - .unwrap() - .get_sample_rate(ch(channel)) - .map_err(bladerf_err)? as f64) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + Ok(session.get_sample_rate(ch(channel)?).map_err(bladerf_err)? as f64) } fn set_sample_rate( @@ -628,15 +692,20 @@ impl crate::DeviceTrait for BladeRf { channel: usize, rate: f64, ) -> Result<(), Error> { - let actual = self - .inner - .lock() - .unwrap() - .set_sample_rate(ch(channel), rate as u32) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + let ch = ch(channel)?; + let actual = session + .set_sample_rate(ch, rate as u32) .map_err(bladerf_err)?; if actual != rate as u32 { log::debug!("Requested sample rate {rate}, actual {actual}"); } + let bw_actual = session.set_bandwidth(ch, actual).map_err(bladerf_err)?; + if bw_actual != actual { + log::debug!("Auto-set bandwidth to {bw_actual} (requested {actual})"); + } + drop(dev); Ok(()) } @@ -645,24 +714,20 @@ impl crate::DeviceTrait for BladeRf { _direction: Direction, _channel: usize, ) -> Result { - Ok(BladeRf1::get_sample_rate_range().into()) + Ok(RfLinkSession::get_sample_rate_range().into()) } fn bandwidth(&self, _direction: Direction, channel: usize) -> Result { - Ok(self - .inner - .lock() - .unwrap() - .get_bandwidth(ch(channel)) - .map_err(bladerf_err)? as f64) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + Ok(session.get_bandwidth(ch(channel)?).map_err(bladerf_err)? as f64) } fn set_bandwidth(&self, _direction: Direction, channel: usize, bw: f64) -> Result<(), Error> { - let actual = self - .inner - .lock() - .unwrap() - .set_bandwidth(ch(channel), bw as u32) + let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; + let actual = session + .set_bandwidth(ch(channel)?, bw as u32) .map_err(bladerf_err)?; if actual != bw as u32 { log::debug!("Requested bandwidth {bw}, actual {actual}"); @@ -671,7 +736,7 @@ impl crate::DeviceTrait for BladeRf { } fn get_bandwidth_range(&self, _direction: Direction, _channel: usize) -> Result { - Ok(BladeRf1::get_bandwidth_range().into()) + Ok(RfLinkSession::get_bandwidth_range().into()) } fn has_dc_offset_mode(&self, _direction: Direction, _channel: usize) -> Result {