use crate::error::BackendError;
use core::fmt::Debug;
#[derive(Debug, Clone, Copy)]
pub struct FlashGeometry {
pub erase_block_size: u32,
pub write_page_size: u32,
pub total_blocks: u32,
pub max_erase_cycles: u32,
}
impl FlashGeometry {
#[inline]
pub fn total_capacity(&self) -> u64 {
u64::from(self.erase_block_size) * u64::from(self.total_blocks)
}
#[inline]
pub fn pages_per_block(&self) -> u32 {
if self.write_page_size == 0 {
return 0;
}
self.erase_block_size / self.write_page_size
}
#[allow(clippy::cast_possible_truncation)]
pub fn reserved_blocks(&self) -> u32 {
if self.erase_block_size == 0 {
return 0;
}
let metadata_size = 4u64 * u64::from(self.total_blocks) + 4u64 * u64::from(self.total_blocks) + u64::from(self.total_blocks.div_ceil(8)) + 64; let ebs = u64::from(self.erase_block_size);
let blocks_per_slot = metadata_size.div_ceil(ebs) as u32;
let journal_blocks = blocks_per_slot * 2; let spare_blocks = 2u32; journal_blocks + spare_blocks
}
const COW_HEADROOM_BLOCKS: u32 = 2;
pub fn logical_block_count(&self) -> u32 {
self.total_blocks
.saturating_sub(self.reserved_blocks())
.saturating_sub(Self::COW_HEADROOM_BLOCKS)
}
}
pub trait FlashHardware: 'static + Debug + Send + Sync {
fn read(&self, offset: u64, buf: &mut [u8]) -> core::result::Result<(), BackendError>;
fn write_page(&self, offset: u64, data: &[u8]) -> core::result::Result<(), BackendError>;
fn erase_block(&self, block_index: u32) -> core::result::Result<(), BackendError>;
fn is_bad_block(&self, block_index: u32) -> core::result::Result<bool, BackendError>;
fn mark_bad_block(&self, block_index: u32) -> core::result::Result<(), BackendError>;
fn geometry(&self) -> FlashGeometry;
fn sync(&self) -> core::result::Result<(), BackendError>;
}