eculocate

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 5fcf9acbe6ab4b3cc7f12f96a3b1bc431af1a4f2
parent 82545ae04b23b5f207347cd28f2dc3747b853ef1
Author: filipton <filipton12@gmail.com>
Date:   Fri,  5 Jul 2024 11:10:51 +0200

feat: crc checks and better ota interface

Diffstat:
Mexamples/src/main.rs | 12++++++++++--
Msimple-ota-server/src/main.rs | 4++--
Msrc/lib.rs | 93+++++++++++++++++++++++++++++++++++++++++--------------------------------------
3 files changed, 60 insertions(+), 49 deletions(-)

diff --git a/examples/src/main.rs b/examples/src/main.rs @@ -98,10 +98,18 @@ async fn main(spawner: Spawner) { .await .expect("Cannot read firmware size!"); let flash_size = u32::from_le_bytes(ota_buff[..4].try_into().unwrap()); + + socket + .read(&mut ota_buff[..4]) + .await + .expect("Cannot read target crc!"); + let target_crc = u32::from_le_bytes(ota_buff[..4].try_into().unwrap()); + log::info!("flash_size: {flash_size}"); + log::info!("target_crc: {target_crc}"); - let mut ota = Ota::new(FlashStorage::new()).with_next_partition_offset(); - ota.set_flash_size(flash_size); + let mut ota = Ota::new(FlashStorage::new()); + ota.ota_begin(flash_size, target_crc); let mut bytes_read = 0; loop { diff --git a/simple-ota-server/src/main.rs b/simple-ota-server/src/main.rs @@ -15,8 +15,8 @@ fn main() { println!("Connection"); let mut stream = stream.unwrap(); - let buf = (binary.len() as u32).to_le_bytes(); - _ = stream.write_all(&buf); + _ = stream.write_all(&(binary.len() as u32).to_le_bytes()); + _ = stream.write_all(&binary_crc.to_le_bytes()); let chunks = binary.chunks(4096 * 2); let mut buf = [0; 1]; diff --git a/src/lib.rs b/src/lib.rs @@ -17,6 +17,17 @@ pub const PARTITIONS: [core::ops::Range<u32>; PARTITIONS_COUNT] = [ pub const OTADATA_OFFSET: u32 = 0xd000; pub const OTADATA_SIZE: u32 = 0x2000; +#[derive(Clone)] +pub struct FlashProgress { + last_crc: u32, + flash_offset: u32, + flash_size: u32, + remaining: u32, + + target_partition: usize, + target_crc: u32, +} + // NOTE: I need to use generics, because after adding esp-storage dependency to // this project its not compiling LULE pub struct Ota<S> @@ -24,12 +35,7 @@ where S: ReadStorage + Storage, { flash: S, - - last_crc: u32, - ota_offset: Option<u32>, - target_partition: Option<usize>, - flash_size: u32, - ota_remaining: u32, + progress: Option<FlashProgress>, } // TODO: add OtaError enum @@ -41,78 +47,75 @@ where pub fn new(flash: S) -> Self { Ota { flash, - - last_crc: 0, - ota_offset: None, - target_partition: None, - ota_remaining: 0, - flash_size: 0, + progress: None, } } - /// Sets ota_offset as next partitions offset - pub fn with_next_partition_offset(self) -> Self { - let next_part = Self::get_next_ota_partition(); - let ota_offset = next_part.map(|i| PARTITIONS[i].start); + /// To begin ota update (need to provide flash size) + pub fn ota_begin(&mut self, size: u32, target_crc: u32) { + let next_part = Self::get_next_ota_partition().expect("Add error handling here"); + let ota_offset = PARTITIONS[next_part].start; - Ota { - ota_offset, + self.progress = Some(FlashProgress { + last_crc: 0, + flash_size: size, + remaining: size, + flash_offset: ota_offset, target_partition: next_part, - ..self - } - } - - /// Sets the firmware flash size - pub fn set_flash_size(&mut self, size: u32) { - self.ota_remaining = size; - self.flash_size = size; + target_crc, + }); } /// Returns ota progress in f32 (0..1) pub fn get_ota_progress(&self) -> f32 { - (self.flash_size - self.ota_remaining) as f32 / self.flash_size as f32 + if self.progress.is_none() { + log::warn!("[OTA] Cannot get ota progress! Seems like update wasn't started yet."); + return 0.0; + } + + let progress = self.progress.as_ref().expect("Add erorr handling here"); + (progress.flash_size - progress.remaining) as f32 / progress.flash_size as f32 } /// Writes next firmware chunk pub fn ota_write_chunk(&mut self, chunk: &[u8]) -> Result<bool, ()> { - if self.flash_size == 0 { - log::error!("[OTA] Cant write chunk without set_flash_size()"); - return Err(()); - } - - if self.ota_remaining == 0 { + let progress = self.progress.as_mut().ok_or_else(|| ())?; // add error like OtaNotStarted + if progress.remaining == 0 { return Ok(true); } - let ota_offset = self.ota_offset.as_mut().ok_or_else(|| ())?; let write_size = chunk.len() as u32; - let write_size = write_size.min(self.ota_remaining) as usize; + let write_size = write_size.min(progress.remaining) as usize; self.flash - .write(*ota_offset, &chunk[..write_size]) + .write(progress.flash_offset, &chunk[..write_size]) .map_err(|_| ())?; log::debug!( "[OTA] Wrote {} bytes to ota partition at 0x{:x}", write_size, - ota_offset + progress.flash_offset ); - self.last_crc = crc32::calc_crc32(&chunk[..write_size], self.last_crc); + progress.last_crc = crc32::calc_crc32(&chunk[..write_size], progress.last_crc); - *ota_offset += write_size as u32; - self.ota_remaining -= write_size as u32; - Ok(self.ota_remaining == 0) + progress.flash_offset += write_size as u32; + progress.remaining -= write_size as u32; + Ok(progress.remaining == 0) } // TODO: crc checks or sth pub fn ota_flush(&mut self) -> Result<(), ()> { - if let Some(target_partition) = self.target_partition { - self.set_target_ota_boot_partition(target_partition); - } + let progress = self.progress.clone().ok_or_else(|| ())?; // add error like OtaNotStarted + if progress.target_crc != progress.last_crc { + log::info!("[OTA] Calculated crc: {:?}", progress.last_crc); + log::info!("[OTA] Target crc: {:?}", progress.target_crc); + log::error!("[OTA] Crc check failed! Cant finish ota update..."); - log::info!("Calculated crc hash: {:?}", self.last_crc); + return Err(()); // wrong crc err or sth like this + } + self.set_target_ota_boot_partition(progress.target_partition); Ok(()) }