use alloc::vec::Vec;
use crate::{Error, Result};
pub const FIRMWARE_DATA_MAX: usize = u32::MAX as usize;
pub const FIRMWARE_DATA_SECTION_LEN: usize = 128;
pub const DEFAULT_DATA_BLOCK_LEN: usize = 128;
#[repr(C)]
#[derive(Clone, Debug, PartialEq)]
pub struct FirmwareData {
block: Vec<u8>,
index: usize,
block_len: usize,
}
impl FirmwareData {
pub const fn new() -> Self {
Self {
block: Vec::new(),
index: 0,
block_len: DEFAULT_DATA_BLOCK_LEN,
}
}
pub fn create(val: &[u8], block_len: usize) -> Result<Self> {
let len = val.len();
if len > FIRMWARE_DATA_MAX {
Err(Error::Firmware(format!(
"invalid firmware dataset length, have: {len}, max: {FIRMWARE_DATA_MAX}"
)))
} else {
Ok(Self {
block: val.into(),
index: 0,
block_len,
})
}
}
pub fn next_section(&mut self) -> Option<&[u8]> {
if self.index >= self.block.len() {
None
} else if self.block.len() - self.index < FIRMWARE_DATA_SECTION_LEN {
let start = self.index;
self.index = self.block.len();
Some(&self.block[start..])
} else {
let start = self.index;
let end = start + FIRMWARE_DATA_SECTION_LEN;
self.index = end;
Some(&self.block[start..end])
}
}
pub fn block_len(&self) -> usize {
self.block_len
}
pub fn set_block_len(&mut self, len: u16) {
self.block_len = len as usize;
}
pub const fn index(&self) -> usize {
self.index
}
pub fn len(&self) -> usize {
self.block.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl TryFrom<&[u8]> for FirmwareData {
type Error = Error;
fn try_from(val: &[u8]) -> Result<Self> {
Self::create(val, DEFAULT_DATA_BLOCK_LEN)
}
}
impl<const N: usize> TryFrom<&[u8; N]> for FirmwareData {
type Error = Error;
fn try_from(val: &[u8; N]) -> Result<Self> {
val.as_ref().try_into()
}
}
impl<const N: usize> TryFrom<[u8; N]> for FirmwareData {
type Error = Error;
fn try_from(val: [u8; N]) -> Result<Self> {
val.as_ref().try_into()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn test_data_sections() -> Result<()> {
let exp_data_buf = [0xff; 4096];
let mut sections = 0;
let mut index = 0;
let exp_sections = 32;
let mut data_block = FirmwareData::create(&exp_data_buf, FIRMWARE_DATA_SECTION_LEN)?;
while let Some(section) = data_block.next_section() {
assert_eq!(section, &exp_data_buf[index..index + section.len()]);
assert!(section.len() <= FIRMWARE_DATA_SECTION_LEN);
index += section.len();
sections += 1;
}
assert_eq!(sections, exp_sections);
Ok(())
}
#[test]
fn test_data_uneven_sections() -> Result<()> {
let exp_data_buf = [0xff; 192];
let mut sections = 0;
let mut index = 0;
let exp_sections = 2;
let mut data_block = FirmwareData::create(&exp_data_buf, FIRMWARE_DATA_SECTION_LEN)?;
while let Some(section) = data_block.next_section() {
assert_eq!(section, &exp_data_buf[index..index + section.len()]);
assert!(section.len() <= FIRMWARE_DATA_SECTION_LEN);
index += section.len();
sections += 1;
}
assert_eq!(sections, exp_sections);
Ok(())
}
#[test]
fn test_invalid_data_block() {
let bad_data_buf = vec![0xff; FIRMWARE_DATA_MAX + 1];
let bad_slice: &[u8] = bad_data_buf.as_ref();
assert!(FirmwareData::create(bad_slice, FIRMWARE_DATA_SECTION_LEN).is_err());
assert!(FirmwareData::try_from(bad_slice).is_err());
}
}