rtlsdr-pure 0.1.1

Pure Rust RTL-SDR driver using cross_usb for native USB and WebUSB
Documentation
use futures_lite::future::block_on;
use rtlsdr_pure::{GainMode, Result, open_first};

fn main() {
    if let Err(err) = block_on(run()) {
        eprintln!("probe failed: {err}");
        std::process::exit(1);
    }
}

async fn run() -> Result<()> {
    let mut args = std::env::args().skip(1);
    let frequency_hz = parse_arg(args.next(), 100_000_000);
    let sample_rate_hz = parse_arg(args.next(), rtlsdr_pure::DEFAULT_SAMPLE_RATE);
    let read_len = parse_arg(args.next(), 16 * 32 * 512usize);

    let mut sdr = open_first().await?;
    println!(
        "opened {:04x}:{:04x} {}",
        sdr.vendor_id(),
        sdr.product_id(),
        sdr.known_name().unwrap_or("RTL-SDR")
    );
    if let Some(manufacturer) = sdr.manufacturer() {
        println!("manufacturer: {manufacturer}");
    }
    if let Some(product) = sdr.product() {
        println!("product: {product}");
    }
    println!("tuner: {:?}", sdr.tuner_kind());

    let actual_rate = sdr.set_sample_rate(sample_rate_hz).await?;
    println!("sample rate: {actual_rate} Hz");

    if sdr.tuner_kind().is_supported() {
        sdr.set_tuner_gain(GainMode::Auto).await?;
        sdr.set_center_frequency(frequency_hz).await?;
        println!("center frequency: {frequency_hz} Hz");
    } else {
        println!("center frequency: skipped for unsupported tuner");
    }

    sdr.reset_buffer().await?;
    let bytes = sdr.read_bytes(read_len).await?;
    let pair_count = bytes.len() / 2;
    let (mean_i, mean_q) = if pair_count == 0 {
        (0.0, 0.0)
    } else {
        let (sum_i, sum_q) = bytes
            .chunks_exact(2)
            .fold((0u64, 0u64), |(sum_i, sum_q), pair| {
                (sum_i + pair[0] as u64, sum_q + pair[1] as u64)
            });
        (
            sum_i as f64 / pair_count as f64,
            sum_q as f64 / pair_count as f64,
        )
    };

    println!(
        "read {} bytes ({} I/Q pairs), mean I={mean_i:.2}, mean Q={mean_q:.2}",
        bytes.len(),
        pair_count
    );
    println!("first 16 bytes: {:02x?}", &bytes[..bytes.len().min(16)]);

    Ok(())
}

fn parse_arg<T>(arg: Option<String>, default: T) -> T
where
    T: std::str::FromStr,
{
    arg.and_then(|value| value.parse().ok()).unwrap_or(default)
}