1use crate::{
9 Slot,
10 chksum::{self, Chksum},
11};
12use core::fmt;
13
14pub trait Flash {
19 type Error: fmt::Debug;
21
22 fn read(&mut self, addr: u32, buf: &mut [u8]) -> Result<(), Self::Error>;
29
30 fn write(&mut self, addr: u32, data: &mut [u8]) -> Result<(), Self::Error>;
35
36 fn erase(&mut self, addr: u32) -> Result<(), Self::Error>;
41
42 fn erase_all(&mut self, count: usize) -> Result<(), Self::Error> {
51 for idx in 0..count {
52 self.erase(idx as u32)?;
53 }
54 Ok(())
55 }
56}
57
58#[derive(Debug)]
82pub struct Storage<F: Flash, const SLOT_SIZE: usize, const SLOT_COUNT: usize> {
83 flash: F,
84 prev: Chksum,
85 idx: usize,
86}
87
88impl<F: Flash, const SLOT_SIZE: usize, const SLOT_COUNT: usize> Storage<F, SLOT_SIZE, SLOT_COUNT> {
89 pub const SPACE: u32 = SLOT_SIZE as u32 * SLOT_COUNT as u32;
94
95 pub const fn new(flash: F) -> Self {
100 Self {
101 flash,
102 prev: Chksum::zero(),
103 idx: 0,
104 }
105 }
106
107 const fn addr(&self, idx: usize) -> u32 {
109 ((idx % SLOT_COUNT) * SLOT_SIZE) as u32
110 }
111
112 fn scan_slot(&mut self, idx: usize) -> Result<Option<Slot>, F::Error> {
114 let mut buf = [0u8; Slot::HEADER_SIZE];
115 let (head, tail) = arrayref::mut_array_refs![&mut buf, 1, Slot::HEADER_SIZE - 1];
116
117 let addr = self.addr(idx);
119 self.flash.read(addr, head)?;
120
121 if head[0] & chksum::BYTE_MASK != 0 {
122 return Ok(None);
123 }
124
125 let addr = addr.saturating_add(1);
127 self.flash.read(addr, tail)?;
128
129 let slot = Slot::from_bytes(idx, buf);
131 let slot = slot.is_valid().then_some(slot);
132 Ok(slot)
133 }
134
135 pub fn scan(&mut self) -> Result<Option<Slot>, F::Error> {
141 let mut current: Option<Slot> = None;
142
143 for idx in 0..SLOT_COUNT {
144 let Some(slot) = self.scan_slot(idx)? else {
145 continue;
146 };
147
148 if let Some(existing) = ¤t {
149 if slot.is_update_to(existing) {
150 current = Some(slot);
151 }
152 } else {
153 current = Some(slot);
154 }
155 }
156
157 if let Some(current) = ¤t {
158 self.idx = current.next_slot::<SLOT_SIZE, SLOT_COUNT>();
159 self.prev = current.chksum;
160 }
161
162 Ok(current)
163 }
164
165 pub fn erase(&mut self, idx: usize) -> Result<(), F::Error> {
170 self.flash.erase(self.addr(idx))?;
171 Ok(())
172 }
173
174 pub fn erase_all(&mut self) -> Result<(), F::Error> {
181 self.idx = 0;
182 self.prev = Chksum::zero();
183 self.flash.erase_all(SLOT_COUNT)
184 }
185
186 pub fn read<'a>(
193 &mut self,
194 mut idx: usize,
195 buf: &'a mut [u8],
196 ) -> Result<Option<&'a mut [u8]>, F::Error> {
197 let mut addr = self.addr(idx);
198 let mut slot = [0u8; Slot::HEADER_SIZE];
199 self.flash.read(addr, &mut slot)?;
200 addr = addr.saturating_add(Slot::HEADER_SIZE as u32);
201 let slot = Slot::from_bytes(idx, slot);
202
203 let Some(data) = buf.get_mut(..slot.len as usize) else {
204 return Ok(None);
205 };
206 let mut buf = &mut *data;
207 let mut remaining_space = SLOT_SIZE - Slot::HEADER_SIZE;
208 while !buf.is_empty() {
209 let read_size = remaining_space.min(buf.len());
210 let (to_read, remaining) = buf.split_at_mut(read_size);
211 self.flash.read(addr, to_read)?;
212 buf = remaining;
213
214 idx = idx.saturating_add(1) % SLOT_COUNT;
215 addr = self.addr(idx).saturating_add(1);
216 remaining_space = SLOT_SIZE - 1;
217 }
218
219 Ok(Some(data))
220 }
221
222 pub fn read_static<const SIZE: usize>(
228 &mut self,
229 idx: usize,
230 buf: &mut [u8; SIZE],
231 ) -> Result<(), F::Error> {
232 const {
234 let space_available = SLOT_SIZE
235 .checked_sub(Slot::HEADER_SIZE)
236 .expect("Invalid SLOT_SIZE, Slot::HEADER_SIZE doesn't fit");
237 assert!(SIZE <= space_available);
238 }
239
240 let addr = self.addr(idx).saturating_add(Slot::HEADER_SIZE as u32);
242 self.flash.read(addr, buf)?;
244
245 Ok(())
246 }
247
248 pub fn write(
254 &mut self,
255 mut idx: usize,
256 prev: Chksum,
257 mut data: &mut [u8],
258 ) -> Result<(usize, Chksum), F::Error> {
259 let slot = Slot::create(idx, prev, data);
260 let slot_addr = self.addr(idx);
261 self.flash.erase(slot_addr)?;
262
263 let mut addr = slot_addr.saturating_add(Slot::HEADER_SIZE as u32);
264 let mut remaining_space = SLOT_SIZE - Slot::HEADER_SIZE;
265
266 loop {
267 let write_size = remaining_space.min(data.len());
268 let (to_write, remaining) = data.split_at_mut(write_size);
269 self.flash.write(addr, to_write)?;
270 data = remaining;
271 idx = idx.saturating_add(1) % SLOT_COUNT;
272
273 if data.is_empty() {
275 break;
276 }
277
278 addr = self.addr(idx);
279 self.flash.erase(addr)?;
280
281 addr = addr.saturating_add(1);
282 remaining_space = SLOT_SIZE - 1;
283 }
284
285 let mut bytes = slot.to_bytes();
288 self.flash.write(slot_addr, &mut bytes)?;
289
290 Ok((idx, slot.chksum))
291 }
292
293 pub fn write_static<const SIZE: usize>(
299 &mut self,
300 mut idx: usize,
301 prev: Chksum,
302 data: &mut [u8; SIZE],
303 ) -> Result<(usize, Chksum), F::Error> {
304 const {
306 let space_available = SLOT_SIZE
307 .checked_sub(Slot::HEADER_SIZE)
308 .expect("Invalid SLOT_SIZE, Slot::HEADER_SIZE doesn't fit");
309 assert!(SIZE <= space_available);
310 }
311
312 let slot = Slot::create(idx, prev, data);
314 let slot_addr = self.addr(idx);
315 self.flash.erase(slot_addr)?;
316
317 let addr = slot_addr.saturating_add(Slot::HEADER_SIZE as u32);
319 self.flash.write(addr, data)?;
320 idx = idx.saturating_add(1) % SLOT_COUNT;
321
322 let mut bytes = slot.to_bytes();
325 self.flash.write(slot_addr, &mut bytes)?;
326
327 Ok((idx, slot.chksum))
328 }
329
330 pub fn append(&mut self, data: &mut [u8]) -> Result<(), F::Error> {
335 let (idx, chksum) = self.write(self.idx, self.prev, data)?;
336 self.idx = idx;
337 self.prev = chksum;
338 Ok(())
339 }
340
341 pub fn append_static<const SIZE: usize>(
347 &mut self,
348 data: &mut [u8; SIZE],
349 ) -> Result<(), F::Error> {
350 let (idx, chksum) = self.write_static(self.idx, self.prev, data)?;
351 self.idx = idx;
352 self.prev = chksum;
353 Ok(())
354 }
355
356 pub const fn reset(&mut self) {
361 self.idx = 0;
362 self.prev = Chksum::zero();
363 }
364
365 pub fn into_inner(self) -> F {
370 self.flash
371 }
372}
373
374#[cfg(test)]
375mod tests {
376 use super::*;
377 use crate::mock::{MeasuredMockFlash, MeasuredStats, MockFlash, SectorMockFlash};
378 use core::convert::Infallible;
379
380 const SLOT_SIZE: usize = 64;
381 const SLOT_COUNT: usize = 8;
382 const SIZE: usize = SLOT_SIZE * SLOT_COUNT;
383
384 const fn mock_storage() -> Storage<MockFlash<SIZE>, SLOT_SIZE, SLOT_COUNT> {
385 let flash = MockFlash::<SIZE>::new();
386 Storage::<_, SLOT_SIZE, SLOT_COUNT>::new(flash)
387 }
388
389 const fn mock_sector_storage()
390 -> Storage<SectorMockFlash<SLOT_SIZE, SLOT_COUNT>, SLOT_SIZE, SLOT_COUNT> {
391 let flash = SectorMockFlash::<SLOT_SIZE, SLOT_COUNT>::new();
392 Storage::<_, SLOT_SIZE, SLOT_COUNT>::new(flash)
393 }
394
395 fn mock_measured_storage() -> Storage<MeasuredMockFlash<SIZE>, SLOT_SIZE, SLOT_COUNT> {
396 let flash = MeasuredMockFlash::<SIZE>::new();
397 Storage::<_, SLOT_SIZE, SLOT_COUNT>::new(flash)
398 }
399
400 fn test_storage_empty_scan<F: Flash<Error = Infallible>>(
401 storage: &mut Storage<F, SLOT_SIZE, SLOT_COUNT>,
402 ) {
403 let Ok(slot) = storage.scan();
404 assert_eq!(slot, None);
405 }
406
407 #[test]
408 fn test_at24cxx_storage_empty_scan() {
409 let mut storage = mock_storage();
410 test_storage_empty_scan(&mut storage);
411 }
412
413 #[test]
414 fn test_w25qxx_storage_empty_scan() {
415 let mut storage = mock_sector_storage();
416 test_storage_empty_scan(&mut storage);
417 }
418
419 #[test]
420 fn test_measured_storage_empty_scan() {
421 let mut storage = mock_measured_storage();
422 test_storage_empty_scan(&mut storage);
423 assert_eq!(
424 storage.flash.stats,
425 MeasuredStats {
426 read: 8,
427 write: 0,
428 erase: 0,
429 }
430 );
431 }
432
433 #[test]
434 fn test_storage_write() {
435 let mut storage = mock_storage();
436
437 let mut data = *b"hello world";
438 storage.append(&mut data);
439
440 let mut buf = [0u8; Slot::HEADER_SIZE];
441 storage.flash.read(0, &mut buf);
442 let slot = Slot::from_bytes(0, buf);
443 assert_eq!(
444 slot,
445 Slot {
446 idx: 0,
447 chksum: Chksum::hash(Chksum::zero(), &data),
448 len: data.len() as u32,
449 prev: Chksum::zero(),
450 }
451 );
452 }
453
454 #[test]
455 fn test_storage_write_static() {
456 let mut storage = mock_storage();
457
458 let mut data = *b"hello world";
459 storage.append_static(&mut data);
460
461 let mut buf = [0u8; Slot::HEADER_SIZE];
462 storage.flash.read(0, &mut buf);
463 let slot = Slot::from_bytes(0, buf);
464 assert_eq!(
465 slot,
466 Slot {
467 idx: 0,
468 chksum: Chksum::hash(Chksum::zero(), &data),
469 len: data.len() as u32,
470 prev: Chksum::zero(),
471 }
472 );
473 }
474
475 fn test_storage_write_scan<F: Flash<Error = Infallible>>(
476 storage: &mut Storage<F, SLOT_SIZE, SLOT_COUNT>,
477 ) {
478 let mut data = *b"hello world";
479 storage.append(&mut data);
480
481 let Ok(scan) = storage.scan();
482 assert_eq!(
483 scan,
484 Some(Slot {
485 idx: 0,
486 chksum: Chksum::hash(Chksum::zero(), &data),
487 len: data.len() as u32,
488 prev: Chksum::zero(),
489 })
490 );
491 }
492
493 #[test]
494 fn test_at24cxx_storage_write_scan() {
495 let mut storage = mock_storage();
496 test_storage_write_scan(&mut storage);
497 }
498
499 #[test]
500 fn test_w25qxx_storage_write_scan() {
501 let mut storage = mock_sector_storage();
502 test_storage_write_scan(&mut storage);
503 }
504
505 #[test]
506 fn test_measured_storage_write_scan() {
507 let mut storage = mock_measured_storage();
508 test_storage_write_scan(&mut storage);
509 assert_eq!(
510 storage.flash.stats,
511 MeasuredStats {
512 read: 19,
513 write: 23,
514 erase: 1,
515 }
516 );
517 }
518
519 fn test_storage_write_read<F: Flash<Error = Infallible>>(
520 storage: &mut Storage<F, SLOT_SIZE, SLOT_COUNT>,
521 ) {
522 let mut data = *b"hello world";
523 storage.append(&mut data);
524
525 let mut buf = [0u8; 1024];
526 let Ok(slice) = storage.read(0, &mut buf);
527
528 assert_eq!(slice.map(|s| &*s), Some("hello world".as_bytes()));
529 }
530
531 #[test]
532 fn test_at24cxx_storage_write_read() {
533 let mut storage = mock_storage();
534 test_storage_write_read(&mut storage);
535 }
536
537 #[test]
538 fn test_w25qxx_storage_write_read() {
539 let mut storage = mock_sector_storage();
540 test_storage_write_read(&mut storage);
541 }
542
543 #[test]
544 fn test_measured_storage_write_read() {
545 let mut storage = mock_measured_storage();
546 test_storage_write_read(&mut storage);
547 assert_eq!(
548 storage.flash.stats,
549 MeasuredStats {
550 read: 23,
551 write: 23,
552 erase: 1,
553 }
554 );
555 }
556
557 fn test_storage_write_wrap_around<F: Flash<Error = Infallible>>(
558 storage: &mut Storage<F, SLOT_SIZE, SLOT_COUNT>,
559 ) {
560 for num in 0..(SLOT_COUNT as u32 * 3 + 2) {
561 let mut buf = [0u8; 6];
562 num.to_be_bytes().iter().enumerate().for_each(|(i, b)| {
563 buf[i] = *b;
564 });
565 storage.append(&mut buf);
566 }
567
568 let slot = storage.scan().unwrap().unwrap();
569 assert_eq!(slot.idx, 1);
570 assert_eq!(storage.idx, 2);
571
572 let mut buf = [0u8; 32];
573 let Ok(slice) = storage.read(slot.idx, &mut buf);
574 assert_eq!(slice, Some(&mut [0, 0, 0, 25, 0, 0][..]));
575 }
576
577 #[test]
578 fn test_at24cxx_storage_write_wrap_around() {
579 let mut storage = mock_storage();
580 test_storage_write_wrap_around(&mut storage);
581 }
582
583 #[test]
584 fn test_w25qxx_storage_write_wrap_around() {
585 let mut storage = mock_sector_storage();
586 test_storage_write_wrap_around(&mut storage);
587 }
588
589 #[test]
590 fn test_measured_storage_write_wrap_around() {
591 let mut storage = mock_measured_storage();
592 test_storage_write_wrap_around(&mut storage);
593 assert_eq!(
594 storage.flash.stats,
595 MeasuredStats {
596 read: 114,
597 write: 468,
598 erase: 26,
599 }
600 );
601 }
602
603 fn test_storage_big_write<F: Flash<Error = Infallible>>(
604 storage: &mut Storage<F, SLOT_SIZE, SLOT_COUNT>,
605 ) {
606 let mut buf = [b'A'; SLOT_SIZE * 5];
607 storage.append(&mut buf);
608 let slot = storage.scan().unwrap().unwrap();
609 assert_eq!(
610 slot,
611 Slot {
612 idx: 0,
613 chksum: Chksum::hash(Chksum::zero(), &buf),
614 len: buf.len() as u32,
615 prev: Chksum::zero(),
616 }
617 );
618
619 let mut buf2 = [0u8; 512];
620 let Ok(slice) = storage.read(slot.idx, &mut buf2);
621 assert_eq!(slice.map(|s| &*s), Some(&buf[..]));
622
623 let mut buf = [b'B'; SLOT_SIZE * 5];
624 storage.append(&mut buf);
625 let new_slot = storage.scan().unwrap().unwrap();
626 assert_eq!(
627 new_slot,
628 Slot {
629 idx: 6,
630 chksum: Chksum::hash(slot.chksum, &buf),
631 len: buf.len() as u32,
632 prev: slot.chksum,
633 }
634 );
635 }
636
637 #[test]
638 fn test_at24cxx_storage_big_write() {
639 let mut storage = mock_storage();
640 test_storage_big_write(&mut storage);
641 }
642
643 #[test]
644 fn test_w25qxx_storage_big_write() {
645 let mut storage = mock_sector_storage();
646 test_storage_big_write(&mut storage);
647 }
648
649 #[test]
650 fn test_measured_storage_big_write() {
651 let mut storage = mock_measured_storage();
652 test_storage_big_write(&mut storage);
653 assert_eq!(
654 storage.flash.stats,
655 MeasuredStats {
656 read: 370,
657 write: 664,
658 erase: 12,
659 }
660 );
661 }
662
663 fn test_append_after_scan<F: Flash<Error = Infallible>>(
664 storage: &mut Storage<F, SLOT_SIZE, SLOT_COUNT>,
665 ) {
666 let mut big = [b'A'; SLOT_SIZE * 2];
667 storage.append(&mut big);
668 assert_eq!(storage.idx, 3);
669 storage.idx = 0;
670
671 storage.scan().unwrap();
672 assert_eq!(storage.idx, 3);
673 assert_eq!(storage.prev, Chksum::hash(Chksum::zero(), &big));
674 }
675
676 #[test]
677 fn test_at24cxx_append_after_scan() {
678 let mut storage = mock_storage();
679 test_append_after_scan(&mut storage);
680 }
681
682 #[test]
683 fn test_w25qxx_append_after_scan() {
684 let mut storage = mock_sector_storage();
685 test_append_after_scan(&mut storage);
686 }
687
688 #[test]
689 fn test_measured_append_after_scan() {
690 let mut storage = mock_measured_storage();
691 test_append_after_scan(&mut storage);
692 assert_eq!(
693 storage.flash.stats,
694 MeasuredStats {
695 read: 19,
696 write: 140,
697 erase: 3,
698 }
699 );
700 }
701
702 fn test_append_three_times_then_scan<F: Flash<Error = Infallible>>(
703 storage: &mut Storage<F, SLOT_SIZE, SLOT_COUNT>,
704 ) {
705 let mut data = *b"first";
706 storage.append(&mut data);
707 let mut data = *b"second";
708 storage.append(&mut data);
709 let mut data = *b"third";
710 storage.append(&mut data);
711
712 let slot = storage.scan().unwrap();
713 assert_eq!(
714 slot,
715 Some(Slot {
716 idx: 2,
717 chksum: Chksum::hash(
718 Chksum::hash(Chksum::hash(Chksum::zero(), b"first"), b"second",),
719 b"third",
720 ),
721 len: 5,
722 prev: Chksum::hash(Chksum::hash(Chksum::zero(), b"first"), b"second",),
723 })
724 );
725 assert_eq!(storage.idx, 3);
726 assert_eq!(
727 storage.prev,
728 Chksum::hash(
729 Chksum::hash(Chksum::hash(Chksum::zero(), b"first"), b"second",),
730 b"third",
731 )
732 );
733 }
734
735 #[test]
736 fn test_at24cxx_append_three_times_then_scan() {
737 let mut storage = mock_storage();
738 test_append_three_times_then_scan(&mut storage);
739 }
740
741 #[test]
742 fn test_w25qxx_append_three_times_then_scan() {
743 let mut storage = mock_sector_storage();
744 test_append_three_times_then_scan(&mut storage);
745 }
746
747 fn test_append_static_three_times_then_scan<F: Flash<Error = Infallible>>(
748 storage: &mut Storage<F, SLOT_SIZE, SLOT_COUNT>,
749 ) {
750 let mut data = *b"first";
751 storage.append_static(&mut data);
752 let mut data = *b"second";
753 storage.append_static(&mut data);
754 let mut data = *b"third";
755 storage.append_static(&mut data);
756
757 let slot = storage.scan().unwrap();
758 assert_eq!(
759 slot,
760 Some(Slot {
761 idx: 2,
762 chksum: Chksum::hash(
763 Chksum::hash(Chksum::hash(Chksum::zero(), b"first"), b"second",),
764 b"third",
765 ),
766 len: 5,
767 prev: Chksum::hash(Chksum::hash(Chksum::zero(), b"first"), b"second",),
768 })
769 );
770 assert_eq!(storage.idx, 3);
771 assert_eq!(
772 storage.prev,
773 Chksum::hash(
774 Chksum::hash(Chksum::hash(Chksum::zero(), b"first"), b"second",),
775 b"third",
776 )
777 );
778 }
779
780 #[test]
781 fn test_at24cxx_append_static_three_times_then_scan() {
782 let mut storage = mock_storage();
783 test_append_static_three_times_then_scan(&mut storage);
784 }
785
786 #[test]
787 fn test_w25qxx_append_static_three_times_then_scan() {
788 let mut storage = mock_sector_storage();
789 test_append_static_three_times_then_scan(&mut storage);
790 }
791
792 #[test]
793 fn test_at24cxx_static_non_static_append_equality() {
794 let mut storage_non_static_writes = mock_storage();
795 test_append_three_times_then_scan(&mut storage_non_static_writes);
796 let mut storage_static_writes = mock_storage();
797 test_append_static_three_times_then_scan(&mut storage_static_writes);
798 assert_eq!(storage_non_static_writes.flash, storage_static_writes.flash);
799 }
800
801 #[test]
802 fn test_w25qxx_static_non_static_append_equality() {
803 let mut storage_non_static_writes = mock_sector_storage();
804 test_append_three_times_then_scan(&mut storage_non_static_writes);
805 let mut storage_static_writes = mock_sector_storage();
806 test_append_static_three_times_then_scan(&mut storage_static_writes);
807 assert_eq!(storage_non_static_writes.flash, storage_static_writes.flash);
808 }
809}