use alloc::{vec, vec::Vec};
use core::ops::Range;
#[cfg(feature = "defmt")]
use defmt::{Format, panic};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
use embedded_storage_async::nor_flash::{MultiwriteNorFlash, NorFlash};
use generic_array::{ArrayLength, GenericArray};
use sequential_storage::cache::NoCache;
use sequential_storage::map::{fetch_item, remove_item, store_item};
use typenum::Unsigned;
const ENTRY_TAG_SIZE: usize = 4;
pub trait Entry {
type Size: ArrayLength;
const TAG: [u8; ENTRY_TAG_SIZE];
fn from_bytes(bytes: &GenericArray<u8, Self::Size>) -> Option<Self>
where
Self: Sized;
fn to_bytes(&self) -> GenericArray<u8, Self::Size>;
}
#[cfg_attr(feature = "defmt", derive(Format))]
pub enum Error<E> {
Flash(E),
FullStorage,
Corrupted,
EntryTooBig,
}
impl<E> Error<E> {
fn from_sequential_storage(error: sequential_storage::Error<E>) -> Self {
match error {
sequential_storage::Error::Storage { value } => Self::Flash(value),
sequential_storage::Error::FullStorage => Self::FullStorage,
sequential_storage::Error::Corrupted {} => Self::Corrupted,
sequential_storage::Error::BufferTooBig => {
panic!("Unexpected storage error: BufferTooBig");
}
sequential_storage::Error::BufferTooSmall(v) => {
panic!("Unexpected storage error: BufferTooSmall({})", v);
}
sequential_storage::Error::SerializationError(v) => {
panic!("Unexpected storage error: SerializationError({})", v);
}
sequential_storage::Error::ItemTooBig => Self::EntryTooBig,
_ => {
panic!("Unexpected storage error: Other");
}
}
}
}
trait NorFlashExt {
const WORD_SIZE: usize;
}
impl<F: NorFlash> NorFlashExt for F {
const WORD_SIZE: usize = if Self::WRITE_SIZE > Self::READ_SIZE {
Self::WRITE_SIZE
} else {
Self::READ_SIZE
};
}
const fn round_up_to_word_size<F: NorFlash>(value: usize) -> usize {
let remainder = value % F::WORD_SIZE;
value + F::WORD_SIZE - remainder
}
pub struct Storage<F> {
flash: Mutex<CriticalSectionRawMutex, F>,
flash_range: Range<u32>,
}
impl<F: MultiwriteNorFlash> Storage<F> {
pub fn new(flash: F, flash_range: Range<u32>) -> Self {
Self {
flash: Mutex::new(flash),
flash_range,
}
}
fn create_buffer<E: Entry>() -> Vec<u8> {
let buf_len = round_up_to_word_size::<F>(E::Size::USIZE + ENTRY_TAG_SIZE);
vec![0; buf_len]
}
pub async fn remove<E: Entry>(&self) -> Result<(), Error<F::Error>> {
let mut buf = Self::create_buffer::<E>();
remove_item(
&mut *self.flash.lock().await,
self.flash_range.clone(),
&mut NoCache::new(),
&mut buf,
&E::TAG,
)
.await
.map_err(Error::from_sequential_storage)
}
pub async fn store<E: Entry>(&self, entry: &E) -> Result<(), Error<F::Error>> {
let mut buf = Self::create_buffer::<E>();
let value_bytes = entry.to_bytes();
store_item(
&mut *self.flash.lock().await,
self.flash_range.clone(),
&mut NoCache::new(),
&mut buf,
&E::TAG,
&value_bytes.as_ref(),
)
.await
.map_err(Error::from_sequential_storage)
}
pub async fn fetch<E: Entry>(&self) -> Result<Option<E>, Error<F::Error>> {
let mut buf = Self::create_buffer::<E>();
let data: Option<&[u8]> = fetch_item(
&mut *self.flash.lock().await,
self.flash_range.clone(),
&mut NoCache::new(),
&mut buf,
&E::TAG,
)
.await
.map_err(Error::from_sequential_storage)?;
Ok(data.and_then(|data| {
let data = GenericArray::try_from_slice(data).unwrap();
E::from_bytes(data)
}))
}
}