libbladerf-rs 0.3.0

Fully Rust native BladeRF driver
mod bandwidth;
mod calibration;
pub(crate) mod corrections;
mod dac_trim;
mod frequency;
mod gain;
mod loopback;
pub use loopback::Loopback;
pub(crate) mod rx_mux;
mod sample_rate;
pub mod stream;
pub mod xb;
use crate::bladerf1::hardware::lms6002d;
use crate::bladerf1::nios_client::NiosClient;
use crate::channel::Channel;
use crate::error::Error;
use crate::transport::usb::{
    BladeRf1DeviceCommands, BladeRf1UsbInterfaceCommands, DeviceCommands, UsbInterfaceCommands,
};
pub use corrections::Correction;
pub use frequency::TuningMode;
pub use gain::GainMode;
use nusb::transfer::{In, Out};
use nusb::{Device, DeviceInfo, MaybeFuture, Speed};
pub use rx_mux::RxMux;
pub use stream::{
    BLADERF_GPIO_8BIT_MODE, BLADERF_GPIO_HIGHLY_PACKED_MODE, BLADERF_GPIO_PACKET,
    BLADERF_GPIO_TIMESTAMP, BLADERF_GPIO_TIMESTAMP_DIV2, METADATA_HEADER_SIZE, MetadataHeader,
    RxStreamBuilder, SampleFormat, TxStreamBuilder,
};
pub const BLADERF1_USB_VID: u16 = 0x2CF0;
pub const BLADERF1_USB_PID: u16 = 0x5246;
pub const BLADERF_GPIO_FEATURE_SMALL_DMA_XFER: u16 = 1 << 7;
pub struct RxStream {
    pool: stream::BufferPool<In>,
}
pub struct TxStream {
    pool: stream::BufferPool<Out>,
}
pub struct BladeRf1 {
    device: Device,
    nios: NiosClient,
    chunk_size: usize,
}
impl BladeRf1 {
    pub fn list_bladerf1() -> crate::Result<impl Iterator<Item = DeviceInfo>> {
        Ok(nusb::list_devices().wait()?.filter(|dev: &DeviceInfo| {
            dev.vendor_id() == BLADERF1_USB_VID && dev.product_id() == BLADERF1_USB_PID
        }))
    }
    fn build(device: Device) -> crate::Result<Self> {
        log::debug!("Manufacturer: {}", device.manufacturer()?);
        log::debug!("Product: {}", device.product()?);
        log::debug!("Serial: {}", device.serial()?);
        log::debug!("Speed: {:?}", device.speed());
        log::debug!("Languages: {:x?}", device.get_supported_languages()?);
        let speed = device.speed().ok_or(Error::UnsupportedSpeed)?;
        if speed < Speed::High {
            log::error!("BladeRF requires High/Super/SuperPlus speeds");
            return Err(Error::UnsupportedSpeed);
        }
        let nios = NiosClient::from(device.detach_and_claim_interface(0).wait()?);
        let chunk_size = crate::bladerf1::hardware::spi_flash::get_chunk_size(speed)?;
        Ok(Self {
            device,
            nios,
            chunk_size,
        })
    }
    pub fn from_first() -> crate::Result<Self> {
        let device = Self::list_bladerf1()?
            .next()
            .ok_or(Error::NotFound)?
            .open()
            .wait()?;
        Self::build(device)
    }
    pub fn from_serial(serial: &str) -> crate::Result<Self> {
        let device = Self::list_bladerf1()?
            .find(|dev| dev.serial_number() == Some(serial))
            .ok_or(Error::NotFound)?
            .open()
            .wait()?;
        Self::build(device)
    }
    pub fn from_bus_addr(bus_number: &str, bus_addr: u8) -> crate::Result<Self> {
        let device = Self::list_bladerf1()?
            .find(|dev| dev.bus_id() == bus_number && dev.device_address() == bus_addr)
            .ok_or(Error::NotFound)?
            .open()
            .wait()?;
        Self::build(device)
    }
    #[cfg(target_os = "linux")]
    pub fn from_fd(fd: std::os::fd::OwnedFd) -> crate::Result<Self> {
        let device = Device::from_fd(fd).wait()?;
        Self::build(device)
    }
    pub fn serial(&self) -> crate::Result<String> {
        self.device.serial()
    }

    pub fn speed(&self) -> crate::Result<Speed> {
        self.device.speed().ok_or(Error::UnsupportedSpeed)
    }

