libbladerf-rs 0.3.0

Fully Rust native BladeRF driver
[![Crates.io](https://img.shields.io/crates/v/libbladerf-rs.svg)](https://crates.io/crates/libbladerf-rs)
[![Documentation](https://docs.rs/libbladerf-rs/badge.svg)](https://docs.rs/libbladerf-rs)
[![License](https://img.shields.io/crates/l/libbladerf-rs.svg)](https://github.com/ratzrattillo/libbladerf-rs#license)
[![Build Status](https://github.com/ratzrattillo/libbladerf-rs/workflows/CI/badge.svg)](https://github.com/ratzrattillo/libbladerf-rs/actions)
[![Downloads](https://img.shields.io/crates/d/libbladerf-rs.svg)](https://crates.io/crates/libbladerf-rs)


A pure Rust driver for the Nuand BladeRF1 SDR, based on [nusb] USB backend. No C libbladeRF dependency.
Supports BladeRF1 on Windows, macOS, and Linux.

[nusb]: https://github.com/kevinmehall/nusb

Use [libbladerf-rs] to control your BladeRF1 from your Rust application. This software is not yet a full replacement for the official [libbladeRF] — some features are still missing.

[libbladeRF]: https://github.com/Nuand/bladeRF
[libbladerf-rs]: https://github.com/ratzrattillo/libbladerf-rs


## VCTCXO Oscillator Calibration

The BladeRF1 uses a 38.4 MHz VCTCXO (temperature-compensated voltage-controlled crystal oscillator) as its master clock reference. The oscillator's tuning voltage is generated by a DAC161S055 (16-bit voltage-output DAC) and set by a **DAC trim value**.

- **DAC trim** is a 16-bit value (0–65535) written to the DAC161S055. It maps to a control voltage in the range of **0.4 V to 2.4 V** at the VCTCXO tuning pin.
- The VCTCXO (ASV TX12) can be pulled approximately **±5 PPM to ±9.5 PPM** from its 38.4 MHz nominal frequency across the full control-voltage span. This gives a **total tuning range of roughly ±20 PPM (±386 Hz at 38.4 MHz)**. The exact band varies per unit due to manufacturing tolerance.
- At the center of the DAC range (about code `0x8000` ≈ 32768), the oscillator is closest to its rated 38.4 MHz. Moving the DAC code up or down shifts the output frequency proportionally.
- **If the DAC trim is wrong**, the oscillator drifts from its nominal frequency. At a few PPM, signals are still detectable but demodulation quality degrades. If the required correction exceeds the VCTCXO's pull range (the DAC hits its rail), no code value can compensate — the board's clock is fundamentally out of spec.
- Over time, ambient conditions (temperature, sunlight, aging) cause the oscillator to drift, necessitating re-calibration.

The **kalibrate example** in this repository demonstrates VCTCXO calibration using GSM FCCH signals as an external frequency reference. It performs a binary search over the 16-bit DAC trim range to minimize detected frequency offset, then optionally writes the corrected value to the device's calibration flash. See `examples/kalibrate/README.md` for details.


## Usage overview

After a BladeRF1 is connected via USB (High or SuperSpeed required) and fully booted,
open a device using [`bladerf1::BladeRf1::from_first`],
[`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

The `info` example demonstrates basic device access:

```bash
cargo run --package info
```

The `rx_tx` example demonstrates the streaming API:

```rust
use anyhow::Result;
use libbladerf_rs::bladerf1::{BladeRf1, SampleFormat};
use libbladerf_rs::Channel;

fn main() -> Result<()> {
    let mut device = BladeRf1::from_first()?;
    device.initialize()?;

    let mut rx = BladeRf1::rx_builder(&mut device)
        .buffer_size(65536)
        .buffer_count(8)
        .format(SampleFormat::Sc16Q11)
        .build()?;

    let buf = rx.read(None)?;
    println!("Got {} bytes", buf.len());
    rx.recycle(buf)?;

    rx.close(&mut device)?;
    Ok(())
}
```

More examples can be found in the `examples/` directory.

## Limitations

[libbladerf-rs] currently only supports the BladeRF1. Support for BladeRF2 is currently not
possible, as the maintainer is not in possession of one.

### Missing Features
- Support for BladeRF2
- Support for Firmware and FPGA flashing/validation
- AGC DC calibration table support (see `AGC_PLAN.md`)
- Usage from both async and blocking contexts (currently sync only)

## Developers
Contributions of any kind are welcome!

If possible, method names should adhere to the documented methods in [libbladeRF-doc]

[libbladeRF-doc]: https://www.nuand.com/libbladeRF-doc/v2.5.0/modules.html
[Wireshark]: https://www.wireshark.org/download.html

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:

```bash
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.

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

Datasheets for the BladeRF1 hardware are available at the following resources:
### SI5338
[SI5338 Datasheet](https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si5338.pdf)

[SI5338 Reference Manual](https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/reference-manuals/Si5338-RM.pdf)

### LMS6002D
[LMS6002D Datasheet](https://cdn.sanity.io/files/yv2p7ubm/production/47449c61cd388c058561bfd3121b8a10b3d2c987.pdf)

[LMS6002D Programming and Calibration Guide](https://cdn.sanity.io/files/yv2p7ubm/production/d20182c51057add570a74bd51d9c1336e814ea90.pdf)

### DAC161S055
[DAC Datasheet](https://www.ti.com/lit/ds/symlink/dac161s055.pdf?ts=1739140548819&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252Fde-de%252FDAC161S055)

## Documentation

Build and open the docs locally:

```bash
cargo doc --features bladerf1 --open
```

## Testing

### Run unit tests (no hardware required)

```bash
cargo test --lib
```

### Run integration tests (requires BladeRF1 connected)

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

### Run a specific test with output

```bash
cargo test --features bladerf1 --test integration_bladerf1_frequency -- --nocapture --test-threads=1
```