|
1 |
| -use crate::{iter::IterableByOverlaps, ReadStorage, Region, Storage}; |
| 1 | +use crate::{ |
| 2 | + iter::{IterableByOverlaps, OverlapIterator}, |
| 3 | + ReadStorage, Region, Storage, |
| 4 | +}; |
2 | 5 |
|
3 | 6 | /// Read only NOR flash trait.
|
4 | 7 | pub trait ReadNorFlash {
|
@@ -77,117 +80,143 @@ impl Page {
|
77 | 80 | }
|
78 | 81 |
|
79 | 82 | impl Region for Page {
|
| 83 | + /// Checks if an address offset is contained within the page |
80 | 84 | fn contains(&self, address: u32) -> bool {
|
81 | 85 | (self.start <= address) && (self.end() > address)
|
82 | 86 | }
|
83 | 87 | }
|
84 | 88 |
|
85 | 89 | ///
|
86 |
| -pub struct RmwNorFlashStorage<S>(S); |
| 90 | +pub struct RmwNorFlashStorage<'a, S> { |
| 91 | + storage: S, |
| 92 | + merge_buffer: &'a mut [u8], |
| 93 | +} |
87 | 94 |
|
88 |
| -impl<S> RmwNorFlashStorage<S> { |
| 95 | +impl<'a, S> RmwNorFlashStorage<'a, S> |
| 96 | +where |
| 97 | + S: NorFlash, |
| 98 | +{ |
89 | 99 | /// Instantiate a new generic `Storage` from a `NorFlash` peripheral
|
90 |
| - pub fn new(nor_flash: S) -> Self { |
91 |
| - Self(nor_flash) |
| 100 | + /// |
| 101 | + /// **NOTE** This will panic if the provided merge buffer, |
| 102 | + /// is smaller than the erase size of the flash peripheral |
| 103 | + pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self { |
| 104 | + if merge_buffer.len() < S::ERASE_SIZE { |
| 105 | + panic!("Merge buffer is too small"); |
| 106 | + } |
| 107 | + |
| 108 | + Self { |
| 109 | + storage: nor_flash, |
| 110 | + merge_buffer, |
| 111 | + } |
92 | 112 | }
|
93 | 113 | }
|
94 | 114 |
|
95 |
| -impl<S> ReadStorage for RmwNorFlashStorage<S> |
| 115 | +impl<'a, S> ReadStorage for RmwNorFlashStorage<'a, S> |
96 | 116 | where
|
97 | 117 | S: ReadNorFlash,
|
98 | 118 | {
|
99 | 119 | type Error = S::Error;
|
100 | 120 |
|
101 | 121 | fn try_read(&mut self, address: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
102 | 122 | // Nothing special to be done for reads
|
103 |
| - self.0.try_read(address, bytes) |
| 123 | + self.storage.try_read(address, bytes) |
104 | 124 | }
|
105 | 125 |
|
106 | 126 | fn capacity(&self) -> usize {
|
107 |
| - self.0.capacity() |
| 127 | + self.storage.capacity() |
108 | 128 | }
|
109 | 129 | }
|
110 | 130 |
|
111 |
| -impl<S> Storage for RmwNorFlashStorage<S> |
| 131 | +impl<'a, S> Storage for RmwNorFlashStorage<'a, S> |
112 | 132 | where
|
113 | 133 | S: NorFlash,
|
114 |
| - // [u8; S::ERASE_SIZE]: Sized, |
115 | 134 | {
|
116 | 135 | fn try_write(&mut self, address: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
117 | 136 | // Perform read/modify/write operations on the byte slice.
|
118 |
| - let last_page = (self.0.capacity() / S::ERASE_SIZE) - 1; |
| 137 | + let last_page = (self.storage.capacity() / S::ERASE_SIZE) - 1; |
119 | 138 |
|
120 | 139 | // `data` is the part of `bytes` contained within `page`,
|
121 | 140 | // and `addr` in the address offset of `page` + any offset into the page as requested by `address`
|
122 | 141 | for (data, page, addr) in (0..last_page as u32)
|
123 | 142 | .map(move |i| Page::new(i, S::ERASE_SIZE))
|
124 | 143 | .overlaps(bytes, address)
|
125 | 144 | {
|
126 |
| - let merge_buffer = &mut [0u8; 2048]; |
127 | 145 | let offset_into_page = addr.saturating_sub(page.start) as usize;
|
128 | 146 |
|
129 |
| - self.try_read(page.start, merge_buffer)?; |
| 147 | + self.storage.try_read(page.start, self.merge_buffer)?; |
130 | 148 |
|
131 | 149 | // If we cannot write multiple times to the same page, we will have to erase it
|
132 |
| - self.0.try_erase(page.start, page.end())?; |
133 |
| - merge_buffer |
| 150 | + self.storage.try_erase(page.start, page.end())?; |
| 151 | + self.merge_buffer |
134 | 152 | .iter_mut()
|
135 | 153 | .skip(offset_into_page)
|
136 | 154 | .zip(data)
|
137 | 155 | .for_each(|(byte, input)| *byte = *input);
|
138 |
| - self.0.try_write(page.start, merge_buffer)?; |
| 156 | + self.storage.try_write(page.start, self.merge_buffer)?; |
139 | 157 | }
|
140 | 158 | Ok(())
|
141 | 159 | }
|
142 | 160 | }
|
143 | 161 |
|
144 |
| -// FIXME: Requires specialization to take advantage of MultiwriteNorFlash? |
145 |
| -// impl<S: MultiwriteNorFlash> Storage for RmwNorFlashStorage<S> { |
146 |
| -// type Error = S::Error; |
147 |
| - |
148 |
| -// fn try_read(&mut self, address: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
149 |
| -// // Nothing special to be done for reads |
150 |
| -// self.0.try_read(address, bytes) |
151 |
| -// } |
152 |
| - |
153 |
| -// fn try_write(&mut self, address: u32, bytes: &[u8]) -> Result<(), Self::Error> { |
154 |
| -// // Perform read/modify/write operations on the byte slice. |
155 |
| -// let erase_size = self.0.erase_size(); |
156 |
| -// let last_page = (self.0.capacity() / erase_size) - 1; |
157 |
| - |
158 |
| -// // `data` is the part of `bytes` contained within `page`, |
159 |
| -// // and `addr` in the address offset of `page` + any offset into the page as requested by `address` |
160 |
| -// for (data, page, addr) in (0..last_page) |
161 |
| -// .map(move |i| Page::new(i, erase_size)) |
162 |
| -// .overlaps(bytes, address) |
163 |
| -// { |
164 |
| -// let merge_buffer = &mut [0u8; MAX_PAGE_SIZE][0..erase_size as usize]; |
165 |
| -// let offset_into_page = addr.saturating_sub(page.start) as usize; |
166 |
| - |
167 |
| -// self.try_read(page.start, merge_buffer)?; |
168 |
| - |
169 |
| -// let rhs = &merge_buffer[offset_into_page..]; |
170 |
| -// let is_subset = |
171 |
| -// data.len() < rhs.len() && data.iter().zip(rhs.iter()).all(|(a, b)| (*a | *b) == *b); |
172 |
| - |
173 |
| -// // Check if we can write the data block directly, under the limitations imposed by NorFlash: |
174 |
| -// // - We can only change 1's to 0's |
175 |
| -// if is_subset { |
176 |
| -// self.0.try_write(addr, data)?; |
177 |
| -// } else { |
178 |
| -// self.0.try_erase(page.start, page.end())?; |
179 |
| -// merge_buffer |
180 |
| -// .iter_mut() |
181 |
| -// .skip(offset_into_page) |
182 |
| -// .zip(data) |
183 |
| -// .for_each(|(byte, input)| *byte = *input); |
184 |
| -// self.0.try_write(page.start, merge_buffer)?; |
185 |
| -// } |
186 |
| -// } |
187 |
| -// Ok(()) |
188 |
| -// } |
189 |
| - |
190 |
| -// fn capacity(&self) -> u32 { |
191 |
| -// self.0.capacity() |
192 |
| -// } |
193 |
| -// } |
| 162 | +/// |
| 163 | +pub struct RmwMultiwriteNorFlashStorage<'a, S> { |
| 164 | + storage: S, |
| 165 | + merge_buffer: &'a mut [u8], |
| 166 | +} |
| 167 | + |
| 168 | +impl<'a, S> ReadStorage for RmwMultiwriteNorFlashStorage<'a, S> |
| 169 | +where |
| 170 | + S: ReadNorFlash, |
| 171 | +{ |
| 172 | + type Error = S::Error; |
| 173 | + |
| 174 | + fn try_read(&mut self, address: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 175 | + // Nothing special to be done for reads |
| 176 | + self.storage.try_read(address, bytes) |
| 177 | + } |
| 178 | + |
| 179 | + fn capacity(&self) -> usize { |
| 180 | + self.storage.capacity() |
| 181 | + } |
| 182 | +} |
| 183 | + |
| 184 | +impl<'a, S> Storage for RmwMultiwriteNorFlashStorage<'a, S> |
| 185 | +where |
| 186 | + S: NorFlash, |
| 187 | +{ |
| 188 | + fn try_write(&mut self, address: u32, bytes: &[u8]) -> Result<(), Self::Error> { |
| 189 | + // Perform read/modify/write operations on the byte slice. |
| 190 | + let last_page = (self.storage.capacity() / S::ERASE_SIZE) - 1; |
| 191 | + |
| 192 | + // `data` is the part of `bytes` contained within `page`, |
| 193 | + // and `addr` in the address offset of `page` + any offset into the page as requested by `address` |
| 194 | + for (data, page, addr) in (0..last_page as u32) |
| 195 | + .map(move |i| Page::new(i, S::ERASE_SIZE)) |
| 196 | + .overlaps(bytes, address) |
| 197 | + { |
| 198 | + let offset_into_page = addr.saturating_sub(page.start) as usize; |
| 199 | + |
| 200 | + self.storage.try_read(page.start, self.merge_buffer)?; |
| 201 | + |
| 202 | + let rhs = &self.merge_buffer[offset_into_page..]; |
| 203 | + let is_subset = |
| 204 | + data.len() < rhs.len() && data.iter().zip(rhs.iter()).all(|(a, b)| (*a | *b) == *b); |
| 205 | + |
| 206 | + // Check if we can write the data block directly, under the limitations imposed by NorFlash: |
| 207 | + // - We can only change 1's to 0's |
| 208 | + if is_subset { |
| 209 | + self.storage.try_write(addr, data)?; |
| 210 | + } else { |
| 211 | + self.storage.try_erase(page.start, page.end())?; |
| 212 | + self.merge_buffer |
| 213 | + .iter_mut() |
| 214 | + .skip(offset_into_page) |
| 215 | + .zip(data) |
| 216 | + .for_each(|(byte, input)| *byte = *input); |
| 217 | + self.storage.try_write(page.start, self.merge_buffer)?; |
| 218 | + } |
| 219 | + } |
| 220 | + Ok(()) |
| 221 | + } |
| 222 | +} |
0 commit comments