libbladerf-rs 0.5.0

Fully Rust native BladeRF driver
docs.rs failed to build libbladerf-rs-0.5.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: libbladerf-rs-0.2.0

Crates.io Documentation License Build Status Downloads

Pure Rust driver for the Nuand BladeRF1 (x40/x115) SDR. No C libbladeRF dependency. USB transport via nusb. Supports Windows, macOS, Linux, Android (via file descriptor) and WebUSB (wasm32-unknown-unknown). Every I/O method can be used synchronously or asynchronously.

Feature flags

Flag Default Effect
bladerf1 yes* BladeRF1 support (x40/x115)
bladerf2 no BladeRF2 support — stub only
xb100 yes XB-100 LED expansion board
xb200 yes XB-200 transverter board
xb300 yes XB-300 amplifier board
smol yes nusb smol integration (blocking thread pool)
tokio no nusb tokio integration (spawn_blocking)

Exactly like every nusb-based driver, one of smol/tokio is required on native targets: nusb resolves device open, interface claim, alternate-setting switches and clear-halt through the selected runtime's blocking pool. Neither is needed on wasm32. If both are enabled nusb uses smol.

* Enabled implicitly by xb100, xb200, or xb300.

Usage

The device is accessed through session types that switch the FX3 USB alternate setting and borrow &mut NiosCore. The borrow checker enforces exclusive access at compile time.

Session types

Session USB alt setting Capabilities
RfLinkSession RfLink (0x01) Tuning, gain, sample rate, bandwidth, streaming, expansion boards, triggers, loopback, corrections
FlashSession SpiFlash (0x02) SPI flash erase/write/verify, calibration region access
ConfigSession Config (0x03) FPGA loading, device configuration

FlashSession and ConfigSession return Error::StreamsActive if any stream is running.

Sync or async

Every I/O method returns an [nusb::MaybeFuture] (re-exported as libbladerf_rs::MaybeFuture). Call .wait() to block the current thread, or .await it from async code:

use libbladerf_rs::MaybeFuture;
use libbladerf_rs::bladerf1::{BladeRf1, RxStream, TuningMode};
use libbladerf_rs::Channel;

// Blocking (native targets only)
let mut dev = BladeRf1::from_first().wait()?;
let mut rf = dev.rf_link_session().wait()?;
rf.initialize(false).wait()?;
rf.set_frequency(Channel::Rx, 100_000_000, TuningMode::Fpga).wait()?;
let mut rx = RxStream::builder(&mut rf).build().wait()?;
rx.start(&mut rf).wait()?;
let buffer = rx.read(Some(std::time::Duration::from_secs(1))).wait()?;
rx.recycle(buffer);
rx.close(&mut rf).wait()?;

// Async — identical calls, `.await` instead of `.wait()`
let mut dev = BladeRf1::from_first().await?;
let mut rf = dev.rf_link_session().await?;
rf.initialize(false).await?;
let mut rx = RxStream::builder(&mut rf).build().await?;
rx.start(&mut rf).await?;
let buffer = rx.read(None).await?;
rx.recycle(buffer);
rx.close(&mut rf).await?;
dev.close().await?;

The crate mirrors nusb's semantics exactly: transfers are real futures completed by nusb's event thread, and the handful of blocking syscalls (device open, interface claim, alternate-setting switch, clear halt) are offloaded through nusb's smol or tokio integration. With the default smol feature both .wait() and .await work under any executor. With tokio instead, .await must run inside a tokio runtime; .wait() works anywhere (the crate enters a private runtime context for callers outside tokio).

Streaming timeouts (RxStream::read, TxStream::get_buffer, TxStream::wait_completion) apply to the blocking path only. The awaited futures ignore the timeout argument, consume at most one USB completion per await and are cancel-safe, so wrap them in your executor's timeout (tokio::time::timeout, gloo_timers, ...) if you need a deadline.

WebUSB

The crate compiles for wasm32-unknown-unknown. nusb's WebUSB backend needs web-sys unstable APIs, so consumers must add to their .cargo/config.toml:

[target.wasm32-unknown-unknown]
rustflags = ["--cfg=web_sys_unstable_apis"]

Obtain a device with nusb::request_device (from a user gesture) or nusb::list_devices, then open it with BladeRf1::from_device(device).await. There is no .wait() on wasm, Drop performs no I/O, and transfers cannot be cancelled, so always close() streams and the device explicitly.

Examples

Git-tracked examples (build and run from the repository root):

Package Purpose
info Basic device info and FPGA version
rx-tx Streaming RX/TX with metadata headers
rx-async RX streaming with the awaited API on tokio (--features tokio)
calibrate DC calibration on LMS6002D
dc-cal-table DC calibration table management
flash-firmware FX3 firmware flashing
flash-fpga FPGA bitstream flashing
cargo run -p info
cargo run -p rx-tx
cargo run -p rx-async

Supported features

  • RF control: frequency (host/FPGA tuning, quick-tune), gain (per-stage apportioning, gain modes, gain stage control), sample rate (integer and rational), bandwidth, LPF mode, RF port selection
  • Streaming: zero-copy DMA via BufferPool (RX/TX), metadata headers, multiple sample formats (Sc16Q11, Sc8Q7, Sc16Q11Packed, *Meta variants), pack/unpack helpers
  • DC calibration: on-demand LMS6002D calibration, flash-stored JSON calibration tables with auto-load on open and frequency-specific apply
  • Flash: erase/write/verify, calibration region (DAC trim, FPGA size)
  • FPGA: host-based loading, flash autoload, source query, firmware log reading
  • Expansion boards: XB-100 (GPIO/LED), XB-200 (filter bank, upconverter, auto filter), XB-300 (amplifier, TRX, output power)
  • Other: SMB clock, VCTCXO tamer, triggers, loopback (LMS + FPGA), corrections (DC/phase), RX mux, retune scheduling, timestamps, firmware flashing

Not supported (vs C libbladeRF)

  • BladeRF2 — stub only, not implemented
  • Synchronous APIbladerf_sync_config/rx/tx not implemented
  • Bootloader — jump to bootloader, load firmware from bootloader
  • OTP (one-time programmable) — read/write/lock
  • Image helpers — flash image allocate/free/read/write
  • Byte-level flash — byte-addressed erase/read/write (page/sector only)
  • Wishbone — master read/write
  • USB reset on open — configuration option
  • Multi-device / MIMO — clock sync helpers
  • Tuning mode get — missing getter
  • Gain calibration tables — bladeRF2-specific (not applicable to BladeRF1)

Developers

Contributions are welcome. The architecture is documented in AGENTS.md. The release and maintenance workflow is documented in docs/MAINTAINERS.md.

Commit messages

Commits must follow Conventional Commits. A husky-rs commit-msg hook (.husky/commit-msg) validates each message with git-cliff (cargo install git-cliff). The hook installs automatically on cargo build / cargo test; set NO_HUSKY_HOOKS=1 to skip installation.

For debugging, compare USB traffic between libbladeRF and [libbladerf-rs] using Wireshark:

sudo usermod -a -G wireshark <your_user>
sudo modprobe usbmon
sudo setfacl -m u:<your_user>:r /dev/usbmon*

Filter example:

usb.bus_id == 1 and usb.device_address == 2

Datasheets

Documentation

cargo doc --features bladerf1 --no-deps --lib --bins --examples

Testing

Unit tests (no hardware)

cargo test --lib
cargo test --test unit

Integration tests (requires BladeRF1)

cargo test --features bladerf1 --tests -- --test-threads=1

Specific test

cargo test --features bladerf1 --test bladerf1 -- frequency -- --test-threads=1