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