seify-hackrfone 0.2.2

Fully Rust native HackRF one driver, powered by nusb
Documentation
use anyhow::{Context, Result};
use seify_hackrfone::{Config, HackRf};
use std::time::{Duration, Instant};

fn main() -> Result<()> {
    env_logger::init();

    let radio = HackRf::open_first().context("Failed to open Hackrf")?;

    println!("Board ID: {}", radio.board_id().context("Read board id")?);
    println!(
        "Firmware version: {}",
        radio.version().context("Read board version")?
    );
    println!("Device version: {}", radio.device_version());

    radio
        .start_rx(&Config {
            vga_db: 0,
            txvga_db: 0,
            lna_db: 0,
            amp_enable: false,
            antenna_enable: false,
            frequency_hz: 915_000_000,
            sample_rate_hz: 2_000_000,
            sample_rate_div: 1,
        })
        .context("Failed to start rx")?;

    // Starts to drop samples below 8KB MTU, with 20MHz sample rate, on AMD Ryzen 9 @5.3GHz, linux 6.6
    // Or use `start_rx_stream` so that triple buffering is used, and the kernel can continue to do
    // IO in the background while we do our processing. Expect to need rx stream or a larger MTU as
    // you implement processing more complicated than average power
    const MTU: usize = 32 * 1024;
    let mut buf = vec![0u8; MTU];

    let mut last_print = Instant::now();
    let mut bytes = 0;
    let mut stream_power = 0;
    loop {
        let n = radio.read(&mut buf).context("Failed to receive samples")?;
        assert_eq!(n, buf.len());
        bytes += n;
        for value in buf.iter().map(|v| *v as i8) {
            stream_power += (value as i64 * value as i64) as u64;
        }

        let now = Instant::now();
        let elapsed = now.saturating_duration_since(last_print);
        if elapsed.as_secs() >= 1 {
            let full_scale_ratio = stream_power as f64 / (bytes * 127 * 127) as f64;
            let db_full_scale = 10.0 * full_scale_ratio.log10() + 3.0;

            let mib = bytes as f64 / 1_000_000.0 / elapsed.as_secs_f64();
            println!(
                "{mib:.1}MiB / s, {:.1}M samples, average power {db_full_scale:.1}dBfs",
                bytes as f64 / 2.0 / 1_000_000.0,
            );
            last_print += Duration::from_secs(1);
            stream_power = 0;
            bytes = 0;
        }
    }
}