libbladerf-rs 0.5.0

Fully Rust native BladeRF driver
//! Flash-stored calibration data access.
//!
//! Reads and writes factory calibration values from the SPI flash calibration
//! region. The calibration page stores the DAC trim value for VCTCXO tuning
//! and the FPGA package size indicator. These values are written during
//! manufacturing and persist across power cycles.

use crate::bladerf1::board::FlashSession;
use crate::bladerf1::board::fpga::{BLADERF_FLASH_FPGA_SIZE_40KLE, BLADERF_FLASH_FPGA_SIZE_115KLE};
use crate::bladerf1::hardware::spi_flash::{BLADERF_FLASH_ADDR_CAL, BLADERF_FLASH_PAGE_SIZE};
use crate::error::Error;
use crate::error::Result;
use crate::flash::{FpgaSize, binkv_decode_field, make_cal_region};
use crate::maybe_future::Op;
use nusb::MaybeFuture;

impl FlashSession<'_> {
    /// Reads the factory DAC trim value from the flash calibration region.
    ///
    /// Parses the binkv-encoded `"DAC"` field from the calibration page.
    /// Returns `Error::BoardState` if the field is missing or not a valid u16.
    pub fn read_flash_dac_trim(&mut self) -> impl MaybeFuture<Output = Result<u16>> {
        Op::new(async move {
            let mut buf = [0u8; BLADERF_FLASH_PAGE_SIZE];
            self.read_cal_cache(&mut buf).await?;
            let dac_str = binkv_decode_field(&buf, "DAC")?;
            dac_str
                .parse::<u16>()
                .map_err(|_| Error::FlashData("failed to parse DAC trim from flash"))
        })
    }

    /// Reads the FPGA package size indicator from the flash calibration region.
    ///
    /// Parses the binkv-encoded `"B"` field to determine whether the device
    /// uses a 40KLE or 115KLE FPGA. The value is used to select the correct
    /// bitstream size for flash operations.
    pub fn read_flash_fpga_size(&mut self) -> impl MaybeFuture<Output = Result<FpgaSize>> {
        Op::new(async move {
            let mut buf = [0u8; BLADERF_FLASH_PAGE_SIZE];
            self.read_cal_cache(&mut buf).await?;
            let fpga_str = binkv_decode_field(&buf, "B")?;
            FpgaSize::parse(&fpga_str)
        })
    }

    /// Writes a new DAC trim value to the flash calibration region.
    ///
    /// Reads the existing FPGA size indicator, constructs a full calibration
    /// page image, and erases/writes/verifies the calibration sector. Use
    /// this to update the factory trim after performing a new calibration
    /// measurement.
    pub fn write_flash_dac_trim(&mut self, dac_trim: u16) -> impl MaybeFuture<Output = Result<()>> {
        Op::new(async move {
            let fpga_size = self.read_flash_fpga_size().await?;
            let cal_image = make_cal_region(fpga_size, dac_trim)?;
            let cal_page = BLADERF_FLASH_ADDR_CAL / BLADERF_FLASH_PAGE_SIZE as u32;
            self.erase_write_verify(cal_page, &cal_image).await
        })
    }

    /// Returns the expected FPGA bitstream size in bytes based on flash calibration data.
    ///
    /// Reads the FPGA size indicator and maps it to the corresponding
    /// bitstream byte count. Returns `Error::Argument` if the flash contains
    /// an unrecognized FPGA size.
    pub fn get_fpga_bytes(&mut self) -> impl MaybeFuture<Output = Result<usize>> {
        Op::new(async move {
            match self.read_flash_fpga_size().await? {
                FpgaSize::KLE40 => Ok(BLADERF_FLASH_FPGA_SIZE_40KLE),
                FpgaSize::KLE115 => Ok(BLADERF_FLASH_FPGA_SIZE_115KLE),
                _ => Err(Error::Argument("unsupported FPGA size".into())),
            }
        })
    }
}