use embedded_storage::Region;
use embedded_storage::iter::IterableByOverlaps;
pub use embedded_storage::nor_flash::{ErrorType, NorFlashError, NorFlashErrorKind};
use crate::{ReadStorage, Storage};
pub trait ReadNorFlash: ErrorType {
const READ_SIZE: usize;
async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error>;
fn capacity(&self) -> usize;
}
pub trait NorFlash: ReadNorFlash {
const WRITE_SIZE: usize;
const ERASE_SIZE: usize;
async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error>;
async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error>;
}
impl<T: ReadNorFlash> ReadNorFlash for &mut T {
const READ_SIZE: usize = T::READ_SIZE;
async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
T::read(self, offset, bytes).await
}
fn capacity(&self) -> usize {
T::capacity(self)
}
}
impl<T: NorFlash> NorFlash for &mut T {
const WRITE_SIZE: usize = T::WRITE_SIZE;
const ERASE_SIZE: usize = T::ERASE_SIZE;
async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
T::erase(self, from, to).await
}
async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
T::write(self, offset, bytes).await
}
}
pub trait MultiwriteNorFlash: NorFlash {}
impl<T: MultiwriteNorFlash> MultiwriteNorFlash for &mut T {}
struct Page {
pub start: u32,
pub size: usize,
}
impl Page {
fn new(index: u32, size: usize) -> Self {
Self {
start: index * size as u32,
size,
}
}
const fn end(&self) -> u32 {
self.start + self.size as u32
}
}
impl Region for Page {
fn contains(&self, address: u32) -> bool {
(self.start <= address) && (self.end() > address)
}
}
#[derive(Debug)]
pub struct RmwNorFlashStorage<'a, S> {
storage: S,
merge_buffer: &'a mut [u8],
}
impl<'a, S> RmwNorFlashStorage<'a, S>
where
S: NorFlash,
{
pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self {
if merge_buffer.len() < S::ERASE_SIZE {
panic!("Merge buffer is too small");
}
Self {
storage: nor_flash,
merge_buffer,
}
}
pub fn into_inner(self) -> S {
self.storage
}
}
impl<'a, S> ReadStorage for RmwNorFlashStorage<'a, S>
where
S: ReadNorFlash,
{
type Error = S::Error;
async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
self.storage.read(offset, bytes).await
}
fn capacity(&self) -> usize {
self.storage.capacity()
}
}
impl<'a, S> Storage for RmwNorFlashStorage<'a, S>
where
S: NorFlash,
{
async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
let last_page = self.storage.capacity() / S::ERASE_SIZE;
for (data, page, addr) in (0..last_page as u32)
.map(move |i| Page::new(i, S::ERASE_SIZE))
.overlaps(bytes, offset)
{
let offset_into_page = addr.saturating_sub(page.start) as usize;
self.storage
.read(page.start, &mut self.merge_buffer[..S::ERASE_SIZE])
.await?;
self.storage.erase(page.start, page.end()).await?;
self.merge_buffer[..S::ERASE_SIZE]
.iter_mut()
.skip(offset_into_page)
.zip(data)
.for_each(|(byte, input)| *byte = *input);
self.storage
.write(page.start, &self.merge_buffer[..S::ERASE_SIZE])
.await?;
}
Ok(())
}
}
pub struct RmwMultiwriteNorFlashStorage<'a, S> {
storage: S,
merge_buffer: &'a mut [u8],
}
impl<'a, S> RmwMultiwriteNorFlashStorage<'a, S>
where
S: MultiwriteNorFlash,
{
pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self {
if merge_buffer.len() < S::ERASE_SIZE {
panic!("Merge buffer is too small");
}
Self {
storage: nor_flash,
merge_buffer,
}
}
pub fn into_inner(self) -> S {
self.storage
}
}
impl<'a, S> ReadStorage for RmwMultiwriteNorFlashStorage<'a, S>
where
S: ReadNorFlash,
{
type Error = S::Error;
async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
self.storage.read(offset, bytes).await
}
fn capacity(&self) -> usize {
self.storage.capacity()
}
}
impl<'a, S> Storage for RmwMultiwriteNorFlashStorage<'a, S>
where
S: MultiwriteNorFlash,
{
async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
let last_page = self.storage.capacity() / S::ERASE_SIZE;
for (data, page, addr) in (0..last_page as u32)
.map(move |i| Page::new(i, S::ERASE_SIZE))
.overlaps(bytes, offset)
{
let offset_into_page = addr.saturating_sub(page.start) as usize;
self.storage
.read(page.start, &mut self.merge_buffer[..S::ERASE_SIZE])
.await?;
let rhs = &self.merge_buffer[offset_into_page..S::ERASE_SIZE];
let is_subset = data.iter().zip(rhs.iter()).all(|(a, b)| *a & *b == *a);
if is_subset {
let offset = addr as usize % S::WRITE_SIZE;
let aligned_end = data.len() % S::WRITE_SIZE + offset + data.len();
self.merge_buffer[..aligned_end].fill(0xff);
self.merge_buffer[offset..offset + data.len()].copy_from_slice(data);
self.storage
.write(addr - offset as u32, &self.merge_buffer[..aligned_end])
.await?;
} else {
self.storage.erase(page.start, page.end()).await?;
self.merge_buffer[..S::ERASE_SIZE]
.iter_mut()
.skip(offset_into_page)
.zip(data)
.for_each(|(byte, input)| *byte = *input);
self.storage
.write(page.start, &self.merge_buffer[..S::ERASE_SIZE])
.await?;
}
}
Ok(())
}
}