1use crate::{iter::IterableByOverlaps, ReadStorage, Region, Storage};
23/// Read only NOR flash trait.
4pub trait ReadNorFlash {
5/// An enumeration of storage errors
6type Error;
78/// The minumum number of bytes the storage peripheral can read
9const READ_SIZE: usize;
1011/// Read a slice of data from the storage peripheral, starting the read
12 /// operation at the given address offset, and reading `bytes.len()` bytes.
13 ///
14 /// This should throw an error in case `bytes.len()` will be larger than
15 /// the peripheral end address.
16fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error>;
1718/// The capacity of the peripheral in bytes.
19fn capacity(&self) -> usize;
20}
2122/// NOR flash trait.
23pub trait NorFlash: ReadNorFlash {
24/// The minumum number of bytes the storage peripheral can write
25const WRITE_SIZE: usize;
2627/// The minumum number of bytes the storage peripheral can erase
28const ERASE_SIZE: usize;
2930/// Erase the given storage range, clearing all data within `[from..to]`.
31 /// The given range will contain all 1s afterwards.
32 ///
33 /// This should return an error if the range is not aligned to a proper
34 /// erase resolution
35 /// If power is lost during erase, contents of the page are undefined.
36 /// `from` and `to` must both be multiples of `ERASE_SIZE` and `from` <= `to`.
37fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error>;
3839/// If power is lost during write, the contents of the written words are undefined,
40 /// but the rest of the page is guaranteed to be unchanged.
41 /// It is not allowed to write to the same word twice.
42 /// `offset` and `bytes.len()` must both be multiples of `WRITE_SIZE`.
43fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error>;
44}
4546/// Marker trait for NorFlash relaxing the restrictions on `write`.
47///
48/// Writes to the same word twice are now allowed. The result is the logical AND of the
49/// previous data and the written data. That is, it is only possible to change 1 bits to 0 bits.
50///
51/// If power is lost during write:
52/// - Bits that were 1 on flash and are written to 1 are guaranteed to stay as 1
53/// - Bits that were 1 on flash and are written to 0 are undefined
54/// - Bits that were 0 on flash are guaranteed to stay as 0
55/// - Rest of the bits in the page are guaranteed to be unchanged
56pub trait MultiwriteNorFlash: NorFlash {}
5758struct Page {
59pub start: u32,
60pub size: usize,
61}
6263impl Page {
64fn new(index: u32, size: usize) -> Self {
65Self {
66 start: index * size as u32,
67 size,
68 }
69 }
7071/// The end address of the page
72const fn end(&self) -> u32 {
73self.start + self.size as u32
74 }
75}
7677impl Region for Page {
78/// Checks if an address offset is contained within the page
79fn contains(&self, address: u32) -> bool {
80 (self.start <= address) && (self.end() > address)
81 }
82}
8384///
85pub struct RmwNorFlashStorage<'a, S> {
86 storage: S,
87 merge_buffer: &'a mut [u8],
88}
8990impl<'a, S> RmwNorFlashStorage<'a, S>
91where
92S: NorFlash,
93{
94/// Instantiate a new generic `Storage` from a `NorFlash` peripheral
95 ///
96 /// **NOTE** This will panic if the provided merge buffer,
97 /// is smaller than the erase size of the flash peripheral
98pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self {
99if merge_buffer.len() < S::ERASE_SIZE {
100panic!("Merge buffer is too small");
101 }
102103Self {
104 storage: nor_flash,
105 merge_buffer,
106 }
107 }
108}
109110impl<'a, S> ReadStorage for RmwNorFlashStorage<'a, S>
111where
112S: ReadNorFlash,
113{
114type Error = S::Error;
115116fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
117// Nothing special to be done for reads
118self.storage.read(offset, bytes)
119 }
120121fn capacity(&self) -> usize {
122self.storage.capacity()
123 }
124}
125126impl<'a, S> Storage for RmwNorFlashStorage<'a, S>
127where
128S: NorFlash,
129{
130fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
131// Perform read/modify/write operations on the byte slice.
132let last_page = self.storage.capacity() / S::ERASE_SIZE;
133134// `data` is the part of `bytes` contained within `page`,
135 // and `addr` in the address offset of `page` + any offset into the page as requested by `address`
136for (data, page, addr) in (0..last_page as u32)
137 .map(move |i| Page::new(i, S::ERASE_SIZE))
138 .overlaps(bytes, offset)
139 {
140let offset_into_page = addr.saturating_sub(page.start) as usize;
141142self.storage
143 .read(page.start, &mut self.merge_buffer[..S::ERASE_SIZE])?;
144145// If we cannot write multiple times to the same page, we will have to erase it
146self.storage.erase(page.start, page.end())?;
147self.merge_buffer[..S::ERASE_SIZE]
148 .iter_mut()
149 .skip(offset_into_page)
150 .zip(data)
151 .for_each(|(byte, input)| *byte = *input);
152self.storage
153 .write(page.start, &self.merge_buffer[..S::ERASE_SIZE])?;
154 }
155Ok(())
156 }
157}
158159///
160pub struct RmwMultiwriteNorFlashStorage<'a, S> {
161 storage: S,
162 merge_buffer: &'a mut [u8],
163}
164165impl<'a, S> RmwMultiwriteNorFlashStorage<'a, S>
166where
167S: MultiwriteNorFlash,
168{
169/// Instantiate a new generic `Storage` from a `NorFlash` peripheral
170 ///
171 /// **NOTE** This will panic if the provided merge buffer,
172 /// is smaller than the erase size of the flash peripheral
173pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self {
174if merge_buffer.len() < S::ERASE_SIZE {
175panic!("Merge buffer is too small");
176 }
177178Self {
179 storage: nor_flash,
180 merge_buffer,
181 }
182 }
183}
184185impl<'a, S> ReadStorage for RmwMultiwriteNorFlashStorage<'a, S>
186where
187S: ReadNorFlash,
188{
189type Error = S::Error;
190191fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
192// Nothing special to be done for reads
193self.storage.read(offset, bytes)
194 }
195196fn capacity(&self) -> usize {
197self.storage.capacity()
198 }
199}
200201impl<'a, S> Storage for RmwMultiwriteNorFlashStorage<'a, S>
202where
203S: MultiwriteNorFlash,
204{
205fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
206// Perform read/modify/write operations on the byte slice.
207let last_page = self.storage.capacity() / S::ERASE_SIZE;
208209// `data` is the part of `bytes` contained within `page`,
210 // and `addr` in the address offset of `page` + any offset into the page as requested by `address`
211for (data, page, addr) in (0..last_page as u32)
212 .map(move |i| Page::new(i, S::ERASE_SIZE))
213 .overlaps(bytes, offset)
214 {
215let offset_into_page = addr.saturating_sub(page.start) as usize;
216217self.storage
218 .read(page.start, &mut self.merge_buffer[..S::ERASE_SIZE])?;
219220let rhs = &self.merge_buffer[offset_into_page..S::ERASE_SIZE];
221let is_subset = data.iter().zip(rhs.iter()).all(|(a, b)| *a & *b == *a);
222223// Check if we can write the data block directly, under the limitations imposed by NorFlash:
224 // - We can only change 1's to 0's
225if is_subset {
226// Use `merge_buffer` as allocation for padding `data` to `WRITE_SIZE`
227let offset = addr as usize % S::WRITE_SIZE;
228let aligned_end = data.len() % S::WRITE_SIZE + offset + data.len();
229self.merge_buffer[..aligned_end].fill(0xff);
230self.merge_buffer[offset..offset + data.len()].copy_from_slice(data);
231self.storage
232 .write(addr - offset as u32, &self.merge_buffer[..aligned_end])?;
233 } else {
234self.storage.erase(page.start, page.end())?;
235self.merge_buffer[..S::ERASE_SIZE]
236 .iter_mut()
237 .skip(offset_into_page)
238 .zip(data)
239 .for_each(|(byte, input)| *byte = *input);
240self.storage
241 .write(page.start, &self.merge_buffer[..S::ERASE_SIZE])?;
242 }
243 }
244Ok(())
245 }
246}