use crate::error::{Error, Result};
pub use crate::bladerf1::board::firmware::BLADERF_FLASH_MIN_FW_SIZE;
pub use crate::bladerf1::board::fpga::{
BLADERF_FLASH_FPGA_SIZE_40KLE, BLADERF_FLASH_FPGA_SIZE_115KLE, is_valid_fpga_size,
};
pub use crate::bladerf1::hardware::spi_flash::{
BLADERF_FLASH_ADDR_CAL, BLADERF_FLASH_ADDR_FIRMWARE, BLADERF_FLASH_ADDR_FPGA,
BLADERF_FLASH_BYTE_LEN_CAL, BLADERF_FLASH_BYTE_LEN_FIRMWARE, BLADERF_FLASH_ERASE_BLOCK_SIZE,
BLADERF_FLASH_PAGE_SIZE,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FpgaSize {
KLE40,
KLE115,
A4,
A5,
A9,
}
impl FpgaSize {
pub fn as_str(&self) -> &'static str {
match self {
FpgaSize::KLE40 => "40",
FpgaSize::KLE115 => "115",
FpgaSize::A4 => "A4",
FpgaSize::A5 => "A5",
FpgaSize::A9 => "A9",
}
}
pub fn variant_label(&self) -> Result<&'static str> {
match self {
FpgaSize::KLE40 => Ok("hostedx40"),
FpgaSize::KLE115 => Ok("hostedx115"),
_ => Err(Error::Unsupported("FPGA variant")),
}
}
pub fn parse(s: &str) -> Result<Self> {
match s {
"40" => Ok(FpgaSize::KLE40),
"115" => Ok(FpgaSize::KLE115),
"A4" => Ok(FpgaSize::A4),
"A5" => Ok(FpgaSize::A5),
"A9" => Ok(FpgaSize::A9),
_ => Err(Error::Argument("unknown FPGA size".into())),
}
}
}
pub fn zcrc(data: &[u8]) -> u16 {
let mut crc: u16 = 0;
for &byte in data {
crc ^= (byte as u16) << 8;
for _ in 0..8 {
if (crc & 0x8000) != 0 {
crc = (crc << 1) ^ 0x1021;
} else {
crc <<= 1;
}
}
}
crc
}
pub fn binkv_encode_field(buf: &mut [u8], idx: usize, field: &str, val: &str) -> Result<usize> {
let flen = field.len();
let vlen = val.len();
let tlen = flen + vlen + 1;
if tlen >= 256 || idx + tlen + 2 > buf.len() {
return Err(Error::BoardState(
"binkv field too large or buffer overflow",
));
}
buf[idx] = (flen + vlen) as u8;
buf[idx + 1..idx + 1 + flen].copy_from_slice(field.as_bytes());
buf[idx + 1 + flen..idx + 1 + flen + vlen].copy_from_slice(val.as_bytes());
let crc = zcrc(&buf[idx..idx + tlen]);
buf[idx + tlen] = crc as u8;
buf[idx + tlen + 1] = (crc >> 8) as u8;
Ok(idx + tlen + 2)
}
pub fn binkv_decode_field(buf: &[u8], field: &str) -> Result<String> {
let flen = field.len();
let mut pos = 0;
while pos < buf.len() {
let c = buf[pos] as usize;
if c == 0xFF {
break;
}
if pos + c + 3 > buf.len() {
break;
}
let stored_crc = u16::from_le_bytes([buf[pos + c + 1], buf[pos + c + 2]]);
let calc_crc = zcrc(&buf[pos..pos + c + 1]);
if stored_crc != calc_crc {
return Err(Error::BoardState("binkv CRC mismatch"));
}
if flen <= c && &buf[pos + 1..pos + 1 + flen] == field.as_bytes() {
let val_start = pos + 1 + flen;
let val_end = pos + 1 + c;
let val = String::from_utf8_lossy(&buf[val_start..val_end]).into_owned();
return Ok(val);
}
pos += c + 3;
}
Err(Error::BoardState("binkv field not found"))
}
pub fn binkv_add_field(buf: &mut [u8], field: &str, val: &str) -> Result<()> {
let mut i = 0;
while i < buf.len() {
let field_len = buf[i] as usize;
if field_len == 0xFF {
break;
}
i += field_len + 3;
}
binkv_encode_field(buf, i, field, val)?;
Ok(())
}
pub fn pad_to_page(data: &[u8]) -> Vec<u8> {
let padding =
(BLADERF_FLASH_PAGE_SIZE - data.len() % BLADERF_FLASH_PAGE_SIZE) % BLADERF_FLASH_PAGE_SIZE;
let mut out = Vec::with_capacity(data.len() + padding);
out.extend_from_slice(data);
out.extend(std::iter::repeat_n(0xFF, padding));
out
}
pub fn decode_flash_size(manufacturer_id: u8, device_id: u8) -> Result<u32> {
match manufacturer_id {
0xC2 => match device_id {
0x36 => Ok(32 << 17),
_ => Err(Error::Unsupported("unknown Macronix flash device")),
},
0xEF => match device_id {
0x15 => Ok(32 << 17),
0x16 => Ok(64 << 17),
0x17 => Ok(128 << 17),
_ => Err(Error::Unsupported("unknown Winbond flash device")),
},
0x1F => match device_id {
0x47 => Ok(32 << 17),
_ => Err(Error::Unsupported("unknown Renesas flash device")),
},
_ => Err(Error::Unsupported("unknown flash manufacturer")),
}
}
pub fn make_cal_region(fpga_size: FpgaSize, dac_trim: u16) -> Result<[u8; 256]> {
let mut buf = [0xFFu8; 256];
binkv_add_field(&mut buf, "B", fpga_size.as_str())?;
let dac_str = format!("{}", dac_trim);
binkv_add_field(&mut buf, "DAC", &dac_str)?;
Ok(buf)
}