1- //! M2 Bootloader RUST
1+ //! M2 Bootloader RUST
22//! ------------------
33//! License : Dual License
44//! - Apache 2.0 for open-source / personal use
55//! - Commercial license required for closed-source use
66//! Author : Md Mahbubur Rahman
77//! URL : <https://m-a-h-b-u-b.github.io>
8- //! GitHub : <https://github.com/m-a-h-b-u-b/M2-Bootloader-RUST >
8+ //! GitHub : <https://github.com/m-a-h-b-u-b/M2-Bootloader-Rust >
99
10- pub fn check_for_update ( ) { }
10+ //! Firmware update handling module.
11+ //!
12+ //! This module manages the process of receiving, validating,
13+ //! and writing a new firmware image to flash memory. It builds
14+ //! upon the flash abstraction (`flash.rs`) and verification
15+ //! routines (`verify.rs`).
16+
17+ use crate :: flash:: { Flash , FlashError , Result } ;
18+ use crate :: verify:: { verify_crc} ;
19+
20+ /// Metadata describing the incoming firmware update.
21+ #[ derive( Debug , Clone , Copy ) ]
22+ pub struct UpdateMetadata {
23+ /// Absolute start address in flash where the new image will be written.
24+ pub target_addr : usize ,
25+ /// Total size of the firmware image in bytes.
26+ pub image_size : usize ,
27+ /// Expected CRC32 checksum of the entire image.
28+ pub expected_crc : u32 ,
29+ }
30+
31+ /// Possible errors during the update process.
32+ #[ derive( Debug ) ]
33+ pub enum UpdateError {
34+ Flash ( FlashError ) ,
35+ InvalidSize ,
36+ CrcMismatch ,
37+ TransferIncomplete ,
38+ Other ( & ' static str ) ,
39+ }
40+
41+ impl From < FlashError > for UpdateError {
42+ fn from ( e : FlashError ) -> Self {
43+ UpdateError :: Flash ( e)
44+ }
45+ }
46+
47+ pub type UpdateResult < T > = core:: result:: Result < T , UpdateError > ;
48+
49+ /// Handles the reception and flashing of a new firmware image.
50+ ///
51+ /// Typical workflow:
52+ /// 1. Call [`begin_update`] with metadata to erase target sectors.
53+ /// 2. Call [`write_chunk`] repeatedly to program image data.
54+ /// 3. Call [`finalize_update`] to verify CRC and finalize.
55+ pub struct FirmwareUpdater < ' a > {
56+ flash : & ' a mut dyn Flash ,
57+ meta : UpdateMetadata ,
58+ written : usize ,
59+ }
60+
61+ impl < ' a > FirmwareUpdater < ' a > {
62+ /// Prepare for a new firmware update by erasing the target region.
63+ pub fn begin_update ( flash : & ' a mut dyn Flash , meta : UpdateMetadata ) -> UpdateResult < Self > {
64+ if meta. image_size == 0 {
65+ return Err ( UpdateError :: InvalidSize ) ;
66+ }
67+ // Erase all sectors covering the target region.
68+ let mut addr = meta. target_addr ;
69+ while addr < meta. target_addr + meta. image_size {
70+ flash. erase_sector ( addr) ?;
71+ addr += flash. sector_size ( ) ;
72+ }
73+ Ok ( FirmwareUpdater { flash, meta, written : 0 } )
74+ }
75+
76+ /// Write a contiguous chunk of firmware data.
77+ /// The caller must supply chunks aligned to the flash page size.
78+ pub fn write_chunk ( & mut self , offset : usize , data : & [ u8 ] ) -> UpdateResult < ( ) > {
79+ if offset != self . written {
80+ return Err ( UpdateError :: Other ( "Offset mismatch" ) ) ;
81+ }
82+ let abs_addr = self . meta . target_addr + offset;
83+ self . flash . write_region ( abs_addr, data) ?;
84+ self . written += data. len ( ) ;
85+ Ok ( ( ) )
86+ }
87+
88+ /// Verify the written firmware image against the expected CRC.
89+ pub fn finalize_update ( mut self ) -> UpdateResult < ( ) > {
90+ if self . written != self . meta . image_size {
91+ return Err ( UpdateError :: TransferIncomplete ) ;
92+ }
93+ let ok = verify_crc ( self . flash , self . meta . target_addr , self . meta . image_size , self . meta . expected_crc )
94+ . map_err ( |e| UpdateError :: Flash ( e) ) ?;
95+ if !ok {
96+ return Err ( UpdateError :: CrcMismatch ) ;
97+ }
98+ Ok ( ( ) )
99+ }
100+ }
101+
102+ #[ cfg( test) ]
103+ mod tests {
104+ use super :: * ;
105+ use crate :: flash:: MockFlash ;
106+
107+ #[ test]
108+ fn test_firmware_update_flow ( ) {
109+ let mut mock = MockFlash :: new ( 4096 , 1024 , 256 ) ;
110+ let data = [ 0x42u8 ; 1024 ] ;
111+ let crc = mock. crc32 ( 0 , data. len ( ) ) . unwrap ( ) ; // computing CRC of empty flash (not used)
112+ // Instead compute CRC of our data.
113+ let mut tmp = MockFlash :: new ( 2048 , 1024 , 256 ) ;
114+ tmp. write_region ( 0 , & data) . unwrap ( ) ;
115+ let expected_crc = tmp. crc32 ( 0 , data. len ( ) ) . unwrap ( ) ;
116+
117+ let meta = UpdateMetadata {
118+ target_addr : 0 ,
119+ image_size : data. len ( ) ,
120+ expected_crc,
121+ } ;
122+
123+ let mut updater = FirmwareUpdater :: begin_update ( & mut mock, meta) . unwrap ( ) ;
124+ updater. write_chunk ( 0 , & data) . unwrap ( ) ;
125+ updater. finalize_update ( ) . unwrap ( ) ;
126+ }
127+ }
0 commit comments