A reimplementation of basic libbladeRF functions in Rust, based on nusb usb backend.
Currently supporting BladeRF1 on Windows, macOS and Linux only.
Use libbladerf-rs to control your bladeRF1 from your Rust application. This software shall currently not be considered as a replacement for the official libbladeRF
due to several features not being available.
Usage overview
After a BladeRF1 is connected via USB (High or SuperSpeed USB port required) and fully booted,
an instance to a BladeRF can be opened using [bladerf1::BladeRf1::from_first].
A handle to a specific BladeRF1 can also be obtained by its [bladerf1::BladeRf1::from_bus_addr] or [bladerf1::BladeRf1::from_serial].
After obtaining an instance of a [bladerf1::BladeRf1], you can set basic parameters like Gain, Frequency
and Sample Rate or Bandwidth.
Examples
An example exists to demonstrate the current functionality of libbladerf-rs:
use anyhow::Result;
use libbladerf_rs::bladerf1::xb::ExpansionBoard;
use libbladerf_rs::bladerf1::{BladeRf1, GainDb, SampleFormat};
use libbladerf_rs::{BLADERF_MODULE_RX, BLADERF_MODULE_TX, Direction};
fn main() -> Result<()> {
env_logger::builder()
.filter_level(log::LevelFilter::Debug)
.filter_module("nusb", log::LevelFilter::Info)
.init();
let bladerf = BladeRf1::from_first()?;
log::debug!("Speed: {:?}", bladerf.speed());
log::debug!("Serial: {}", bladerf.serial()?);
log::debug!("Manufacturer: {}", bladerf.manufacturer()?);
log::debug!("FX3 Firmware: {}", bladerf.fx3_firmware()?);
log::debug!("Product: {}", bladerf.product()?);
let languages = bladerf.get_supported_languages()?;
log::debug!("Languages: {:x?}", languages);
bladerf.initialize()?;
log::debug!("FPGA: {}", bladerf.fpga_version()?);
let xb = bladerf.expansion_get_attached();
log::debug!("XB: {xb:?}");
bladerf.expansion_attach(ExpansionBoard::Xb200)?;
let xb = bladerf.expansion_get_attached();
log::debug!("XB: {xb:?}");
let frequency_range = bladerf.get_frequency_range()?;
log::debug!("Frequency Range: {frequency_range:?}");
bladerf.set_frequency(BLADERF_MODULE_RX, frequency_range.min().unwrap() as u64)?;
bladerf.set_frequency(BLADERF_MODULE_TX, frequency_range.min().unwrap() as u64)?;
let frequency_rx = bladerf.get_frequency(BLADERF_MODULE_RX)?;
let frequency_tx = bladerf.get_frequency(BLADERF_MODULE_TX)?;
log::debug!("Frequency RX: {}", frequency_rx);
log::debug!("Frequency TX: {}", frequency_tx);
let sample_rate_range = BladeRf1::get_sample_rate_range();
log::debug!("Sample Rate: {sample_rate_range:?}");
bladerf.set_sample_rate(BLADERF_MODULE_RX, sample_rate_range.min().unwrap() as u32)?;
bladerf.set_sample_rate(BLADERF_MODULE_TX, sample_rate_range.min().unwrap() as u32)?;
let sample_rate_rx = bladerf.get_sample_rate(BLADERF_MODULE_RX)?;
let sample_rate_tx = bladerf.get_sample_rate(BLADERF_MODULE_TX)?;
log::debug!("Sample Rate RX: {}", sample_rate_rx);
log::debug!("Sample Rate TX: {}", sample_rate_tx);
let bandwidth_range = BladeRf1::get_bandwidth_range();
log::debug!("Bandwidth: {bandwidth_range:?}");
bladerf.set_bandwidth(BLADERF_MODULE_RX, bandwidth_range.min().unwrap() as u32)?;
bladerf.set_bandwidth(BLADERF_MODULE_TX, bandwidth_range.min().unwrap() as u32)?;
let bandwidth_rx = bladerf.get_bandwidth(BLADERF_MODULE_RX)?;
let bandwidth_tx = bladerf.get_bandwidth(BLADERF_MODULE_TX)?;
log::debug!("Bandwidth RX: {}", bandwidth_rx);
log::debug!("Bandwidth TX: {}", bandwidth_tx);
let gain_stages_rx = BladeRf1::get_gain_stages(BLADERF_MODULE_RX);
let gain_stages_tx = BladeRf1::get_gain_stages(BLADERF_MODULE_TX);
log::debug!("Gain Stages RX: {gain_stages_rx:?}");
log::debug!("Gain Stages TX: {gain_stages_tx:?}");
let gain_range_rx = BladeRf1::get_gain_range(BLADERF_MODULE_RX);
let gain_range_tx = BladeRf1::get_gain_range(BLADERF_MODULE_TX);
log::debug!("Gain Range RX: {gain_range_rx:?}");
log::debug!("Gain Range TX: {gain_range_tx:?}");
bladerf.set_gain(
BLADERF_MODULE_RX,
GainDb {
db: gain_range_rx.min().unwrap() as i8,
},
)?;
bladerf.set_gain(
BLADERF_MODULE_TX,
GainDb {
db: gain_range_tx.min().unwrap() as i8,
},
)?;
let gain_rx = bladerf.get_gain(BLADERF_MODULE_RX)?;
let gain_tx = bladerf.get_gain(BLADERF_MODULE_TX)?;
log::debug!("Gain RX: {}", gain_rx.db);
log::debug!("Gain TX: {}", gain_tx.db);
bladerf.perform_format_config(Direction::Rx, SampleFormat::Sc16Q11)?;
bladerf.enable_module(BLADERF_MODULE_RX, true)?;
bladerf.experimental_control_urb()?;
bladerf.perform_format_deconfig(Direction::Rx)?;
bladerf.enable_module(BLADERF_MODULE_RX, false)?;
Ok(())
}
Build this example by executing the following command in your shell:
cargo run --package info
Limitations
libbladerf-rs currently only supports the BladeRF1. Support for BladeRF2 is currently not
possible, as I am not in the possession of named SDR.
Implemented Features
- Getting/Setting gain levels of individual stages like rxvga1, rxvga2, lna, txvga1 and txvga2.
- Getting/Setting RX/TX frequency
- Getting/Setting Bandwidth
- Getting/Setting Sample Rate
- Support for BladeRF1 Expansion boards (XB100, XB200, XB300)
- Interface for sending and receiving I/Q samples
Missing Features
- Support for BladeRF2
- Support for Firmware and FPGA flashing/validation
- Support for different I/Q sample formats and timestamps
- DC calibration table support
- Usage from both async and blocking contexts (currently sync only)
- Extensive documentation
- AGC enablement
Developers
Contributions of any kind are welcome!
If possible, method names should adhere to the documented methods in libbladeRF-doc
For debugging purposes, it is useful to compare the communication between the SDR and
the original libbladeRF with the communication of libbladerf-rs.
Hand tooling for this purpose is Wireshark. Allow wireshark to monitor USB traffic:
sudo usermod -a -G wireshark <your_user>
sudo modprobe usbmon
sudo setfacl -m u:<your_user>:r /dev/usbmon*
Filter out unwanted traffic by using a Wireshark filter like e.g.
usb.bus_id == 1 and usb.device_address == 2
Datasheets for the BladeRF1 hardware are available at the following resources:
SI5338
SI5338 Datasheet
SI5338 Reference Manual
LMS6002D
LMS6002D Datasheet
LMS6002D Programming and Calibration Guide
DAC161S055
DAC Datasheet
libbladerf-rs is a pure rust implementation for interacting with a Nuand BladeRF1.
To view the documentation, build it with:
cargo doc --open
Examples on how to use libbladerf-rs can be found in the examples/ directory
Testing
Run tests using the following command
cargo test -- --test-threads=1
Run tests and display output
cargo test -- --nocapture --test-threads=1
Run a specific test and display output
cargo test --test bladerf1_tuning -- --nocapture --test-threads=1