@@ -8,6 +8,8 @@ use std::{
88use md5:: { Context , Digest } ;
99use regex:: Regex ;
1010use serde:: { Deserialize , Deserializer , Serialize } ;
11+ use strum:: IntoEnumIterator ;
12+ use strum_macros:: EnumIter ;
1113
1214use crate :: error:: {
1315 CSVError , DuplicatePartitionsError , InvalidSubTypeError , NoAppError ,
@@ -16,10 +18,11 @@ use crate::error::{
1618
1719const MAX_PARTITION_LENGTH : usize = 0xC00 ;
1820const PARTITION_TABLE_SIZE : usize = 0x1000 ;
21+ const PARTITION_SIZE : usize = 32 ;
22+ const PARTITION_ALIGNMENT : u32 = 0x10000 ;
1923
2024#[ derive( Copy , Clone , Debug , Deserialize , Serialize , PartialEq ) ]
2125#[ repr( u8 ) ]
22- #[ allow( dead_code) ]
2326#[ serde( rename_all = "lowercase" ) ]
2427pub enum Type {
2528 App = 0x00 ,
@@ -29,21 +32,14 @@ pub enum Type {
2932impl Type {
3033 pub fn subtype_hint ( & self ) -> String {
3134 match self {
32- Type :: App => "'factory', 'ota_0' through 'ota_15' and 'test'" . into ( ) ,
35+ Type :: App => "'factory', 'ota_0' through 'ota_15', and 'test'" . into ( ) ,
3336 Type :: Data => {
34- use DataType :: * ;
35- let types = [
36- Ota , Phy , Nvs , CoreDump , NvsKeys , EFuse , EspHttpd , Fat , Spiffs ,
37- ] ;
38-
39- let mut out = format ! ( "'{}'" , serde_plain:: to_string( & types[ 0 ] ) . unwrap( ) ) ;
40- for ty in & types[ 1 ..types. len ( ) - 2 ] {
41- let ser = serde_plain:: to_string ( & ty) . unwrap ( ) ;
42- write ! ( & mut out, ", '{}'" , ser) . unwrap ( ) ;
43- }
37+ let types = DataType :: iter ( )
38+ . map ( |dt| format ! ( "'{}'" , serde_plain:: to_string( & dt) . unwrap( ) ) )
39+ . collect :: < Vec < _ > > ( ) ;
4440
45- let ser = serde_plain :: to_string ( & types[ types. len ( ) - 1 ] ) . unwrap ( ) ;
46- write ! ( & mut out, " and '{}' " , ser ) . unwrap ( ) ;
41+ let mut out = types[ 0 .. types. len ( ) - 2 ] . join ( ", " ) ;
42+ write ! ( & mut out, ", and {} " , types [ types . len ( ) - 1 ] ) . unwrap ( ) ;
4743
4844 out
4945 }
@@ -52,16 +48,15 @@ impl Type {
5248}
5349
5450impl Display for Type {
55- fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
51+ fn fmt ( & self , f : & mut Formatter ) -> std:: fmt:: Result {
5652 write ! ( f, "{}" , serde_plain:: to_string( self ) . unwrap( ) )
5753 }
5854}
5955
6056#[ derive( Copy , Clone , Debug , Deserialize , Serialize , PartialEq ) ]
6157#[ repr( u8 ) ]
62- #[ allow( dead_code) ]
63- #[ serde( rename_all = "lowercase" ) ]
6458pub enum AppType {
59+ #[ serde( rename = "factory" ) ]
6560 Factory = 0x00 ,
6661 #[ serde( rename = "ota_0" ) ]
6762 Ota0 = 0x10 ,
@@ -95,12 +90,12 @@ pub enum AppType {
9590 Ota14 = 0x1e ,
9691 #[ serde( rename = "ota_15" ) ]
9792 Ota15 = 0x1f ,
93+ #[ serde( rename = "test" ) ]
9894 Test = 0x20 ,
9995}
10096
101- #[ derive( Copy , Clone , Debug , Deserialize , Serialize , PartialEq ) ]
97+ #[ derive( Copy , Clone , Debug , Deserialize , EnumIter , Serialize , PartialEq ) ]
10298#[ repr( u8 ) ]
103- #[ allow( dead_code) ]
10499#[ serde( rename_all = "lowercase" ) ]
105100pub enum DataType {
106101 Ota = 0x00 ,
@@ -122,20 +117,20 @@ impl DataType {
122117}
123118
124119#[ derive( Debug , Deserialize , PartialEq , Copy , Clone ) ]
125- #[ allow( dead_code) ]
126120#[ serde( untagged) ]
127121pub enum SubType {
128122 App ( AppType ) ,
129123 Data ( DataType ) ,
130124}
131125
132126impl Display for SubType {
133- fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
127+ fn fmt ( & self , f : & mut Formatter ) -> std:: fmt:: Result {
134128 let ser = match self {
135129 SubType :: App ( sub) => serde_plain:: to_string ( sub) ,
136130 SubType :: Data ( sub) => serde_plain:: to_string ( sub) ,
137131 }
138132 . unwrap ( ) ;
133+
139134 write ! ( f, "{}" , ser)
140135 }
141136}
@@ -156,6 +151,18 @@ impl SubType {
156151 }
157152}
158153
154+ #[ derive( Copy , Clone , Debug , Deserialize , Serialize , PartialEq ) ]
155+ #[ serde( rename_all = "lowercase" ) ]
156+ pub enum Flags {
157+ Encrypted = 0x1 ,
158+ }
159+
160+ impl Flags {
161+ pub fn as_u32 ( & self ) -> u32 {
162+ * self as u32
163+ }
164+ }
165+
159166#[ derive( Debug ) ]
160167pub struct PartitionTable {
161168 partitions : Vec < Partition > ,
@@ -202,7 +209,10 @@ impl PartitionTable {
202209 /// Attempt to parse a partition table from the given string. For more
203210 /// information on the partition table CSV format see:
204211 /// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html
205- pub fn try_from_str < S : Into < String > > ( data : S ) -> Result < Self , PartitionTableError > {
212+ pub fn try_from_str < S > ( data : S ) -> Result < Self , PartitionTableError >
213+ where
214+ S : Into < String > ,
215+ {
206216 let data = data. into ( ) ;
207217 let mut reader = csv:: ReaderBuilder :: new ( )
208218 . comment ( Some ( b'#' ) )
@@ -213,32 +223,39 @@ impl PartitionTable {
213223 // Default offset is 0x8000 in esp-idf, partition table size is 0x1000
214224 let mut offset = 0x9000 ;
215225 let mut partitions = Vec :: with_capacity ( data. lines ( ) . count ( ) ) ;
226+
216227 for record in reader. records ( ) {
217228 let record = record. map_err ( |e| CSVError :: new ( e, data. clone ( ) ) ) ?;
218229 let position = record. position ( ) ;
230+
219231 let mut partition: DeserializedPartition = record
220232 . deserialize ( None )
221233 . map_err ( |e| CSVError :: new ( e, data. clone ( ) ) ) ?;
222-
223234 partition. fixup_offset ( & mut offset) ;
224235
225236 let mut partition = Partition :: from ( partition) ;
226237 partition. line = position. map ( |pos| pos. line ( ) as usize ) ;
238+
227239 partitions. push ( partition) ;
228240 }
229241
230242 let table = Self { partitions } ;
231243 table. validate ( & data) ?;
244+
232245 Ok ( table)
233246 }
234247
235248 pub fn to_bytes ( & self ) -> Vec < u8 > {
236249 let mut result = Vec :: with_capacity ( PARTITION_TABLE_SIZE ) ;
237250 self . save ( & mut result) . unwrap ( ) ;
251+
238252 result
239253 }
240254
241- pub fn save < W : Write > ( & self , writer : & mut W ) -> std:: io:: Result < ( ) > {
255+ pub fn save < W > ( & self , writer : & mut W ) -> std:: io:: Result < ( ) >
256+ where
257+ W : Write ,
258+ {
242259 let mut hasher = HashWriter :: new ( writer) ;
243260 for partition in & self . partitions {
244261 partition. save ( & mut hasher) ?;
@@ -286,7 +303,7 @@ impl PartitionTable {
286303 . into ( ) ) ;
287304 }
288305
289- if partition. ty == Type :: App && partition. offset . rem ( 0x10000 ) != 0 {
306+ if partition. ty == Type :: App && partition. offset . rem ( PARTITION_ALIGNMENT ) != 0 {
290307 return Err ( UnalignedPartitionError :: new ( source, * line) . into ( ) ) ;
291308 }
292309 }
@@ -330,8 +347,6 @@ impl PartitionTable {
330347 }
331348}
332349
333- const PARTITION_SIZE : usize = 32 ;
334-
335350#[ derive( Debug , Deserialize ) ]
336351pub struct DeserializedPartition {
337352 #[ serde( deserialize_with = "deserialize_partition_name" ) ]
@@ -342,13 +357,13 @@ pub struct DeserializedPartition {
342357 offset : Option < u32 > ,
343358 #[ serde( deserialize_with = "deserialize_partition_size" ) ]
344359 size : u32 ,
345- flags : Option < u32 > ,
360+ flags : Option < Flags > ,
346361}
347362
348363impl DeserializedPartition {
349364 fn align ( offset : u32 , ty : Type ) -> u32 {
350365 let pad = match ty {
351- Type :: App => 0x10000 ,
366+ Type :: App => PARTITION_ALIGNMENT ,
352367 Type :: Data => 4 ,
353368 } ;
354369
@@ -368,28 +383,14 @@ impl DeserializedPartition {
368383 }
369384}
370385
371- impl From < DeserializedPartition > for Partition {
372- fn from ( part : DeserializedPartition ) -> Self {
373- Partition {
374- name : part. name ,
375- ty : part. ty ,
376- sub_type : part. sub_type ,
377- offset : part. offset . unwrap ( ) ,
378- size : part. size ,
379- flags : part. flags ,
380- line : None ,
381- }
382- }
383- }
384-
385386#[ derive( Debug ) ]
386387pub struct Partition {
387388 name : String ,
388389 ty : Type ,
389390 sub_type : SubType ,
390391 offset : u32 ,
391392 size : u32 ,
392- flags : Option < u32 > ,
393+ flags : Option < Flags > ,
393394 line : Option < usize > ,
394395}
395396
@@ -399,7 +400,7 @@ impl Partition {
399400 sub_type : SubType ,
400401 offset : u32 ,
401402 size : u32 ,
402- flags : Option < u32 > ,
403+ flags : Option < Flags > ,
403404 ) -> Self {
404405 Partition {
405406 name,
@@ -415,7 +416,10 @@ impl Partition {
415416 }
416417 }
417418
418- pub fn save < W : Write > ( & self , writer : & mut W ) -> std:: io:: Result < ( ) > {
419+ pub fn save < W > ( & self , writer : & mut W ) -> std:: io:: Result < ( ) >
420+ where
421+ W : Write ,
422+ {
419423 writer. write_all ( & [ 0xAA , 0x50 ] ) ?;
420424 writer. write_all ( & [ self . ty as u8 , self . sub_type . as_u8 ( ) ] ) ?;
421425 writer. write_all ( & self . offset . to_le_bytes ( ) ) ?;
@@ -428,7 +432,7 @@ impl Partition {
428432 writer. write_all ( & name_bytes) ?;
429433
430434 let flags = match & self . flags {
431- Some ( f) => f. to_le_bytes ( ) ,
435+ Some ( f) => f. as_u32 ( ) . to_le_bytes ( ) ,
432436 None => 0u32 . to_le_bytes ( ) ,
433437 } ;
434438 writer. write_all ( & flags) ?;
@@ -440,11 +444,29 @@ impl Partition {
440444 self . offset
441445 }
442446
447+ pub fn flags ( & self ) -> Option < Flags > {
448+ self . flags
449+ }
450+
443451 fn overlaps ( & self , other : & Partition ) -> bool {
444452 max ( self . offset , other. offset ) < min ( self . offset + self . size , other. offset + other. size )
445453 }
446454}
447455
456+ impl From < DeserializedPartition > for Partition {
457+ fn from ( p : DeserializedPartition ) -> Self {
458+ Partition {
459+ name : p. name ,
460+ ty : p. ty ,
461+ sub_type : p. sub_type ,
462+ offset : p. offset . unwrap ( ) ,
463+ size : p. size ,
464+ flags : p. flags ,
465+ line : None ,
466+ }
467+ }
468+ }
469+
448470fn deserialize_partition_name < ' de , D > ( deserializer : D ) -> Result < String , D :: Error >
449471where
450472 D : Deserializer < ' de > ,
@@ -511,16 +533,20 @@ where
511533 D : Deserializer < ' de > ,
512534{
513535 use serde:: de:: Error ;
536+
514537 let deserialized = deserialize_partition_offset_or_size ( deserializer) ?;
515538 deserialized. ok_or_else ( || Error :: custom ( "invalid partition size/offset format" ) )
516539}
517540
518- struct HashWriter < W : Write > {
541+ struct HashWriter < W > {
519542 inner : W ,
520543 hasher : Context ,
521544}
522545
523- impl < W : Write > Write for HashWriter < W > {
546+ impl < W > Write for HashWriter < W >
547+ where
548+ W : Write ,
549+ {
524550 fn write ( & mut self , buf : & [ u8 ] ) -> std:: io:: Result < usize > {
525551 self . hasher . write_all ( buf) ?;
526552 self . inner . write ( buf)
@@ -531,7 +557,10 @@ impl<W: Write> Write for HashWriter<W> {
531557 }
532558}
533559
534- impl < W : Write > HashWriter < W > {
560+ impl < W > HashWriter < W >
561+ where
562+ W : Write ,
563+ {
535564 pub fn new ( inner : W ) -> Self {
536565 HashWriter {
537566 inner,
@@ -553,7 +582,7 @@ mod tests {
553582# Name, Type, SubType, Offset, Size, Flags
554583nvs, data, nvs, 0x9000, 0x6000,
555584phy_init, data, phy, 0xf000, 0x1000,
556- factory, app, factory, 0x10000, 1M,
585+ factory, app, factory, 0x10000, 1M, encrypted
557586" ;
558587
559588 const PTABLE_1 : & str = "
@@ -644,6 +673,12 @@ phy_init, data, phy, 0xf000, 0x1000,
644673 let pt0 = PartitionTable :: try_from_str ( PTABLE_0 ) ;
645674 assert ! ( pt0. is_ok( ) ) ;
646675
676+ let pt0 = pt0. unwrap ( ) ;
677+ let nvs = pt0. find ( "nvs" ) . unwrap ( ) ;
678+ let fac = pt0. find ( "factory" ) . unwrap ( ) ;
679+ assert_eq ! ( nvs. flags( ) , None ) ;
680+ assert_eq ! ( fac. flags( ) , Some ( Flags :: Encrypted ) ) ;
681+
647682 let pt1 = PartitionTable :: try_from_str ( PTABLE_1 ) ;
648683 assert ! ( pt1. is_ok( ) ) ;
649684
@@ -652,6 +687,7 @@ phy_init, data, phy, 0xf000, 0x1000,
652687
653688 PartitionTable :: try_from_str ( PTABLE_NO_FACTORY )
654689 . expect ( "Failed to parse partition table without factory partition" ) ;
690+
655691 PartitionTable :: try_from_str ( PTABLE_NO_APP )
656692 . expect_err ( "Failed to reject partition table without factory or ota partition" ) ;
657693 }
0 commit comments