Skip to content

Commit

Permalink
Make RmwNorFlashStorage::new take a mutable merge_buffer, that must b…
Browse files Browse the repository at this point in the history
…e atleast EraseSize long. Introduce RmwMultiwriteNorFlashStorage
  • Loading branch information
MathiasKoch committed Mar 18, 2021
1 parent 5943283 commit deec732
Showing 1 changed file with 92 additions and 66 deletions.
158 changes: 92 additions & 66 deletions src/nor_flash.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{iter::IterableByOverlaps, ReadStorage, Region, Storage};
use crate::{ReadStorage, Region, Storage, iter::{IterableByOverlaps, OverlapIterator}};

/// Read only NOR flash trait.
pub trait ReadNorFlash {
Expand Down Expand Up @@ -77,117 +77,143 @@ impl Page {
}

impl Region for Page {
/// Checks if an address offset is contained within the page
fn contains(&self, address: u32) -> bool {
(self.start <= address) && (self.end() > address)
}
}

///
pub struct RmwNorFlashStorage<S>(S);
pub struct RmwNorFlashStorage<'a, S> {
storage: S,
merge_buffer: &'a mut [u8]
}

impl<S> RmwNorFlashStorage<S> {
impl<'a, S> RmwNorFlashStorage<'a, S>
where
S: NorFlash,
{
/// Instantiate a new generic `Storage` from a `NorFlash` peripheral
pub fn new(nor_flash: S) -> Self {
Self(nor_flash)
///
/// **NOTE** This will panic if the provided merge buffer,
/// is smaller than the erase size of the flash peripheral
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
}
}
}

impl<S> ReadStorage for RmwNorFlashStorage<S>
impl<'a, S> ReadStorage for RmwNorFlashStorage<'a, S>
where
S: ReadNorFlash,
{
type Error = S::Error;

fn try_read(&mut self, address: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
// Nothing special to be done for reads
self.0.try_read(address, bytes)
self.storage.try_read(address, bytes)
}

fn capacity(&self) -> usize {
self.0.capacity()
self.storage.capacity()
}
}

impl<S> Storage for RmwNorFlashStorage<S>
impl<'a, S> Storage for RmwNorFlashStorage<'a, S>
where
S: NorFlash,
// [u8; S::ERASE_SIZE]: Sized,
{
fn try_write(&mut self, address: u32, bytes: &[u8]) -> Result<(), Self::Error> {
// Perform read/modify/write operations on the byte slice.
let last_page = (self.0.capacity() / S::ERASE_SIZE) - 1;
let last_page = (self.storage.capacity() / S::ERASE_SIZE) - 1;

// `data` is the part of `bytes` contained within `page`,
// and `addr` in the address offset of `page` + any offset into the page as requested by `address`
for (data, page, addr) in (0..last_page as u32)
.map(move |i| Page::new(i, S::ERASE_SIZE))
.overlaps(bytes, address)
{
let merge_buffer = &mut [0u8; 2048];
let offset_into_page = addr.saturating_sub(page.start) as usize;

self.try_read(page.start, merge_buffer)?;
self.storage.try_read(page.start, self.merge_buffer)?;

// If we cannot write multiple times to the same page, we will have to erase it
self.0.try_erase(page.start, page.end())?;
merge_buffer
self.storage.try_erase(page.start, page.end())?;
self.merge_buffer
.iter_mut()
.skip(offset_into_page)
.zip(data)
.for_each(|(byte, input)| *byte = *input);
self.0.try_write(page.start, merge_buffer)?;
self.storage.try_write(page.start, self.merge_buffer)?;
}
Ok(())
}
}

// FIXME: Requires specialization to take advantage of MultiwriteNorFlash?
// impl<S: MultiwriteNorFlash> Storage for RmwNorFlashStorage<S> {
// type Error = S::Error;

// fn try_read(&mut self, address: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
// // Nothing special to be done for reads
// self.0.try_read(address, bytes)
// }

// fn try_write(&mut self, address: u32, bytes: &[u8]) -> Result<(), Self::Error> {
// // Perform read/modify/write operations on the byte slice.
// let erase_size = self.0.erase_size();
// let last_page = (self.0.capacity() / erase_size) - 1;

// // `data` is the part of `bytes` contained within `page`,
// // and `addr` in the address offset of `page` + any offset into the page as requested by `address`
// for (data, page, addr) in (0..last_page)
// .map(move |i| Page::new(i, erase_size))
// .overlaps(bytes, address)
// {
// let merge_buffer = &mut [0u8; MAX_PAGE_SIZE][0..erase_size as usize];
// let offset_into_page = addr.saturating_sub(page.start) as usize;

// self.try_read(page.start, merge_buffer)?;

// let rhs = &merge_buffer[offset_into_page..];
// let is_subset =
// data.len() < rhs.len() && data.iter().zip(rhs.iter()).all(|(a, b)| (*a | *b) == *b);

// // Check if we can write the data block directly, under the limitations imposed by NorFlash:
// // - We can only change 1's to 0's
// if is_subset {
// self.0.try_write(addr, data)?;
// } else {
// self.0.try_erase(page.start, page.end())?;
// merge_buffer
// .iter_mut()
// .skip(offset_into_page)
// .zip(data)
// .for_each(|(byte, input)| *byte = *input);
// self.0.try_write(page.start, merge_buffer)?;
// }
// }
// Ok(())
// }

// fn capacity(&self) -> u32 {
// self.0.capacity()
// }
// }
///
pub struct RmwMultiwriteNorFlashStorage<'a, S> {
storage: S,
merge_buffer: &'a mut [u8]
}

impl<'a, S> ReadStorage for RmwMultiwriteNorFlashStorage<'a, S>
where
S: ReadNorFlash,
{
type Error = S::Error;

fn try_read(&mut self, address: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
// Nothing special to be done for reads
self.storage.try_read(address, bytes)
}

fn capacity(&self) -> usize {
self.storage.capacity()
}
}

impl<'a, S> Storage for RmwMultiwriteNorFlashStorage<'a, S>
where
S: NorFlash,
{
fn try_write(&mut self, address: u32, bytes: &[u8]) -> Result<(), Self::Error> {
// Perform read/modify/write operations on the byte slice.
let last_page = (self.storage.capacity() / S::ERASE_SIZE) - 1;

// `data` is the part of `bytes` contained within `page`,
// and `addr` in the address offset of `page` + any offset into the page as requested by `address`
for (data, page, addr) in (0..last_page as u32)
.map(move |i| Page::new(i, S::ERASE_SIZE))
.overlaps(bytes, address)
{
let offset_into_page = addr.saturating_sub(page.start) as usize;

self.storage.try_read(page.start, self.merge_buffer)?;

let rhs = &self.merge_buffer[offset_into_page..];
let is_subset =
data.len() < rhs.len() && data.iter().zip(rhs.iter()).all(|(a, b)| (*a | *b) == *b);

// Check if we can write the data block directly, under the limitations imposed by NorFlash:
// - We can only change 1's to 0's
if is_subset {
self.storage.try_write(addr, data)?;
} else {
self.storage.try_erase(page.start, page.end())?;
self.merge_buffer
.iter_mut()
.skip(offset_into_page)
.zip(data)
.for_each(|(byte, input)| *byte = *input);
self.storage.try_write(page.start, self.merge_buffer)?;
}
}
Ok(())
}
}

0 comments on commit deec732

Please sign in to comment.