commit a932717f67c60a89ff669f98b7fe2756b39c44eb
parent 0f715179169652f3b8f73668af34f93129baeeec
Author: filipton <filipton12@gmail.com>
Date: Fri, 5 Jul 2024 13:36:52 +0200
feat: ota verify flash (reading and crc'ing)
Diffstat:
4 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
@@ -4,6 +4,12 @@ OTA for esp-hal (no-std).
## Limitations
For now only works on esp32s3 (esp32c3 in the near future).
+## Features
+- Obviously OTA updates
+- Dynamic partitions reading (so no macros, no reading from partitions.csv) - fully automatic
+- Checking currently booted partition (using some pointer magic from ESP-IDF)
+- CRC32 verification
+
## Example
This example uses embassy-net for TcpSocket, as you can see ota doesn't use
async so you can easily use it with smoltcp.
@@ -43,8 +49,10 @@ loop {
}
if res == Ok(true) {
- _ = ota.ota_flush();
- // Here just reboot or sth!
+ if ota.ota_flush(true).is_ok() {
+ // Here just reboot or sth!
+ }
+
break;
}
}
diff --git a/examples/src/main.rs b/examples/src/main.rs
@@ -126,7 +126,15 @@ async fn main(spawner: Spawner) {
}
if res == Ok(true) {
- _ = ota.ota_flush();
+ let res = ota.ota_flush(false);
+ if let Err(e) = res {
+ log::error!("Ota flush error: {e:?}");
+ break;
+ }
+
+ log::info!("Ota OK! Rebooting in 1s!");
+ Timer::after_millis(1000).await;
+ esp_hal::reset::software_reset();
break;
}
}
diff --git a/simple-ota-server/firmware.bin b/simple-ota-server/firmware.bin
Binary files differ.
diff --git a/src/lib.rs b/src/lib.rs
@@ -9,6 +9,7 @@ pub mod paddr;
const PART_OFFSET: u32 = 0x8000;
const PART_SIZE: u32 = 0xc00;
const FIRST_OTA_PART_SUBTYPE: u8 = 0x10;
+const OTA_VERIFY_READ_SIZE: usize = 256;
#[derive(Clone)]
pub struct FlashProgress {
@@ -121,8 +122,15 @@ where
Ok(progress.remaining == 0)
}
- // TODO: crc checks or sth
- pub fn ota_flush(&mut self) -> Result<(), ()> {
+ /// verify - should it read flash and check crc
+ pub fn ota_flush(&mut self, verify: bool) -> Result<(), ()> {
+ if verify {
+ if !self.ota_verify()? {
+ log::error!("[OTA] Verify failed! Not flushing...");
+ return Err(()); // verify error
+ }
+ }
+
let progress = self.progress.clone().ok_or_else(|| ())?; // add error like OtaNotStarted
if progress.target_crc != progress.last_crc {
log::warn!("[OTA] Calculated crc: {:?}", progress.last_crc);
@@ -136,6 +144,31 @@ where
Ok(())
}
+ /// It reads written flash and checks crc
+ pub fn ota_verify(&mut self) -> Result<bool, ()> {
+ let progress = self.progress.clone().ok_or_else(|| ())?; // add error like OtaNotStarted
+ let mut calc_crc = 0;
+ let mut bytes = [0; OTA_VERIFY_READ_SIZE];
+
+ let mut partition_offset = self.pinfo.ota_partitions[progress.target_partition].0;
+ let mut remaining = progress.flash_size;
+
+ loop {
+ let n = remaining.min(OTA_VERIFY_READ_SIZE as u32);
+ if n == 0 {
+ break;
+ }
+
+ _ = self.flash.read(partition_offset, &mut bytes[..n as usize]);
+ partition_offset += n;
+ remaining -= n;
+
+ calc_crc = crc32::calc_crc32(&bytes[..n as usize], calc_crc);
+ }
+
+ Ok(calc_crc == progress.target_crc)
+ }
+
/// Sets ota boot target partition
pub fn set_target_ota_boot_partition(&mut self, target: usize) {
let (seq1, seq2) = self.get_ota_boot_sequences();