use crate::StorageMedium;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectorError<E> {
Storage(E),
VerificationFailed,
}
impl<E> From<E> for SectorError<E> {
fn from(err: E) -> Self {
SectorError::Storage(err)
}
}
pub const MIN_SECTOR_SIZE: usize = 128;
pub struct SectorStorage<S: StorageMedium> {
storage: S,
sector_size: usize,
sector_count: usize,
}
impl<S: StorageMedium> SectorStorage<S> {
pub fn new(storage: S) -> Self {
let info = storage.info();
let mut sector_size = MIN_SECTOR_SIZE;
if let Some(erase_size) = info.erase_size {
sector_size = sector_size.max(erase_size.get());
}
sector_size = sector_size.max(info.write_size.get());
let write_size = info.write_size.get();
sector_size = sector_size.div_ceil(write_size) * write_size;
if let Some(erase_size) = info.erase_size {
let erase_size = erase_size.get();
sector_size = sector_size.div_ceil(erase_size) * erase_size;
}
let sector_count = info.size / sector_size;
Self {
storage,
sector_size,
sector_count,
}
}
pub fn sector_size(&self) -> usize {
self.sector_size
}
pub fn sector_count(&self) -> usize {
self.sector_count
}
#[cfg(test)]
pub fn into_inner(self) -> S {
self.storage
}
pub fn read_sector(&mut self, sector_index: usize, buf: &mut [u8]) -> Result<(), S::Error> {
assert!(
sector_index < self.sector_count,
"sector index {sector_index} out of bounds (sector_count = {})",
self.sector_count
);
assert_eq!(
buf.len(),
self.sector_size,
"buffer length {} does not match sector size {}",
buf.len(),
self.sector_size
);
let offset = sector_index * self.sector_size;
self.storage.read(offset, buf)
}
pub fn write_sector(
&mut self,
sector_index: usize,
data: &[u8],
) -> Result<(), SectorError<S::Error>> {
assert!(
sector_index < self.sector_count,
"sector index {sector_index} out of bounds (sector_count = {})",
self.sector_count
);
assert_eq!(
data.len(),
self.sector_size,
"data length {} does not match sector size {}",
data.len(),
self.sector_size
);
let offset = sector_index * self.sector_size;
self.storage.erase(offset, self.sector_size)?;
self.storage.write(offset, data)?;
if !self.storage.verify(offset, data)? {
return Err(SectorError::VerificationFailed);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use crate::test_storage::TestStorage;
#[test]
fn sector_size_sram() {
let storage = TestStorage::new_sram(1024);
let sector_storage = SectorStorage::new(storage);
assert_eq!(sector_storage.sector_size(), 128);
assert_eq!(sector_storage.sector_count(), 8); }
#[test]
fn sector_size_flash_small_erase() {
let storage = TestStorage::new_flash(1024, 64, 4);
let sector_storage = SectorStorage::new(storage);
assert_eq!(sector_storage.sector_size(), 128);
assert_eq!(sector_storage.sector_count(), 8);
}
#[test]
fn sector_size_flash_large_erase() {
let storage = TestStorage::new_flash(4096, 512, 4);
let sector_storage = SectorStorage::new(storage);
assert_eq!(sector_storage.sector_size(), 512);
assert_eq!(sector_storage.sector_count(), 8); }
#[test]
fn read_write_sector() {
let storage = TestStorage::new_sram(1024);
let mut sector_storage = SectorStorage::new(storage);
let sector_size = sector_storage.sector_size();
let mut write_data = alloc::vec![0u8; sector_size];
write_data[0] = 0xAB;
write_data[1] = 0xCD;
write_data[sector_size - 1] = 0xEF;
sector_storage.write_sector(0, &write_data).unwrap();
let mut read_data = alloc::vec![0u8; sector_size];
sector_storage.read_sector(0, &mut read_data).unwrap();
assert_eq!(read_data, write_data);
}
#[test]
fn write_sector_erases_first() {
let storage = TestStorage::new_flash(1024, 128, 4);
let mut sector_storage = SectorStorage::new(storage);
let sector_size = sector_storage.sector_size();
let data1 = alloc::vec![0x11u8; sector_size];
sector_storage.write_sector(0, &data1).unwrap();
let data2 = alloc::vec![0x22u8; sector_size];
sector_storage.write_sector(0, &data2).unwrap();
let mut read_data = alloc::vec![0u8; sector_size];
sector_storage.read_sector(0, &mut read_data).unwrap();
assert_eq!(read_data, data2);
}
#[test]
fn multiple_sectors() {
let storage = TestStorage::new_sram(1024);
let mut sector_storage = SectorStorage::new(storage);
let sector_size = sector_storage.sector_size();
let sector_count = sector_storage.sector_count();
for i in 0..sector_count {
let mut data = alloc::vec![i as u8; sector_size];
data[0] = i as u8;
sector_storage.write_sector(i, &data).unwrap();
}
for i in 0..sector_count {
let mut data = alloc::vec![0u8; sector_size];
sector_storage.read_sector(i, &mut data).unwrap();
assert_eq!(data[0], i as u8);
}
}
#[test]
#[should_panic(expected = "sector index")]
fn read_sector_out_of_bounds() {
let storage = TestStorage::new_sram(1024);
let mut sector_storage = SectorStorage::new(storage);
let mut buf = alloc::vec![0u8; sector_storage.sector_size()];
let _ = sector_storage.read_sector(100, &mut buf);
}
#[test]
#[should_panic(expected = "sector index")]
fn write_sector_out_of_bounds() {
let storage = TestStorage::new_sram(1024);
let mut sector_storage = SectorStorage::new(storage);
let data = alloc::vec![0u8; sector_storage.sector_size()];
let _ = sector_storage.write_sector(100, &data);
}
#[test]
#[should_panic(expected = "buffer length")]
fn read_sector_wrong_buffer_size() {
let storage = TestStorage::new_sram(1024);
let mut sector_storage = SectorStorage::new(storage);
let mut buf = alloc::vec![0u8; 64]; let _ = sector_storage.read_sector(0, &mut buf);
}
#[test]
#[should_panic(expected = "data length")]
fn write_sector_wrong_data_size() {
let storage = TestStorage::new_sram(1024);
let mut sector_storage = SectorStorage::new(storage);
let data = alloc::vec![0u8; 64]; let _ = sector_storage.write_sector(0, &data);
}
}