soapysdr 0.5.0

Library wrapping SoapySDR, a hardware abstraction layer for many software defined radio devices, including rtl-sdr, HackRF, USRP, LimeSDR, BladeRF, and Airspy.
Documentation
use soapysdr_sys::*;
use std::slice;

use std::ffi::CStr;
use std::os::raw::c_char;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[non_exhaustive]
pub enum ArgType {
    Bool,
    Float,
    Int,
    String,
}

impl From<SoapySDRArgInfoType> for ArgType {
    #[allow(non_upper_case_globals)]
    fn from(arg_info_type: SoapySDRArgInfoType) -> Self {
        match arg_info_type {
            soapysdr_sys::SOAPY_SDR_ARG_INFO_BOOL => ArgType::Bool,
            soapysdr_sys::SOAPY_SDR_ARG_INFO_FLOAT => ArgType::Float,
            soapysdr_sys::SOAPY_SDR_ARG_INFO_INT => ArgType::Int,
            soapysdr_sys::SOAPY_SDR_ARG_INFO_STRING => ArgType::String,
            _ => panic!("Unexpected SoapySDRArgInfoType value"),
        }
    }
}

/// Metadata about supported arguments.
#[derive(Debug)]
pub struct ArgInfo {
    /// The key used to identify the argument
    pub key: String,

    /// The default value of the argument when not specified
    pub value: String,

    /// The displayable name of the argument
    pub name: Option<String>,

    ///  A brief description about the argument
    pub description: Option<String>,

    /// The units of the argument: dB, Hz, etc
    pub units: Option<String>,

    /// The data type of the argument
    pub data_type: ArgType,

    /// A discrete list of possible values.
    ///
    /// When specified, the argument should be restricted to this options set.
    pub options: Vec<(String, Option<String>)>,
}

unsafe fn required_string(s: *mut c_char) -> String {
    unsafe {
        assert!(!s.is_null(), "Null string from SoapySDR");
        CStr::from_ptr(s).to_string_lossy().into()
    }
}

unsafe fn optional_string(s: *mut c_char) -> Option<String> {
    unsafe {
        if !s.is_null() {
            Some(CStr::from_ptr(s).to_string_lossy().into())
        } else {
            None
        }
    }
}

pub unsafe fn arg_info_from_c(c: &SoapySDRArgInfo) -> ArgInfo {
    unsafe {
        ArgInfo {
            key: required_string(c.key),
            value: required_string(c.value),
            name: optional_string(c.name),
            description: optional_string(c.description),
            units: optional_string(c.units),
            data_type: c.type_.into(),
            options: {
                let option_vals = slice::from_raw_parts(c.options, c.numOptions);
                let option_names = slice::from_raw_parts(c.optionNames, c.numOptions);
                option_vals
                    .iter()
                    .zip(option_names.iter())
                    .map(|(&name, &val)| (required_string(name), optional_string(val)))
                    .collect()
            },
        }
    }
}