From f943b269c50dacd25bc0d8644030da0b86ac9143 Mon Sep 17 00:00:00 2001 From: ratzrattillo <11601995+ratzrattillo@users.noreply.github.com> Date: Sat, 9 May 2026 13:29:39 +0200 Subject: [PATCH 1/6] backup after refactoring --- Cargo.toml | 5 ++--- src/impls/bladerf1.rs | 10 ++-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16260d3..3eded7c 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,11 @@ 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 = { 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/src/impls/bladerf1.rs b/src/impls/bladerf1.rs index 0963644..c3da6fc 100644 --- a/src/impls/bladerf1.rs +++ b/src/impls/bladerf1.rs @@ -163,7 +163,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 = @@ -195,7 +195,6 @@ impl BladeRf { pub struct RxStreamer { streamer: RxStream, - dev: Arc>, format: SampleFormat, buffer_size: usize, active: bool, @@ -203,7 +202,6 @@ pub struct RxStreamer { pub struct TxStreamer { streamer: TxStream, - dev: Arc>, format: SampleFormat, buffer_size: usize, active: bool, @@ -228,9 +226,7 @@ macro_rules! impl_streamer_common { sleep(Duration::from_nanos(t as u64)); } if self.active { - self.streamer - .close(&mut *self.dev.lock().unwrap()) - .map_err(bladerf_err)?; + self.streamer.close().map_err(bladerf_err)?; self.active = false; } Ok(()) @@ -339,7 +335,6 @@ impl BladeRf { .expect("Failed to create RX streamer"); RxStreamer { streamer, - dev: self.inner.clone(), format, buffer_size: BUFFER_SIZE, active: true, @@ -356,7 +351,6 @@ impl BladeRf { .expect("Failed to create TX streamer"); TxStreamer { streamer, - dev: self.inner.clone(), format, buffer_size: BUFFER_SIZE, active: true, From 0005b98803a244d51fb231d7e66223b591bed511 Mon Sep 17 00:00:00 2001 From: ratzrattillo <11601995+ratzrattillo@users.noreply.github.com> Date: Sun, 10 May 2026 23:40:23 +0200 Subject: [PATCH 2/6] fix pending samples bug --- src/impls/bladerf1.rs | 81 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/src/impls/bladerf1.rs b/src/impls/bladerf1.rs index c3da6fc..b426be7 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, }; 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}; @@ -191,6 +193,14 @@ impl BladeRf { .expansion_attach(board_type) .map_err(bladerf_err) } + + pub fn calibrate_dc(&mut self, module: DcCalModule) -> Result<(), Error> { + self.inner + .lock() + .unwrap() + .calibrate_dc(module) + .map_err(bladerf_err) + } } pub struct RxStreamer { @@ -198,6 +208,7 @@ pub struct RxStreamer { format: SampleFormat, buffer_size: usize, active: bool, + pending: Option<(Buffer, usize)>, } pub struct TxStreamer { @@ -241,6 +252,31 @@ impl crate::RxStreamer for RxStreamer { debug_assert_eq!(buffers.len(), 1); 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 { + self.streamer.recycle(buf); + } + } + + if written >= output.len() { + return Ok(written); + } + + let remaining = &mut output[written..]; let dma_buffer = self .streamer @@ -248,17 +284,23 @@ impl crate::RxStreamer for RxStreamer { .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 { + self.streamer.recycle(dma_buffer); + } - Ok(samples_to_produce) + written += samples_to_produce; + Ok(written) } } @@ -275,7 +317,8 @@ impl crate::TxStreamer for TxStreamer { debug_assert_eq!(buffers.len(), 1); let bytes_per_sample = self.format.sample_size(); - let samples_to_write = buffers[0].len(); + let max_samples = self.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 @@ -292,9 +335,6 @@ impl crate::TxStreamer for TxStreamer { self.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) } @@ -338,6 +378,7 @@ impl BladeRf { format, buffer_size: BUFFER_SIZE, active: true, + pending: None, } } @@ -567,8 +608,15 @@ impl crate::DeviceTrait for BladeRf { } } log::trace!("Setting frequency to {frequency}"); - dev.set_frequency(ch(channel), frequency as u64, TuningMode::Fpga) - .map_err(bladerf_err) + if dev + .set_frequency(ch(channel), frequency as u64, TuningMode::Fpga) + .is_err() + { + log::warn!("FPGA retune failed, falling back to host tuning"); + dev.set_frequency(ch(channel), frequency as u64, TuningMode::Host) + .map_err(bladerf_err)?; + } + Ok(()) } fn frequency_components( @@ -622,15 +670,20 @@ impl crate::DeviceTrait for BladeRf { channel: usize, rate: f64, ) -> Result<(), Error> { - let actual = self - .inner - .lock() - .unwrap() + let mut dev = self.inner.lock().unwrap(); + let actual = dev .set_sample_rate(ch(channel), rate as u32) .map_err(bladerf_err)?; if actual != rate as u32 { log::debug!("Requested sample rate {rate}, actual {actual}"); } + let bw_actual = dev + .set_bandwidth(ch(channel), actual) + .map_err(bladerf_err)?; + if bw_actual != actual { + log::debug!("Auto-set bandwidth to {bw_actual} (requested {actual})"); + } + drop(dev); Ok(()) } From 5afdc9953ee605df963a0d9008e377ae802ad945 Mon Sep 17 00:00:00 2001 From: ratzrattillo <11601995+ratzrattillo@users.noreply.github.com> Date: Wed, 13 May 2026 17:26:52 +0200 Subject: [PATCH 3/6] adjust to libbladerf-rs api changes --- src/impls/bladerf1.rs | 343 ++++++++++++++++++++++-------------------- 1 file changed, 181 insertions(+), 162 deletions(-) diff --git a/src/impls/bladerf1.rs b/src/impls/bladerf1.rs index b426be7..09f169d 100644 --- a/src/impls/bladerf1.rs +++ b/src/impls/bladerf1.rs @@ -15,57 +15,69 @@ 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; + +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 / 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 +} + +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 / 128.0; + let q_val = (chunk[1] as i8) as f32 / 128.0; + *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()); + let bytes_needed = num_samples * 4; + let dst_bytes = + unsafe { std::slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u8, bytes_needed) }; + SampleFormat::unpack_sc16q11_packed(src, dst_bytes, num_samples).unwrap(); + for i in (0..num_samples).rev() { + let byte_off = i * 4; + let i_val = + i16::from_le_bytes([dst_bytes[byte_off], dst_bytes[byte_off + 1]]) as f32 / 2048.0; + let q_val = + i16::from_le_bytes([dst_bytes[byte_off + 2], dst_bytes[byte_off + 3]]) as f32 / 2048.0; + dst[i] = Complex32::new(i_val, q_val); + } + num_samples +} + +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:?}"), } } @@ -91,6 +103,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 { @@ -109,20 +129,6 @@ impl From for Range { } } -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()), - } -} - pub struct BladeRf { inner: Arc>, } @@ -204,53 +210,57 @@ impl BladeRf { } 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 streamer = RxStream::builder(&mut *dev) + .buffer_size(BUFFER_SIZE) + .buffer_count(BUFFER_COUNT) + .format(self.format) + .build() + .map_err(bladerf_err)?; + self.streamer = Some(streamer); + Ok(()) + } - 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().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(mut streamer) = self.streamer.take() { + streamer + .close(&mut *self.dev.lock().unwrap()) + .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; @@ -268,7 +278,7 @@ impl crate::RxStreamer for RxStreamer { if offset < buf.len() { self.pending = Some((buf, offset)); } else { - self.streamer.recycle(buf); + streamer.recycle(buf); } } @@ -278,8 +288,7 @@ impl crate::RxStreamer for RxStreamer { let remaining = &mut output[written..]; - let dma_buffer = self - .streamer + let dma_buffer = streamer .read(Some(Duration::from_micros(timeout_us as u64))) .map_err(bladerf_err)?; @@ -296,7 +305,7 @@ impl crate::RxStreamer for RxStreamer { let offset = samples_to_produce * bytes_per_sample; self.pending = Some((dma_buffer, offset)); } else { - self.streamer.recycle(dma_buffer); + streamer.recycle(dma_buffer); } written += samples_to_produce; @@ -305,7 +314,40 @@ impl crate::RxStreamer for RxStreamer { } 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 streamer = TxStream::builder(&mut *dev) + .buffer_size(BUFFER_SIZE) + .buffer_count(BUFFER_COUNT) + .format(self.format) + .build() + .map_err(bladerf_err)?; + self.streamer = Some(streamer); + Ok(()) + } + + 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(mut streamer) = self.streamer.take() { + streamer + .close(&mut *self.dev.lock().unwrap()) + .map_err(bladerf_err)?; + } + Ok(()) + } fn write( &mut self, @@ -315,14 +357,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 max_samples = self.buffer_size / bytes_per_sample; + 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)?; @@ -332,7 +374,7 @@ impl crate::TxStreamer for TxStreamer { &mut dma_buffer[..bytes_needed], ); - self.streamer + streamer .submit(dma_buffer, bytes_needed) .map_err(bladerf_err)?; @@ -361,44 +403,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, - format, - buffer_size: BUFFER_SIZE, - active: true, - pending: None, - } - } - - 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, - format, - buffer_size: BUFFER_SIZE, - active: true, - } - } -} - impl crate::DeviceTrait for BladeRf { type RxStreamer = RxStreamer; type TxStreamer = TxStreamer; @@ -445,7 +449,12 @@ impl crate::DeviceTrait for BladeRf { log::error!("BladeRF1 only supports one RX channel!"); return Err(Error::ValueError); } - Ok(self.create_rx_streamer(SampleFormat::Sc16Q11)) + Ok(RxStreamer { + streamer: None, + dev: Arc::clone(&self.inner), + format: SampleFormat::Sc16Q11, + pending: None, + }) } fn tx_streamer(&self, channels: &[usize], _args: Args) -> Result { @@ -453,7 +462,11 @@ impl crate::DeviceTrait for BladeRf { log::error!("BladeRF1 only supports one TX channel!"); return Err(Error::ValueError); } - Ok(self.create_tx_streamer(SampleFormat::Sc16Q11)) + Ok(TxStreamer { + streamer: None, + dev: Arc::clone(&self.inner), + format: SampleFormat::Sc16Q11, + }) } fn antennas(&self, _direction: Direction, _channel: usize) -> Result, Error> { @@ -478,7 +491,7 @@ impl crate::DeviceTrait for BladeRf { .inner .lock() .unwrap() - .get_gain_modes(ch(channel)) + .get_gain_modes(ch(channel)?) .is_ok()) } @@ -491,7 +504,7 @@ impl crate::DeviceTrait for BladeRf { self.inner .lock() .unwrap() - .set_gain_mode(ch(channel), mode) + .set_gain_mode(ch(channel)?, mode) .map_err(bladerf_err) } @@ -500,17 +513,21 @@ impl crate::DeviceTrait for BladeRf { } fn gain_elements(&self, _direction: Direction, channel: usize) -> Result, Error> { - Ok(BladeRf1::get_gain_stages(ch(channel)) + Ok(BladeRf1::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> { + let range = BladeRf1::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); self.inner .lock() .unwrap() - .set_gain(ch(channel), GainDb::from(gain as i8)) + .set_gain(ch(channel)?, GainDb::from(clamped as i8)) .map_err(bladerf_err) } @@ -519,14 +536,14 @@ impl crate::DeviceTrait for BladeRf { self.inner .lock() .unwrap() - .get_gain(ch(channel)) + .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(BladeRf1::get_gain_range(ch(channel)?).into()) } fn set_gain_element( @@ -537,10 +554,14 @@ impl crate::DeviceTrait for BladeRf { gain: f64, ) -> Result<(), Error> { let stage = GainStage::try_from(name).map_err(|_| Error::ValueError)?; + let range = BladeRf1::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); self.inner .lock() .unwrap() - .set_gain_stage(stage, GainDb::from(gain as i8)) + .set_gain_stage(stage, GainDb::from(clamped as i8)) .map_err(bladerf_err) } @@ -586,7 +607,7 @@ impl crate::DeviceTrait for BladeRf { .inner .lock() .unwrap() - .get_frequency(ch(channel)) + .get_frequency(ch(channel)?) .map_err(bladerf_err)? as f64) } @@ -608,12 +629,13 @@ impl crate::DeviceTrait for BladeRf { } } log::trace!("Setting frequency to {frequency}"); + let ch = ch(channel)?; if dev - .set_frequency(ch(channel), frequency as u64, TuningMode::Fpga) + .set_frequency(ch, frequency as u64, TuningMode::Fpga) .is_err() { log::warn!("FPGA retune failed, falling back to host tuning"); - dev.set_frequency(ch(channel), frequency as u64, TuningMode::Host) + dev.set_frequency(ch, frequency as u64, TuningMode::Host) .map_err(bladerf_err)?; } Ok(()) @@ -660,7 +682,7 @@ impl crate::DeviceTrait for BladeRf { .inner .lock() .unwrap() - .get_sample_rate(ch(channel)) + .get_sample_rate(ch(channel)?) .map_err(bladerf_err)? as f64) } @@ -671,15 +693,12 @@ impl crate::DeviceTrait for BladeRf { rate: f64, ) -> Result<(), Error> { let mut dev = self.inner.lock().unwrap(); - let actual = dev - .set_sample_rate(ch(channel), rate as u32) - .map_err(bladerf_err)?; + let ch = ch(channel)?; + let actual = dev.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 = dev - .set_bandwidth(ch(channel), actual) - .map_err(bladerf_err)?; + let bw_actual = dev.set_bandwidth(ch, actual).map_err(bladerf_err)?; if bw_actual != actual { log::debug!("Auto-set bandwidth to {bw_actual} (requested {actual})"); } @@ -700,7 +719,7 @@ impl crate::DeviceTrait for BladeRf { .inner .lock() .unwrap() - .get_bandwidth(ch(channel)) + .get_bandwidth(ch(channel)?) .map_err(bladerf_err)? as f64) } @@ -709,7 +728,7 @@ impl crate::DeviceTrait for BladeRf { .inner .lock() .unwrap() - .set_bandwidth(ch(channel), bw as u32) + .set_bandwidth(ch(channel)?, bw as u32) .map_err(bladerf_err)?; if actual != bw as u32 { log::debug!("Requested bandwidth {bw}, actual {actual}"); From 445e7ef810f48b30f7e84cb0e60bf5173fcdd618 Mon Sep 17 00:00:00 2001 From: ratzrattillo <11601995+ratzrattillo@users.noreply.github.com> Date: Sat, 23 May 2026 02:35:43 +0200 Subject: [PATCH 4/6] update to lockfree libbladerf-rs API --- src/impls/bladerf1.rs | 50 ++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/impls/bladerf1.rs b/src/impls/bladerf1.rs index 09f169d..21ec051 100644 --- a/src/impls/bladerf1.rs +++ b/src/impls/bladerf1.rs @@ -1,9 +1,8 @@ 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, RxStream, SampleFormat, TuningMode, TxStream, }; use libbladerf_rs::channel::Channel; use libbladerf_rs::range::{Range as BladeRfRange, RangeItem as BladeRfRangeItem}; @@ -17,6 +16,8 @@ use std::time::Duration; 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) @@ -37,8 +38,8 @@ fn bladerf_err(e: libbladerf_rs::Error) -> Error { 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 / 2048.0; - let q_val = i16::from_le_bytes([chunk[2], chunk[3]]) as f32 / 2048.0; + 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 @@ -47,8 +48,8 @@ fn convert_sc16q11_to_complex32(src: &[u8], dst: &mut [Complex32]) -> usize { 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 / 128.0; - let q_val = (chunk[1] as i8) as f32 / 128.0; + 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 @@ -57,21 +58,26 @@ fn convert_sc8q7_to_complex32(src: &[u8], dst: &mut [Complex32]) -> usize { 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()); - let bytes_needed = num_samples * 4; - let dst_bytes = - unsafe { std::slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u8, bytes_needed) }; - SampleFormat::unpack_sc16q11_packed(src, dst_bytes, num_samples).unwrap(); - for i in (0..num_samples).rev() { - let byte_off = i * 4; - let i_val = - i16::from_le_bytes([dst_bytes[byte_off], dst_bytes[byte_off + 1]]) as f32 / 2048.0; - let q_val = - i16::from_le_bytes([dst_bytes[byte_off + 2], dst_bytes[byte_off + 3]]) as f32 / 2048.0; - dst[i] = Complex32::new(i_val, q_val); + 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_sc16q11_to_complex32(src, dst), @@ -236,7 +242,7 @@ impl crate::RxStreamer for RxStreamer { sleep(Duration::from_nanos(t as u64)); } let mut dev = self.dev.lock().unwrap(); - let streamer = RxStream::builder(&mut *dev) + let streamer = RxStream::builder(&mut dev) .buffer_size(BUFFER_SIZE) .buffer_count(BUFFER_COUNT) .format(self.format) @@ -252,8 +258,8 @@ impl crate::RxStreamer for RxStreamer { } if let Some(mut streamer) = self.streamer.take() { streamer - .close(&mut *self.dev.lock().unwrap()) - .map_err(bladerf_err)?; + .close(&mut self.dev.lock().unwrap()) + .map_err(bladerf_err)?; } Ok(()) } @@ -327,7 +333,7 @@ impl crate::TxStreamer for TxStreamer { sleep(Duration::from_nanos(t as u64)); } let mut dev = self.dev.lock().unwrap(); - let streamer = TxStream::builder(&mut *dev) + let streamer = TxStream::builder(&mut dev) .buffer_size(BUFFER_SIZE) .buffer_count(BUFFER_COUNT) .format(self.format) @@ -343,7 +349,7 @@ impl crate::TxStreamer for TxStreamer { } if let Some(mut streamer) = self.streamer.take() { streamer - .close(&mut *self.dev.lock().unwrap()) + .close(&mut self.dev.lock().unwrap()) .map_err(bladerf_err)?; } Ok(()) From aa15dd63e68b9e94c15c675a2835a992452ea01b Mon Sep 17 00:00:00 2001 From: ratzrattillo <11601995+ratzrattillo@users.noreply.github.com> Date: Tue, 26 May 2026 23:05:27 +0200 Subject: [PATCH 5/6] separation of streamer creation and stream start --- examples/rx_threaded.rs | 8 +- src/impls/bladerf1.rs | 213 ++++++++++++++++++++-------------------- 2 files changed, 111 insertions(+), 110 deletions(-) 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 21ec051..37d47b5 100644 --- a/src/impls/bladerf1.rs +++ b/src/impls/bladerf1.rs @@ -2,7 +2,8 @@ use crate::{Args, Direction, Error, Range, RangeItem}; 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, SampleFormat, 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}; @@ -141,7 +142,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)), }) @@ -199,19 +201,15 @@ 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> { - self.inner - .lock() - .unwrap() - .calibrate_dc(module) - .map_err(bladerf_err) + 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) } } @@ -242,24 +240,22 @@ impl crate::RxStreamer for RxStreamer { sleep(Duration::from_nanos(t as u64)); } let mut dev = self.dev.lock().unwrap(); - let streamer = RxStream::builder(&mut dev) - .buffer_size(BUFFER_SIZE) - .buffer_count(BUFFER_COUNT) - .format(self.format) - .build() - .map_err(bladerf_err)?; - self.streamer = Some(streamer); - Ok(()) + 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(mut streamer) = self.streamer.take() { - streamer - .close(&mut self.dev.lock().unwrap()) - .map_err(bladerf_err)?; + 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(()) } @@ -333,24 +329,22 @@ impl crate::TxStreamer for TxStreamer { sleep(Duration::from_nanos(t as u64)); } let mut dev = self.dev.lock().unwrap(); - let streamer = TxStream::builder(&mut dev) - .buffer_size(BUFFER_SIZE) - .buffer_count(BUFFER_COUNT) - .format(self.format) - .build() - .map_err(bladerf_err)?; - self.streamer = Some(streamer); - Ok(()) + 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(mut streamer) = self.streamer.take() { - streamer - .close(&mut self.dev.lock().unwrap()) - .map_err(bladerf_err)?; + 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(()) } @@ -455,8 +449,16 @@ impl crate::DeviceTrait for BladeRf { log::error!("BladeRF1 only supports one RX channel!"); return Err(Error::ValueError); } + 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: None, + streamer: Some(streamer), dev: Arc::clone(&self.inner), format: SampleFormat::Sc16Q11, pending: None, @@ -468,8 +470,16 @@ impl crate::DeviceTrait for BladeRf { log::error!("BladeRF1 only supports one TX channel!"); return Err(Error::ValueError); } + 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: None, + streamer: Some(streamer), dev: Arc::clone(&self.inner), format: SampleFormat::Sc16Q11, }) @@ -493,12 +503,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> { @@ -507,49 +514,48 @@ impl crate::DeviceTrait for BladeRf { } else { GainMode::Mgc }; - self.inner - .lock() - .unwrap() + 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> { - let range = BladeRf1::get_gain_range(ch(channel)?); + 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); - self.inner - .lock() - .unwrap() + 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( @@ -560,13 +566,13 @@ impl crate::DeviceTrait for BladeRf { gain: f64, ) -> Result<(), Error> { let stage = GainStage::try_from(name).map_err(|_| Error::ValueError)?; - let range = BladeRf1::get_gain_stage_range(stage); + 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); - self.inner - .lock() - .unwrap() + 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) } @@ -578,13 +584,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, )) } @@ -595,26 +598,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( @@ -625,23 +621,26 @@ 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}"); let ch = ch(channel)?; - if dev + if session .set_frequency(ch, frequency as u64, TuningMode::Fpga) .is_err() { log::warn!("FPGA retune failed, falling back to host tuning"); - dev.set_frequency(ch, frequency as u64, TuningMode::Host) + session + .set_frequency(ch, frequency as u64, TuningMode::Host) .map_err(bladerf_err)?; } Ok(()) @@ -684,12 +683,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( @@ -699,12 +695,15 @@ impl crate::DeviceTrait for BladeRf { rate: f64, ) -> Result<(), Error> { let mut dev = self.inner.lock().unwrap(); + let mut session = dev.rf_link_session().map_err(bladerf_err)?; let ch = ch(channel)?; - let actual = dev.set_sample_rate(ch, rate as u32).map_err(bladerf_err)?; + 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 = dev.set_bandwidth(ch, actual).map_err(bladerf_err)?; + 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})"); } @@ -717,23 +716,19 @@ 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() + 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 { @@ -743,7 +738,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 { From 0bb3fb0839158cf517c71319020f70388d8b15b2 Mon Sep 17 00:00:00 2001 From: ratzrattillo <11601995+ratzrattillo@users.noreply.github.com> Date: Sat, 20 Jun 2026 12:09:06 +0200 Subject: [PATCH 6/6] update libbladerf-rs to v0.4.1 --- Cargo.toml | 3 ++- src/impls/bladerf1.rs | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3eded7c..8683722 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,8 @@ thiserror = "2.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] once_cell = "1.21" -libbladerf-rs = { path="../libbladerf-rs", 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 } diff --git a/src/impls/bladerf1.rs b/src/impls/bladerf1.rs index 37d47b5..94cbd73 100644 --- a/src/impls/bladerf1.rs +++ b/src/impls/bladerf1.rs @@ -130,9 +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(), - } + Range::new(val.iter().cloned().map(Into::into).collect()) } } @@ -550,7 +548,7 @@ impl crate::DeviceTrait for BladeRf { let mut dev = self.inner.lock().unwrap(); let mut session = dev.rf_link_session().map_err(bladerf_err)?; Ok(Some( - session.get_gain(ch(channel)?).map_err(bladerf_err)?.db as f64, + session.get_gain(ch(channel)?).map_err(bladerf_err)?.db() as f64, )) } @@ -587,7 +585,7 @@ impl crate::DeviceTrait for BladeRf { let mut dev = self.inner.lock().unwrap(); let mut session = dev.rf_link_session().map_err(bladerf_err)?; Ok(Some( - session.get_gain_stage(stage).map_err(bladerf_err)?.db as f64, + session.get_gain_stage(stage).map_err(bladerf_err)?.db() as f64, )) }