1use embedded_storage::nor_flash::{
2 ErrorType,
3 MultiwriteNorFlash,
4 NorFlash,
5 NorFlashError,
6 NorFlashErrorKind,
7 ReadNorFlash,
8};
9
10#[cfg(feature = "bytewise-read")]
11use crate::buffer::FlashWordBuffer;
12use crate::{
13 FlashStorage,
14 FlashStorageError,
15 buffer::{FlashSectorBuffer, uninit_slice, uninit_slice_mut},
16};
17
18impl FlashStorage<'_> {
19 #[inline(always)]
20 fn is_word_aligned(bytes: &[u8]) -> bool {
21 (bytes.as_ptr() as usize) % (Self::WORD_SIZE as usize) == 0
23 }
24}
25
26impl NorFlashError for FlashStorageError {
27 fn kind(&self) -> NorFlashErrorKind {
28 match self {
29 Self::NotAligned => NorFlashErrorKind::NotAligned,
30 Self::OutOfBounds => NorFlashErrorKind::OutOfBounds,
31 _ => NorFlashErrorKind::Other,
32 }
33 }
34}
35
36impl ErrorType for FlashStorage<'_> {
37 type Error = FlashStorageError;
38}
39
40impl ReadNorFlash for FlashStorage<'_> {
41 #[cfg(not(feature = "bytewise-read"))]
42 const READ_SIZE: usize = Self::WORD_SIZE as _;
43
44 #[cfg(feature = "bytewise-read")]
45 const READ_SIZE: usize = 1;
46
47 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
48 const RS: u32 = FlashStorage::READ_SIZE as u32;
49 self.check_alignment::<{ RS }>(offset, bytes.len())?;
50 self.check_bounds(offset, bytes.len())?;
51
52 #[cfg(feature = "bytewise-read")]
53 let (offset, bytes) = {
54 let byte_offset = (offset % Self::WORD_SIZE) as usize;
55 if byte_offset > 0 {
56 let mut word_buffer = FlashWordBuffer::uninit();
57
58 let offset = offset - byte_offset as u32;
59 let length = bytes.len().min(Self::WORD_SIZE as usize - byte_offset);
60
61 self.internal_read(offset, word_buffer.as_bytes_mut())?;
62 let word_buffer = unsafe { word_buffer.assume_init_bytes_mut() };
63 bytes[..length].copy_from_slice(&word_buffer[byte_offset..][..length]);
64
65 (offset + Self::WORD_SIZE, &mut bytes[length..])
66 } else {
67 (offset, bytes)
68 }
69 };
70
71 if Self::is_word_aligned(bytes) {
72 for (offset, chunk) in (offset..)
74 .step_by(Self::SECTOR_SIZE as _)
75 .zip(bytes.chunks_mut(Self::SECTOR_SIZE as _))
76 {
77 #[cfg(not(feature = "bytewise-read"))]
79 self.internal_read(offset, uninit_slice_mut(chunk))?;
80
81 #[cfg(feature = "bytewise-read")]
82 {
83 let length = chunk.len();
84 let byte_length = length % Self::WORD_SIZE as usize;
85 let length = length - byte_length;
86
87 self.internal_read(offset, &mut uninit_slice_mut(chunk)[..length])?;
88
89 if byte_length > 0 {
91 let mut word_buffer = FlashWordBuffer::uninit();
92
93 self.internal_read(offset + length as u32, word_buffer.as_bytes_mut())?;
94 let word_buffer = unsafe { word_buffer.assume_init_bytes_mut() };
95 chunk[length..].copy_from_slice(&word_buffer[..byte_length]);
96 }
97 }
98 }
99 } else {
100 let mut buffer = FlashSectorBuffer::uninit();
102
103 for (offset, chunk) in (offset..)
104 .step_by(Self::SECTOR_SIZE as _)
105 .zip(bytes.chunks_mut(Self::SECTOR_SIZE as _))
106 {
107 #[cfg(not(feature = "bytewise-read"))]
109 self.internal_read(offset, &mut buffer.as_bytes_mut()[..chunk.len()])?;
110
111 #[cfg(feature = "bytewise-read")]
113 {
114 let length = chunk.len();
115 let byte_length = length % Self::WORD_SIZE as usize;
116 let length = if byte_length > 0 {
117 length - byte_length + Self::WORD_SIZE as usize
118 } else {
119 length
120 };
121
122 self.internal_read(offset, &mut buffer.as_bytes_mut()[..length])?;
123 }
124 let buffer = unsafe { buffer.assume_init_bytes() };
125
126 chunk.copy_from_slice(&buffer[..chunk.len()]);
128 }
129 }
130
131 Ok(())
132 }
133
134 fn capacity(&self) -> usize {
135 self.capacity
136 }
137}
138
139impl NorFlash for FlashStorage<'_> {
140 const WRITE_SIZE: usize = Self::WORD_SIZE as _;
141 const ERASE_SIZE: usize = Self::SECTOR_SIZE as _;
142
143 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
144 const WS: u32 = FlashStorage::WORD_SIZE;
145 self.check_alignment::<{ WS }>(offset, bytes.len())?;
146 self.check_bounds(offset, bytes.len())?;
147
148 if Self::is_word_aligned(bytes) {
149 for (offset, chunk) in (offset..)
151 .step_by(Self::SECTOR_SIZE as _)
152 .zip(bytes.chunks(Self::SECTOR_SIZE as _))
153 {
154 self.internal_write(offset, chunk)?;
156 }
157 } else {
158 let mut buffer = FlashSectorBuffer::uninit();
160
161 for (offset, chunk) in (offset..)
162 .step_by(Self::SECTOR_SIZE as _)
163 .zip(bytes.chunks(Self::SECTOR_SIZE as _))
164 {
165 buffer.as_bytes_mut()[..chunk.len()].copy_from_slice(uninit_slice(chunk));
167 self.internal_write(offset, unsafe {
169 &buffer.assume_init_bytes()[..chunk.len()]
170 })?;
171 }
172 }
173
174 Ok(())
175 }
176
177 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
178 let len = (to - from) as _;
179 const SZ: u32 = FlashStorage::SECTOR_SIZE;
180 self.check_alignment::<{ SZ }>(from, len)?;
181 self.check_bounds(from, len)?;
182
183 for sector in from / Self::SECTOR_SIZE..to / Self::SECTOR_SIZE {
184 self.internal_erase(sector)?;
185 }
186
187 Ok(())
188 }
189}
190
191impl MultiwriteNorFlash for FlashStorage<'_> {}
192
193#[cfg(test)]
195mod tests {
196 use super::*;
197 use crate::common::Flash;
198
199 const WORD_SIZE: u32 = 4;
200 const SECTOR_SIZE: u32 = 4 << 10;
201 const NUM_SECTORS: u32 = 3;
202 const FLASH_SIZE: u32 = SECTOR_SIZE * NUM_SECTORS;
203 const MAX_OFFSET: u32 = SECTOR_SIZE * 1;
204 const MAX_LENGTH: u32 = SECTOR_SIZE * 2;
205
206 #[repr(C, align(4))]
207 struct TestBuffer {
208 data: [u8; FLASH_SIZE as _],
209 }
210
211 impl TestBuffer {
212 const fn seq() -> Self {
213 let mut data = [0u8; FLASH_SIZE as _];
214 let mut index = 0;
215 while index < FLASH_SIZE {
216 data[index as usize] = (index & 0xff) as u8;
217 index += 1;
218 }
219 Self { data }
220 }
221 }
222
223 impl Default for TestBuffer {
224 fn default() -> Self {
225 Self {
226 data: [0u8; FLASH_SIZE as usize],
227 }
228 }
229 }
230
231 #[cfg(not(miri))]
232 fn range_gen<const ALIGN: u32, const MAX_OFF: u32, const MAX_LEN: u32>(
233 aligned: Option<bool>,
234 ) -> impl Iterator<Item = (u32, u32)> {
235 (0..=MAX_OFF).flat_map(move |off| {
236 (0..=MAX_LEN - off)
237 .filter(move |len| {
238 aligned
239 .map(|aligned| aligned == (off % ALIGN == 0 && len % ALIGN == 0))
240 .unwrap_or(true)
241 })
242 .map(move |len| (off, len))
243 })
244 }
245
246 #[cfg(miri)]
247 fn range_gen<const ALIGN: u32, const MAX_OFF: u32, const MAX_LEN: u32>(
248 aligned: Option<bool>,
249 ) -> impl Iterator<Item = (u32, u32)> {
250 match aligned {
252 Some(true) => vec![(0, 4), (0, 8), (0, 16), (0, 32), (0, 1024)],
253 Some(false) => vec![(3, 7), (11, 11)],
254 None => vec![
255 (0, 4),
256 (0, 8),
257 (0, 16),
258 (0, 32),
259 (0, 1024),
260 (3, 7),
261 (11, 11),
262 (0, 4098),
263 ],
264 }
265 .into_iter()
266 }
267
268 #[test]
269 #[cfg(not(feature = "bytewise-read"))]
270 fn aligned_read() {
271 let mut flash = FlashStorage::new(Flash::new());
272 flash.capacity = 4 * 4096;
273 let src = TestBuffer::seq();
274 let mut data = TestBuffer::default();
275
276 flash.erase(0, FLASH_SIZE).unwrap();
277 flash.write(0, &src.data).unwrap();
278
279 for (off, len) in range_gen::<WORD_SIZE, MAX_OFFSET, MAX_LENGTH>(Some(true)) {
280 flash.read(off, &mut data.data[..len as usize]).unwrap();
281 assert_eq!(
282 data.data[..len as usize],
283 src.data[off as usize..][..len as usize]
284 );
285 }
286 }
287
288 #[test]
289 #[cfg(not(feature = "bytewise-read"))]
290 fn not_aligned_read_aligned_buffer() {
291 let mut flash = FlashStorage::new(Flash::new());
292 flash.capacity = 4 * 4096;
293 let mut data = TestBuffer::default();
294
295 for (off, len) in range_gen::<WORD_SIZE, MAX_OFFSET, MAX_LENGTH>(Some(false)) {
296 flash.read(off, &mut data.data[..len as usize]).unwrap_err();
297 }
298 }
299
300 #[test]
301 #[cfg(not(feature = "bytewise-read"))]
302 fn aligned_read_not_aligned_buffer() {
303 let mut flash = FlashStorage::new(Flash::new());
304 flash.capacity = 4 * 4096;
305 let src = TestBuffer::seq();
306 let mut data = TestBuffer::default();
307
308 flash.erase(0, FLASH_SIZE).unwrap();
309 flash.write(0, &src.data).unwrap();
310
311 for (off, len) in range_gen::<WORD_SIZE, MAX_OFFSET, MAX_LENGTH>(Some(true)) {
312 flash
313 .read(off, &mut data.data[1..][..len as usize])
314 .unwrap();
315 assert_eq!(
316 data.data[1..][..len as usize],
317 src.data[off as usize..][..len as usize]
318 );
319 }
320 }
321
322 #[test]
323 #[cfg(feature = "bytewise-read")]
324 fn bytewise_read_aligned_buffer() {
325 let mut flash = FlashStorage::new(Flash::new());
326
327 flash.capacity = 4 * 4096;
328 let src = TestBuffer::seq();
329 let mut data = TestBuffer::default();
330
331 flash.erase(0, FLASH_SIZE).unwrap();
332 flash.write(0, &src.data).unwrap();
333
334 for (off, len) in range_gen::<WORD_SIZE, MAX_OFFSET, MAX_LENGTH>(None) {
335 flash.read(off, &mut data.data[..len as usize]).unwrap();
336 assert_eq!(
337 data.data[..len as usize],
338 src.data[off as usize..][..len as usize]
339 );
340 }
341 }
342
343 #[test]
344 #[cfg(feature = "bytewise-read")]
345 fn bytewise_read_not_aligned_buffer() {
346 let mut flash = FlashStorage::new(Flash::new());
347
348 flash.capacity = 4 * 4096;
349 let src = TestBuffer::seq();
350 let mut data = TestBuffer::default();
351
352 flash.erase(0, FLASH_SIZE).unwrap();
353 flash.write(0, &src.data).unwrap();
354
355 for (off, len) in range_gen::<WORD_SIZE, MAX_OFFSET, MAX_LENGTH>(None) {
356 flash
357 .read(off, &mut data.data[1..][..len as usize])
358 .unwrap();
359 assert_eq!(
360 data.data[1..][..len as usize],
361 src.data[off as usize..][..len as usize]
362 );
363 }
364 }
365
366 #[test]
367 fn write_not_aligned_buffer() {
368 let mut flash = FlashStorage::new(Flash::new());
369 flash.capacity = 4 * 4096;
370 let mut read_data = TestBuffer::default();
371 let write_data = TestBuffer::seq();
372
373 flash.erase(0, FLASH_SIZE).unwrap();
374 flash.write(0, &write_data.data[1..129]).unwrap();
375
376 flash.read(0, &mut read_data.data[..128]).unwrap();
377
378 assert_eq!(&read_data.data[..128], &write_data.data[1..129]);
379 }
380}