1use crate::partitions::{
28 AppPartitionSubType,
29 DataPartitionSubType,
30 Error,
31 FlashRegion,
32 PartitionType,
33};
34
35const SLOT0_DATA_OFFSET: u32 = 0x0000;
36const SLOT1_DATA_OFFSET: u32 = 0x1000;
37
38const UNINITIALIZED_SEQUENCE: u32 = 0xffffffff;
39
40#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, strum::FromRepr)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43enum OtaDataSlot {
44 None,
46 Slot0,
48 Slot1,
50}
51
52impl OtaDataSlot {
53 fn next(&self) -> OtaDataSlot {
55 match self {
56 OtaDataSlot::None => OtaDataSlot::Slot0,
57 OtaDataSlot::Slot0 => OtaDataSlot::Slot1,
58 OtaDataSlot::Slot1 => OtaDataSlot::Slot0,
59 }
60 }
61
62 fn offset(&self) -> u32 {
63 match self {
64 OtaDataSlot::None => SLOT0_DATA_OFFSET,
65 OtaDataSlot::Slot0 => SLOT0_DATA_OFFSET,
66 OtaDataSlot::Slot1 => SLOT1_DATA_OFFSET,
67 }
68 }
69}
70
71#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Hash, strum::FromRepr)]
73#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74#[repr(u32)]
75pub enum OtaImageState {
76 New = 0x0,
81
82 PendingVerify = 0x1,
86
87 Valid = 0x2,
90
91 Invalid = 0x3,
96
97 Aborted = 0x4,
101
102 #[default]
105 Undefined = 0xFFFFFFFF,
106}
107
108impl TryFrom<u32> for OtaImageState {
109 type Error = Error;
110
111 fn try_from(value: u32) -> Result<Self, Self::Error> {
112 OtaImageState::from_repr(value).ok_or(Error::Invalid)
113 }
114}
115
116#[derive(Debug, Clone, Copy, Default)]
119#[cfg_attr(feature = "defmt", derive(defmt::Format))]
120#[repr(C)]
121struct OtaSelectEntry {
122 pub ota_seq: u32,
124 pub seq_label: [u8; 20],
126 pub ota_state: OtaImageState,
128 pub crc: u32,
130}
131
132impl OtaSelectEntry {
133 fn read<'a, 'd>(region: &mut FlashRegion<'a, 'd>, offset: u32) -> Result<Self, Error> {
134 fn is_valid(buffer: &[u8]) -> bool {
135 let ota_seq = u32::from_le_bytes(unwrap!(buffer[0..4].try_into()));
136 let ota_state = u32::from_le_bytes(unwrap!(buffer[24..28].try_into()));
137 let crc = u32::from_le_bytes(unwrap!(buffer[28..32].try_into()));
138
139 if ota_seq == u32::MAX && ota_state == OtaImageState::Undefined as u32 {
140 return true;
141 }
142
143 if OtaImageState::try_from(ota_state).is_err() {
144 return false;
145 }
146
147 let calculated_crc = crate::crypto::Crc32::new().crc(&ota_seq.to_le_bytes());
148 if crc != calculated_crc {
149 return false;
150 }
151
152 true
153 }
154
155 let mut buffer = [0u8; 32];
156 region.read(offset, &mut buffer)?;
157
158 if !is_valid(&buffer) {
159 return Err(Error::Invalid);
160 }
161
162 let entry: *mut OtaSelectEntry = &mut buffer as *mut _ as *mut OtaSelectEntry;
163 let entry = unsafe { *entry };
164 Ok(entry)
165 }
166
167 fn write<'a, 'd>(
168 &mut self,
169 region: &mut FlashRegion<'a, 'd>,
170 offset: u32,
171 ) -> Result<(), Error> {
172 let bytes: &mut [u8; 32] = unwrap!(
173 unsafe { core::slice::from_raw_parts_mut(self as *mut _ as *mut u8, 0x20) }.try_into()
174 );
175 region.write(offset, bytes)?;
176
177 Ok(())
178 }
179}
180
181#[derive(Debug)]
185#[cfg_attr(feature = "defmt", derive(defmt::Format))]
186pub struct Ota<'a, 'd> {
187 flash: FlashRegion<'a, 'd>,
188 ota_partition_count: usize,
189}
190
191impl<'a, 'd> Ota<'a, 'd> {
192 pub fn new(
201 flash: FlashRegion<'a, 'd>,
202 ota_partition_count: usize,
203 ) -> Result<Ota<'a, 'd>, Error> {
204 if ota_partition_count == 0 || ota_partition_count > 16 {
205 return Err(Error::InvalidArgument);
206 }
207
208 if flash.capacity() != 0x2000
209 || flash.partition_type != PartitionType::Data(DataPartitionSubType::Ota)
210 {
211 return Err(Error::InvalidPartition {
212 expected_size: 0x2000,
213 expected_type: PartitionType::Data(DataPartitionSubType::Ota),
214 });
215 }
216
217 Ok(Ota {
218 flash,
219 ota_partition_count,
220 })
221 }
222
223 pub fn current_app_partition(&mut self) -> Result<AppPartitionSubType, Error> {
231 let (seq0, seq1) = self.get_slot_seq()?;
232
233 let slot = if seq0 == UNINITIALIZED_SEQUENCE && seq1 == UNINITIALIZED_SEQUENCE {
234 AppPartitionSubType::Factory
235 } else if seq0 == UNINITIALIZED_SEQUENCE {
236 AppPartitionSubType::from_ota_app_number(
237 ((seq1 - 1) % self.ota_partition_count as u32) as u8,
238 )?
239 } else if seq1 == UNINITIALIZED_SEQUENCE || seq0 > seq1 {
240 AppPartitionSubType::from_ota_app_number(
241 ((seq0 - 1) % self.ota_partition_count as u32) as u8,
242 )?
243 } else {
244 let counter = u32::max(seq0, seq1) - 1;
245 AppPartitionSubType::from_ota_app_number(
246 (counter % self.ota_partition_count as u32) as u8,
247 )?
248 };
249
250 Ok(slot)
251 }
252
253 fn get_slot_seq(&mut self) -> Result<(u32, u32), Error> {
254 let buffer1 = OtaSelectEntry::read(&mut self.flash, SLOT0_DATA_OFFSET)?;
255 let buffer2 = OtaSelectEntry::read(&mut self.flash, SLOT1_DATA_OFFSET)?;
256 let seq0 = buffer1.ota_seq;
257 let seq1 = buffer2.ota_seq;
258 Ok((seq0, seq1))
259 }
260
261 pub fn set_current_app_partition(&mut self, app: AppPartitionSubType) -> Result<(), Error> {
270 if app == AppPartitionSubType::Factory {
271 self.flash.write(SLOT0_DATA_OFFSET, &[0xffu8; 0x20])?;
272 self.flash.write(SLOT1_DATA_OFFSET, &[0xffu8; 0x20])?;
273 return Ok(());
274 }
275
276 if app == AppPartitionSubType::Test {
277 return Err(Error::InvalidArgument);
280 }
281
282 let ota_app_index = app.ota_app_number();
283 if ota_app_index >= self.ota_partition_count as u8 {
284 return Err(Error::InvalidArgument);
285 }
286
287 let current = self.current_app_partition()?;
288
289 if current != app {
291 let inc = if current == AppPartitionSubType::Factory {
300 (((app.ota_app_number()) as i32 + 1) + (self.ota_partition_count as i32)) as u32
301 % self.ota_partition_count as u32
302 } else {
303 ((((app.ota_app_number()) as i32) - ((current.ota_app_number()) as i32))
304 + (self.ota_partition_count as i32)) as u32
305 % self.ota_partition_count as u32
306 };
307
308 let slot = self.current_slot()?.next();
310
311 let (seq0, seq1) = self.get_slot_seq()?;
312 let new_seq = {
313 if seq0 == UNINITIALIZED_SEQUENCE && seq1 == UNINITIALIZED_SEQUENCE {
314 inc
316 } else if seq0 == UNINITIALIZED_SEQUENCE {
317 seq1 + inc
319 } else if seq1 == UNINITIALIZED_SEQUENCE {
320 seq0 + inc
322 } else {
323 u32::max(seq0, seq1) + inc
324 }
325 };
326
327 let crc = crate::crypto::Crc32::new();
328 let checksum = crc.crc(&new_seq.to_le_bytes());
329
330 let mut buffer = OtaSelectEntry::read(&mut self.flash, slot.offset())?;
331 buffer.ota_seq = new_seq;
332 buffer.crc = checksum;
333 buffer.write(&mut self.flash, slot.offset())?;
334 }
335
336 Ok(())
337 }
338
339 fn current_slot(&mut self) -> Result<OtaDataSlot, Error> {
341 let (seq0, seq1) = self.get_slot_seq()?;
342
343 let slot = if seq0 == UNINITIALIZED_SEQUENCE && seq1 == UNINITIALIZED_SEQUENCE {
344 OtaDataSlot::None
345 } else if seq0 == UNINITIALIZED_SEQUENCE {
346 OtaDataSlot::Slot1
347 } else if seq1 == UNINITIALIZED_SEQUENCE || seq0 > seq1 {
348 OtaDataSlot::Slot0
349 } else {
350 OtaDataSlot::Slot1
351 };
352 Ok(slot)
353 }
354
355 pub fn set_current_ota_state(&mut self, state: OtaImageState) -> Result<(), Error> {
360 if let (UNINITIALIZED_SEQUENCE, UNINITIALIZED_SEQUENCE) = self.get_slot_seq()? {
361 Err(Error::InvalidState)
362 } else {
363 let offset = self.current_slot()?.offset();
364 let mut buffer = OtaSelectEntry::read(&mut self.flash, offset)?;
365 buffer.ota_state = state;
366 buffer.write(&mut self.flash, offset)?;
367 Ok(())
368 }
369 }
370
371 pub fn current_ota_state(&mut self) -> Result<OtaImageState, Error> {
376 if let (UNINITIALIZED_SEQUENCE, UNINITIALIZED_SEQUENCE) = self.get_slot_seq()? {
377 Err(Error::InvalidState)
378 } else {
379 let offset = self.current_slot()?.offset();
380 let buffer = OtaSelectEntry::read(&mut self.flash, offset)?;
381 Ok(buffer.ota_state)
382 }
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389 use crate::partitions::{FlashStorage, PartitionEntry};
390
391 const PARTITION_RAW: [u8; 32] = [
392 0xaa, 0x50, 1, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
400
401 const SLOT_INITIAL: &[u8] = &[
402 255u8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
403 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
404 ];
405
406 const SLOT_COUNT_1_UNDEFINED: &[u8] = &[
407 1u8, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
408 255, 255, 255, 255, 255, 255, 255, 255, 255, 154, 152, 67, 71,
409 ];
410
411 const SLOT_COUNT_1_VALID: &[u8] = &[
412 1u8, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
413 255, 255, 255, 255, 255, 2, 0, 0, 0, 154, 152, 67, 71,
414 ];
415
416 const SLOT_COUNT_2_NEW: &[u8] = &[
417 2, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
418 255, 255, 255, 255, 0, 0, 0, 0, 116, 55, 246, 85,
419 ];
420
421 const SLOT_COUNT_3_PENDING: &[u8] = &[
422 3, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
423 255, 255, 255, 255, 1, 0, 0, 0, 17, 80, 74, 237,
424 ];
425
426 fn ota_region<'a>(
427 flash: &'a mut FlashStorage<'static>,
428 binary: [u8; 32],
429 ) -> FlashRegion<'a, 'static> {
430 PartitionEntry { binary }.as_flash_region(flash)
431 }
432
433 fn init_ota_flash(flash: &mut FlashStorage<'static>) {
434 flash.erase(0, 0x2000).unwrap();
435 }
436
437 fn read_slot(flash: &mut FlashStorage<'static>, offset: u32) -> [u8; 0x20] {
438 let mut buf = [0u8; 0x20];
439 flash.read(offset, &mut buf).unwrap();
440 buf
441 }
442
443 #[test]
444 fn test_initial_state_and_next_slot() {
445 let mut flash = FlashStorage::new();
446 init_ota_flash(&mut flash);
447
448 let mock_region = ota_region(&mut flash, PARTITION_RAW);
449
450 let mut sut = Ota::new(mock_region, 2).unwrap();
451 assert_eq!(
452 sut.current_app_partition().unwrap(),
453 AppPartitionSubType::Factory
454 );
455 assert_eq!(
456 sut.current_ota_state(),
457 Err(crate::partitions::Error::InvalidState)
458 );
459 assert_eq!(
460 sut.set_current_ota_state(OtaImageState::New),
461 Err(crate::partitions::Error::InvalidState)
462 );
463 assert_eq!(
464 sut.current_ota_state(),
465 Err(crate::partitions::Error::InvalidState)
466 );
467
468 sut.set_current_app_partition(AppPartitionSubType::Ota0)
469 .unwrap();
470 assert_eq!(
471 sut.current_app_partition().unwrap(),
472 AppPartitionSubType::Ota0
473 );
474 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Undefined));
475
476 assert_eq!(&read_slot(&mut flash, 0x0000)[..], SLOT_COUNT_1_UNDEFINED);
477 assert_eq!(&read_slot(&mut flash, 0x1000)[..], SLOT_INITIAL);
478 }
479
480 #[test]
481 fn test_slot0_valid_next_slot() {
482 let mut flash = FlashStorage::new();
483 init_ota_flash(&mut flash);
484 flash.write(0x0000, SLOT_COUNT_1_VALID).unwrap();
485 flash.write(0x1000, SLOT_INITIAL).unwrap();
486
487 let mock_region = ota_region(&mut flash, PARTITION_RAW);
488
489 let mut sut = Ota::new(mock_region, 2).unwrap();
490 assert_eq!(
491 sut.current_app_partition().unwrap(),
492 AppPartitionSubType::Ota0
493 );
494 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Valid));
495
496 sut.set_current_app_partition(AppPartitionSubType::Ota1)
497 .unwrap();
498 sut.set_current_ota_state(OtaImageState::New).unwrap();
499 assert_eq!(
500 sut.current_app_partition().unwrap(),
501 AppPartitionSubType::Ota1
502 );
503 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::New));
504
505 assert_eq!(&read_slot(&mut flash, 0x0000)[..], SLOT_COUNT_1_VALID);
506 assert_eq!(&read_slot(&mut flash, 0x1000)[..], SLOT_COUNT_2_NEW);
507 }
508
509 #[test]
510 fn test_slot1_new_next_slot() {
511 let mut flash = FlashStorage::new();
512 init_ota_flash(&mut flash);
513 flash.write(0x0000, SLOT_COUNT_1_VALID).unwrap();
514 flash.write(0x1000, SLOT_COUNT_2_NEW).unwrap();
515
516 let mock_region = ota_region(&mut flash, PARTITION_RAW);
517
518 let mut sut = Ota::new(mock_region, 2).unwrap();
519 assert_eq!(
520 sut.current_app_partition().unwrap(),
521 AppPartitionSubType::Ota1
522 );
523 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::New));
524
525 sut.set_current_app_partition(AppPartitionSubType::Ota0)
526 .unwrap();
527 sut.set_current_ota_state(OtaImageState::PendingVerify)
528 .unwrap();
529 assert_eq!(
530 sut.current_app_partition().unwrap(),
531 AppPartitionSubType::Ota0
532 );
533 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::PendingVerify));
534
535 assert_eq!(&read_slot(&mut flash, 0x0000)[..], SLOT_COUNT_3_PENDING);
536 assert_eq!(&read_slot(&mut flash, 0x1000)[..], SLOT_COUNT_2_NEW);
537 }
538
539 #[test]
540 fn test_multi_updates() {
541 let mut flash = FlashStorage::new();
542 init_ota_flash(&mut flash);
543
544 let mock_region = ota_region(&mut flash, PARTITION_RAW);
545
546 let mut sut = Ota::new(mock_region, 2).unwrap();
547 assert_eq!(
548 sut.current_app_partition().unwrap(),
549 AppPartitionSubType::Factory
550 );
551 assert_eq!(
552 sut.current_ota_state(),
553 Err(crate::partitions::Error::InvalidState)
554 );
555
556 sut.set_current_app_partition(AppPartitionSubType::Ota0)
557 .unwrap();
558 sut.set_current_ota_state(OtaImageState::PendingVerify)
559 .unwrap();
560 assert_eq!(
561 sut.current_app_partition().unwrap(),
562 AppPartitionSubType::Ota0
563 );
564 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::PendingVerify));
565
566 sut.set_current_app_partition(AppPartitionSubType::Ota1)
567 .unwrap();
568 sut.set_current_ota_state(OtaImageState::New).unwrap();
569 assert_eq!(
570 sut.current_app_partition().unwrap(),
571 AppPartitionSubType::Ota1
572 );
573 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::New));
574
575 sut.set_current_app_partition(AppPartitionSubType::Ota0)
576 .unwrap();
577 sut.set_current_ota_state(OtaImageState::Aborted).unwrap();
578 assert_eq!(
579 sut.current_app_partition().unwrap(),
580 AppPartitionSubType::Ota0
581 );
582 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Aborted));
583
584 sut.set_current_app_partition(AppPartitionSubType::Ota0)
586 .unwrap();
587 sut.set_current_ota_state(OtaImageState::Valid).unwrap();
588 assert_eq!(
589 sut.current_app_partition().unwrap(),
590 AppPartitionSubType::Ota0
591 );
592 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Valid));
593 }
594
595 #[test]
596 fn test_multi_updates_4_apps() {
597 let mut flash = FlashStorage::new();
598 init_ota_flash(&mut flash);
599
600 let mock_region = ota_region(&mut flash, PARTITION_RAW);
601
602 let mut sut = Ota::new(mock_region, 4).unwrap();
603 assert_eq!(
604 sut.current_app_partition().unwrap(),
605 AppPartitionSubType::Factory
606 );
607 assert_eq!(
608 sut.current_ota_state(),
609 Err(crate::partitions::Error::InvalidState)
610 );
611
612 sut.set_current_app_partition(AppPartitionSubType::Ota0)
613 .unwrap();
614 sut.set_current_ota_state(OtaImageState::PendingVerify)
615 .unwrap();
616 assert_eq!(
617 sut.current_app_partition().unwrap(),
618 AppPartitionSubType::Ota0
619 );
620 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::PendingVerify));
621
622 sut.set_current_app_partition(AppPartitionSubType::Ota1)
623 .unwrap();
624 sut.set_current_ota_state(OtaImageState::New).unwrap();
625 assert_eq!(
626 sut.current_app_partition().unwrap(),
627 AppPartitionSubType::Ota1
628 );
629 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::New));
630
631 sut.set_current_app_partition(AppPartitionSubType::Ota2)
632 .unwrap();
633 sut.set_current_ota_state(OtaImageState::Aborted).unwrap();
634 assert_eq!(
635 sut.current_app_partition().unwrap(),
636 AppPartitionSubType::Ota2
637 );
638 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Aborted));
639
640 sut.set_current_app_partition(AppPartitionSubType::Ota3)
641 .unwrap();
642 sut.set_current_ota_state(OtaImageState::Valid).unwrap();
643 assert_eq!(
644 sut.current_app_partition().unwrap(),
645 AppPartitionSubType::Ota3
646 );
647 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Valid));
648
649 sut.set_current_app_partition(AppPartitionSubType::Ota2)
651 .unwrap();
652 sut.set_current_ota_state(OtaImageState::Invalid).unwrap();
653 assert_eq!(
654 sut.current_app_partition().unwrap(),
655 AppPartitionSubType::Ota2
656 );
657 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Invalid));
658
659 assert_eq!(
660 sut.set_current_app_partition(AppPartitionSubType::Ota5),
661 Err(crate::partitions::Error::InvalidArgument)
662 );
663
664 assert_eq!(
665 sut.set_current_app_partition(AppPartitionSubType::Test),
666 Err(crate::partitions::Error::InvalidArgument)
667 );
668 }
669
670 #[test]
671 fn test_multi_updates_skip_parts() {
672 let mut flash = FlashStorage::new();
673 init_ota_flash(&mut flash);
674
675 let mock_region = ota_region(&mut flash, PARTITION_RAW);
676
677 let mut sut = Ota::new(mock_region, 16).unwrap();
678 assert_eq!(
679 sut.current_app_partition().unwrap(),
680 AppPartitionSubType::Factory
681 );
682 assert_eq!(
683 sut.current_ota_state(),
684 Err(crate::partitions::Error::InvalidState)
685 );
686
687 sut.set_current_app_partition(AppPartitionSubType::Ota10)
688 .unwrap();
689 assert_eq!(
690 sut.current_app_partition().unwrap(),
691 AppPartitionSubType::Ota10
692 );
693 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Undefined));
694
695 sut.set_current_app_partition(AppPartitionSubType::Ota14)
696 .unwrap();
697 assert_eq!(
698 sut.current_app_partition().unwrap(),
699 AppPartitionSubType::Ota14
700 );
701 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Undefined));
702
703 sut.set_current_app_partition(AppPartitionSubType::Ota5)
704 .unwrap();
705 assert_eq!(
706 sut.current_app_partition().unwrap(),
707 AppPartitionSubType::Ota5
708 );
709 assert_eq!(sut.current_ota_state(), Ok(OtaImageState::Undefined));
710 }
711
712 #[test]
713 fn test_ota_slot_next() {
714 assert_eq!(OtaDataSlot::None.next(), OtaDataSlot::Slot0);
715 assert_eq!(OtaDataSlot::Slot0.next(), OtaDataSlot::Slot1);
716 assert_eq!(OtaDataSlot::Slot1.next(), OtaDataSlot::Slot0);
717 }
718
719 #[test]
720 fn test_read_erased_slot() {
721 let mut flash = FlashStorage::new();
722 init_ota_flash(&mut flash);
723
724 let mut region = ota_region(&mut flash, PARTITION_RAW);
725 let entry = OtaSelectEntry::read(&mut region, SLOT0_DATA_OFFSET).unwrap();
726 assert_eq!(entry.ota_seq, UNINITIALIZED_SEQUENCE);
727 assert_eq!(entry.seq_label, [0xff; 20]);
728 assert_eq!(entry.ota_state, OtaImageState::Undefined);
729 assert_eq!(entry.crc, UNINITIALIZED_SEQUENCE);
730 }
731
732 #[test]
733 fn test_read_valid_slot() {
734 let mut flash = FlashStorage::new();
735 init_ota_flash(&mut flash);
736 flash.write(0x0000, SLOT_COUNT_1_VALID).unwrap();
737
738 let mut region = ota_region(&mut flash, PARTITION_RAW);
739 let entry = OtaSelectEntry::read(&mut region, SLOT0_DATA_OFFSET).unwrap();
740 assert_eq!(entry.ota_seq, 1);
741 assert_eq!(entry.ota_state, OtaImageState::Valid);
742 }
743
744 #[test]
745 fn test_read_rejects_bad_crc() {
746 let mut flash = FlashStorage::new();
747 init_ota_flash(&mut flash);
748
749 let mut slot = [0u8; 32];
750 slot.copy_from_slice(SLOT_COUNT_1_UNDEFINED);
751 slot[31] ^= 0xff;
752 flash.write(0x0000, &slot).unwrap();
753
754 let mut region = ota_region(&mut flash, PARTITION_RAW);
755 assert!(matches!(
756 OtaSelectEntry::read(&mut region, SLOT0_DATA_OFFSET),
757 Err(crate::partitions::Error::Invalid)
758 ));
759 }
760
761 #[test]
762 fn test_read_rejects_unknown_ota_state() {
763 let mut flash = FlashStorage::new();
764 init_ota_flash(&mut flash);
765
766 let ota_seq = 1u32;
767 let crc = crate::crypto::Crc32::new().crc(&ota_seq.to_le_bytes());
768 let mut slot = [0xffu8; 32];
769 slot[0..4].copy_from_slice(&ota_seq.to_le_bytes());
770 slot[24..28].copy_from_slice(&0x1234_5678u32.to_le_bytes());
771 slot[28..32].copy_from_slice(&crc.to_le_bytes());
772 flash.write(0x0000, &slot).unwrap();
773
774 let mut region = ota_region(&mut flash, PARTITION_RAW);
775 assert!(matches!(
776 OtaSelectEntry::read(&mut region, SLOT0_DATA_OFFSET),
777 Err(crate::partitions::Error::Invalid)
778 ));
779 }
780
781 #[test]
782 fn test_read_rejects_erased_seq_with_non_erased_state() {
783 let mut flash = FlashStorage::new();
784 init_ota_flash(&mut flash);
785
786 let mut slot = [0xffu8; 32];
787 slot[24..28].copy_from_slice(&(OtaImageState::Valid as u32).to_le_bytes());
788 flash.write(0x0000, &slot).unwrap();
789
790 let mut region = ota_region(&mut flash, PARTITION_RAW);
791 assert!(matches!(
792 OtaSelectEntry::read(&mut region, SLOT0_DATA_OFFSET),
793 Err(crate::partitions::Error::Invalid)
794 ));
795 }
796
797 #[test]
798 fn test_one_corrupt_slot_fails_current_app_partition() {
799 let mut flash = FlashStorage::new();
800 init_ota_flash(&mut flash);
801
802 let mut corrupt = [0u8; 32];
803 corrupt.copy_from_slice(SLOT_COUNT_1_UNDEFINED);
804 corrupt[31] ^= 0xff;
805 flash.write(0x0000, &corrupt).unwrap();
806 flash.write(0x1000, SLOT_COUNT_2_NEW).unwrap();
807
808 let region = ota_region(&mut flash, PARTITION_RAW);
809 let mut sut = Ota::new(region, 2).unwrap();
810 assert_eq!(
811 sut.current_app_partition(),
812 Err(crate::partitions::Error::Invalid)
813 );
814 }
815
816 #[test]
817 fn test_reset_to_factory_after_corrupt_ota_data() {
818 let mut flash = FlashStorage::new();
819 init_ota_flash(&mut flash);
820
821 let mut corrupt = [0u8; 32];
822 corrupt.copy_from_slice(SLOT_COUNT_1_UNDEFINED);
823 corrupt[31] ^= 0xff;
824 flash.write(0x0000, &corrupt).unwrap();
825 flash.write(0x1000, SLOT_COUNT_2_NEW).unwrap();
826
827 let region = ota_region(&mut flash, PARTITION_RAW);
828 let mut sut = Ota::new(region, 2).unwrap();
829 assert_eq!(
830 sut.current_app_partition(),
831 Err(crate::partitions::Error::Invalid)
832 );
833
834 sut.set_current_app_partition(AppPartitionSubType::Factory)
835 .unwrap();
836 assert_eq!(
837 sut.current_app_partition().unwrap(),
838 AppPartitionSubType::Factory
839 );
840 assert_eq!(&read_slot(&mut flash, 0x0000)[..], SLOT_INITIAL);
841 assert_eq!(&read_slot(&mut flash, 0x1000)[..], SLOT_INITIAL);
842 }
843}