Skip to content

Commit 1078baa

Browse files
committed
Rework NorFlash & Storage traits, and add RmwNorFlashStorage wrapper between them
1 parent 52a1352 commit 1078baa

File tree

4 files changed

+207
-149
lines changed

4 files changed

+207
-149
lines changed

Cargo.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ categories = ["embedded", "hardware-support", "no-std"]
1616

1717
[dependencies]
1818
nb = "1"
19-
no-std-net = "0.4"
20-
heapless = "^0.5"
19+
heapless = "^0.5"

src/iter.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Address, Region};
1+
use crate::Region;
22

33
/// Iterator producing block-region pairs, where each memory block maps to each
44
/// region.
@@ -9,7 +9,7 @@ where
99
{
1010
memory: &'a [u8],
1111
regions: I,
12-
base_address: Address,
12+
base_address: u32,
1313
}
1414

1515
/// Trait allowing us to automatically add an `overlaps` function to all iterators over [`Region`]
@@ -19,25 +19,29 @@ where
1919
I: Iterator<Item = R>,
2020
{
2121
/// Obtain an [`OverlapIterator`] over a subslice of `memory` that overlaps with the region in `self`
22-
fn overlaps(self, memory: &'a [u8], base_address: Address) -> OverlapIterator<R, I>;
22+
fn overlaps(self, memory: &'a [u8], base_address: u32) -> OverlapIterator<R, I>;
2323
}
2424

2525
impl<'a, R, I> Iterator for OverlapIterator<'a, R, I>
2626
where
2727
R: Region,
2828
I: Iterator<Item = R>,
2929
{
30-
type Item = (&'a [u8], R, Address);
30+
type Item = (&'a [u8], R, u32);
3131

3232
fn next(&mut self) -> Option<Self::Item> {
3333
while let Some(region) = self.regions.next() {
3434
// TODO: This might be possible to do in a smarter way?
3535
let mut block_range = (0..self.memory.len())
36-
.skip_while(|index| !region.contains(self.base_address + *index))
37-
.take_while(|index| region.contains(self.base_address + *index));
36+
.skip_while(|index| !region.contains(self.base_address + *index as u32))
37+
.take_while(|index| region.contains(self.base_address + *index as u32));
3838
if let Some(start) = block_range.next() {
3939
let end = block_range.last().unwrap_or(start) + 1;
40-
return Some((&self.memory[start..end], region, self.base_address + start));
40+
return Some((
41+
&self.memory[start..end],
42+
region,
43+
self.base_address + start as u32,
44+
));
4145
}
4246
}
4347
None
@@ -50,7 +54,7 @@ where
5054
R: Region,
5155
I: Iterator<Item = R>,
5256
{
53-
fn overlaps(self, memory: &'a [u8], base_address: Address) -> OverlapIterator<R, I> {
57+
fn overlaps(self, memory: &'a [u8], base_address: u32) -> OverlapIterator<R, I> {
5458
OverlapIterator {
5559
memory,
5660
regions: self,

src/lib.rs

+13-139
Original file line numberDiff line numberDiff line change
@@ -2,169 +2,43 @@
22
//!
33
//! Storage traits to allow on and off board storage devices to read and write
44
//! data.
5-
//!
6-
//! Implementation based on `Cuervo`s great work in
7-
//! https://www.ecorax.net/as-above-so-below-1/ and
8-
//! https://www.ecorax.net/as-above-so-below-2/
95
106
#![no_std]
117
#![deny(missing_docs)]
128
#![deny(unsafe_code)]
139

14-
use core::ops::{Add, Sub};
15-
use heapless::{consts::*, Vec};
16-
use nb;
17-
1810
/// Currently contains [`OverlapIterator`]
1911
pub mod iter;
20-
21-
/// An address denotes the read/write address of a single word.
22-
#[derive(Default, Copy, Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
23-
pub struct Address(pub u32);
24-
25-
impl Add<usize> for Address {
26-
type Output = Self;
27-
28-
fn add(self, rhs: usize) -> Self::Output {
29-
Address(self.0 + rhs as u32)
30-
}
31-
}
32-
33-
impl Add<isize> for Address {
34-
type Output = Self;
35-
36-
fn add(self, rhs: isize) -> Self::Output {
37-
Address((self.0 as isize + rhs) as u32)
38-
}
39-
}
40-
impl Sub<usize> for Address {
41-
type Output = Self;
42-
43-
fn sub(self, rhs: usize) -> Self::Output {
44-
Address(self.0 - rhs as u32)
45-
}
46-
}
47-
48-
impl Sub<isize> for Address {
49-
type Output = Self;
50-
51-
fn sub(self, rhs: isize) -> Self::Output {
52-
Address((self.0 as isize - rhs) as u32)
53-
}
54-
}
55-
56-
impl Sub<Address> for Address {
57-
type Output = Self;
58-
59-
fn sub(self, rhs: Address) -> Self::Output {
60-
Address(self.0 - rhs.0)
61-
}
62-
}
12+
/// Technology specific traits for NOR Flashes
13+
pub mod nor_flash;
6314

6415
/// A region denotes a contiguous piece of memory between two addresses.
6516
pub trait Region {
6617
/// Check if `address` is contained in the region of `Self`
67-
fn contains(&self, address: Address) -> bool;
18+
fn contains(&self, address: u32) -> bool;
6819
}
6920

7021
/// Transparent storage trait
71-
pub trait ReadWriteStorage {
22+
pub trait Storage {
7223
/// An enumeration of storage errors
7324
type Error;
7425

7526
/// Read a slice of data from the storage peripheral, starting the read
7627
/// operation at the given address, and reading until end address
7728
/// (`self.range().1`) or buffer length, whichever comes first.
78-
fn try_read(&mut self, address: Address, bytes: &mut [u8]) -> nb::Result<(), Self::Error>;
29+
fn try_read(&mut self, address: u32, bytes: &mut [u8]) -> Result<(), Self::Error>;
7930

8031
/// Write a slice of data to the storage peripheral, starting the write
8132
/// operation at the given address.
82-
fn try_write(&mut self, address: Address, bytes: &[u8]) -> nb::Result<(), Self::Error>;
83-
84-
/// The range of possible addresses within the peripheral.
8533
///
86-
/// (start_addr, end_addr)
87-
fn range(&self) -> (Address, Address);
88-
89-
/// Erase the given storage range, clearing all data within `[from..to]`.
90-
fn try_erase(&mut self, from: Address, to: Address) -> nb::Result<(), Self::Error>;
91-
}
92-
93-
/// NOR flash region trait.
94-
pub trait NorFlashRegion {
95-
/// The range of possible addresses within the region.
34+
/// **NOTE:**
35+
/// This function will automatically erase any pages necessary to write the given data,
36+
/// and might as such do RMW operations at an undesirable performance impact.
9637
///
97-
/// (start_addr, end_addr)
98-
fn range(&self) -> (Address, Address);
99-
/// Maximum number of bytes that can be written at once.
100-
fn page_size(&self) -> usize;
101-
/// List of avalable erase sizes in this region.
102-
/// Should be sorted in ascending order.
103-
/// Currently limited to 5 sizes, but could be increased if necessary.
104-
fn erase_sizes(&self) -> Vec<usize, U5>;
105-
}
106-
107-
/// Blanket implementation for all types implementing [`NorFlashRegion`]
108-
impl<T: NorFlashRegion> Region for T {
109-
fn contains(&self, address: Address) -> bool {
110-
let (start, end) = self.range();
111-
address.0 >= start.0 && address.0 < end.0
112-
}
113-
}
114-
115-
/// NOR flash storage trait
116-
pub trait NorFlash {
117-
/// An enumeration of storage errors
118-
type Error;
119-
/// Region type
120-
type Region: NorFlashRegion;
121-
122-
/// Read a slice of data from the storage peripheral, starting the read
123-
/// operation at the given address, and reading until end address
124-
/// (`self.range().1`) or buffer length, whichever comes first.
125-
fn try_read(&mut self, address: Address, bytes: &mut [u8]) -> nb::Result<(), Self::Error>;
38+
/// CONSIDERATIONS:
39+
/// - Should the address here be normalized (always start from zero?)
40+
fn try_write(&mut self, address: u32, bytes: &[u8]) -> Result<(), Self::Error>;
12641

127-
/// Write a slice of data to the storage peripheral, starting the write
128-
/// operation at the given address.
129-
///
130-
/// Since this is done on a NOR flash all bytes are anded with the current
131-
/// content in the flash. This means no 0s can to turned into 1s this way.
132-
fn try_write(&mut self, address: Address, bytes: &[u8]) -> nb::Result<(), Self::Error>;
133-
134-
/// Erase the given storage range, clearing all data within `[from..to]`.
135-
/// The given range will contain all 1s afterwards.
136-
///
137-
/// This should return an error if the range is not aligned to a proper
138-
/// erase resolution
139-
fn try_erase(&mut self, from: Address, to: Address) -> nb::Result<(), Self::Error>;
140-
141-
/// Get all distinct memory reagions. These must not overlap, but can be disjoint.
142-
/// Most chips will return a single region, but some chips have regions with
143-
/// different erase sizes.
144-
/// Currently limited to 4 regions, but could be increased if necessary
145-
fn regions(&self) -> Vec<Self::Region, U4>;
146-
}
147-
148-
/// Marker trait for NOR flashes with uniform erase and page sizes across the whole
149-
/// address range
150-
pub trait UniformNorFlash {}
151-
152-
/// Blanket implementation for all types implementing [`NorFlash`] and [`UniformNorFlash`]
153-
impl<T: NorFlash + UniformNorFlash> NorFlashRegion for T {
154-
/// The range of possible addresses within the peripheral.
155-
///
156-
/// (start_addr, end_addr)
157-
fn range(&self) -> (Address, Address) {
158-
self.regions()[0].range()
159-
}
160-
/// Maximum number of bytes that can be written at once.
161-
fn page_size(&self) -> usize {
162-
self.regions()[0].page_size()
163-
}
164-
/// List of avalable erase sizes in this region.
165-
/// Should be sorted in ascending order.
166-
/// Currently limited to 5 sizes, but could be increased if necessary.
167-
fn erase_sizes(&self) -> Vec<usize, U5> {
168-
self.regions()[0].erase_sizes()
169-
}
42+
/// The capacity of the storage peripheral in bytes.
43+
fn capacity(&self) -> u32;
17044
}

0 commit comments

Comments
 (0)