    pub fn fx3_firmware_version(&self) -> crate::Result<String> {
        self.device.fx3_firmware_version()
    }
    pub fn fpga_version(&mut self) -> crate::Result<String> {
        let version = self.nios.nios_get_fpga_version()?;
        Ok(format!("{version}"))
    }
    pub fn config_gpio_read(&mut self) -> crate::Result<u32> {
        self.nios.nios_config_read()
    }
    pub fn config_gpio_write(&mut self, mut data: u32) -> crate::Result<()> {
        log::trace!("[config_gpio_write] data: {data}");
        let speed = self.device.speed().ok_or(Error::UnsupportedSpeed)?;
        log::trace!("[config_gpio_write] speed: {speed:?}");
        match speed {
            Speed::High => {
                data |= BLADERF_GPIO_FEATURE_SMALL_DMA_XFER as u32;
            }
            Speed::Super => {
                data &= !(BLADERF_GPIO_FEATURE_SMALL_DMA_XFER as u32);
            }
            _ => {
                log::error!("speed {speed:?} not supported");
                return Err(Error::UnsupportedSpeed);
            }
        }
        log::trace!("[config_gpio_write] data after speed check: {data}");
        self.nios.nios_config_write(data)
    }
    pub fn initialize(&mut self, force: bool) -> crate::Result<()> {
        let alt_setting = self.nios.get_alt_setting();
        log::trace!("[*] Init - Default Alt Setting {alt_setting}");
        if alt_setting != 1 {
            self.nios.usb_change_setting(0x01)?;
            log::trace!("[*] Init - Set Alt Setting to 0x01");
        }
        let cfg = self.config_gpio_read()?;
        if force || (cfg & 0x7f) == 0 {
            log::trace!(
                "[*] Init - {}initializing device (GPIO={cfg:#04x})",
                if force { "Force " } else { "" }
            );
            self.config_gpio_write(0x57)?;
            lms6002d::enable_rffe(&mut self.nios, Channel::Tx, false)?;
            lms6002d::enable_rffe(&mut self.nios, Channel::Rx, false)?;
            lms6002d::write(&mut self.nios, 0x05, 0x3e)?;
            lms6002d::write(&mut self.nios, 0x47, 0x40)?;
            lms6002d::write(&mut self.nios, 0x59, 0x29)?;
            lms6002d::write(&mut self.nios, 0x64, 0x36)?;
            lms6002d::write(&mut self.nios, 0x79, 0x37)?;
            lms6002d::set(&mut self.nios, 0x3f, 0x80)?;
            lms6002d::set(&mut self.nios, 0x5f, 0x80)?;
            lms6002d::set(&mut self.nios, 0x6e, 0xc0)?;
            lms6002d::frequency::config_charge_pumps(&mut self.nios, Channel::Tx)?;
            lms6002d::frequency::config_charge_pumps(&mut self.nios, Channel::Rx)?;
            let _actual_tx = crate::bladerf1::hardware::si5338::set_sample_rate(
                &mut self.nios,
                Channel::Tx,
                1_000_000,
            )?;
            let _actual_rx = crate::bladerf1::hardware::si5338::set_sample_rate(
                &mut self.nios,
                Channel::Rx,
                1_000_000,
            )?;
            self.set_frequency(Channel::Tx, 2_447_000_000, TuningMode::Fpga)?;
            self.set_frequency(Channel::Rx, 2_484_000_000, TuningMode::Fpga)?;
            crate::bladerf1::hardware::dac161s055::write(&mut self.nios, 0)?;
            self.set_gain_mode(Channel::Rx, GainMode::Mgc)?;
        } else {
            log::trace!("[*] Init - Device already initialized: {cfg:#04x}");
        }
        Ok(())
    }
    pub fn enable_module(&mut self, channel: Channel, enable: bool) -> crate::Result<()> {
        if !enable {
            self.perform_format_deconfig(channel)?;
        }
        lms6002d::enable_rffe(&mut self.nios, channel, enable)?;
        self.nios.usb_enable_module(channel, enable)
    }
    pub fn band_select(&mut self, channel: Channel, band: lms6002d::Band) -> crate::Result<()> {
        let band_value = match band {
            lms6002d::Band::Low => 2,
            lms6002d::Band::High => 1,
        };
        log::trace!("Selecting {band:?} band");
        lms6002d::select_band(&mut self.nios, channel, band)?;
        let mut gpio = self.config_gpio_read()?;
        let shift = if channel == Channel::Tx {
            3 << 3
        } else {
            3 << 5
        };
        gpio &= !shift;
        let shift = if channel == Channel::Tx {
            band_value << 3
        } else {
            band_value << 5
        };
        gpio |= shift;
        self.config_gpio_write(gpio)
    }
}