@@ -40,6 +40,38 @@ pub struct InfoData {
4040impl InfoData {
4141 /// Encoded size in bytes.
4242 pub const SIZE : u16 = core:: mem:: size_of :: < Self > ( ) as u16 ;
43+
44+ /// Decode from the start of `bytes` (little-endian fields in declaration
45+ /// order); `None` when `bytes` is shorter than [`SIZE`](Self::SIZE).
46+ /// Bytes past `SIZE` are ignored, so a longer reply from a newer device
47+ /// still decodes.
48+ pub fn from_bytes ( bytes : & [ u8 ] ) -> Option < Self > {
49+ let b = bytes. get ( ..Self :: SIZE as usize ) ?;
50+ Some ( Self {
51+ capacity : u32:: from_le_bytes ( [ b[ 0 ] , b[ 1 ] , b[ 2 ] , b[ 3 ] ] ) ,
52+ erase_size : u16:: from_le_bytes ( [ b[ 4 ] , b[ 5 ] ] ) ,
53+ boot_version : u16:: from_le_bytes ( [ b[ 6 ] , b[ 7 ] ] ) ,
54+ app_version : u16:: from_le_bytes ( [ b[ 8 ] , b[ 9 ] ] ) ,
55+ mode : b[ 10 ] ,
56+ boot_baud : b[ 11 ] ,
57+ compat : u32:: from_le_bytes ( [ b[ 12 ] , b[ 13 ] , b[ 14 ] , b[ 15 ] ] ) ,
58+ max_payload : u16:: from_le_bytes ( [ b[ 16 ] , b[ 17 ] ] ) ,
59+ } )
60+ }
61+
62+ /// Encode as little-endian fields in declaration order.
63+ pub fn to_bytes ( & self ) -> [ u8 ; Self :: SIZE as usize ] {
64+ let mut b = [ 0 ; Self :: SIZE as usize ] ;
65+ b[ 0 ..4 ] . copy_from_slice ( & { self . capacity } . to_le_bytes ( ) ) ;
66+ b[ 4 ..6 ] . copy_from_slice ( & { self . erase_size } . to_le_bytes ( ) ) ;
67+ b[ 6 ..8 ] . copy_from_slice ( & { self . boot_version } . to_le_bytes ( ) ) ;
68+ b[ 8 ..10 ] . copy_from_slice ( & { self . app_version } . to_le_bytes ( ) ) ;
69+ b[ 10 ] = self . mode ;
70+ b[ 11 ] = self . boot_baud ;
71+ b[ 12 ..16 ] . copy_from_slice ( & { self . compat } . to_le_bytes ( ) ) ;
72+ b[ 16 ..18 ] . copy_from_slice ( & { self . max_payload } . to_le_bytes ( ) ) ;
73+ b
74+ }
4375}
4476
4577/// Typed Erase request data.
@@ -50,6 +82,27 @@ pub struct EraseData {
5082 pub byte_count : u16 ,
5183}
5284
85+ impl EraseData {
86+ /// Encoded size in bytes.
87+ pub const SIZE : u16 = core:: mem:: size_of :: < Self > ( ) as u16 ;
88+
89+ /// Decode from the start of `bytes` (little-endian fields in declaration
90+ /// order); `None` when `bytes` is shorter than [`SIZE`](Self::SIZE).
91+ /// Bytes past `SIZE` are ignored, so a longer reply from a newer device
92+ /// still decodes.
93+ pub fn from_bytes ( bytes : & [ u8 ] ) -> Option < Self > {
94+ let b = bytes. get ( ..Self :: SIZE as usize ) ?;
95+ Some ( Self {
96+ byte_count : u16:: from_le_bytes ( [ b[ 0 ] , b[ 1 ] ] ) ,
97+ } )
98+ }
99+
100+ /// Encode as little-endian fields in declaration order.
101+ pub fn to_bytes ( & self ) -> [ u8 ; Self :: SIZE as usize ] {
102+ self . byte_count . to_le_bytes ( )
103+ }
104+ }
105+
53106/// Typed Verify response data.
54107#[ repr( C ) ]
55108#[ derive( Clone , Copy ) ]
@@ -58,6 +111,27 @@ pub struct VerifyData {
58111 pub crc : u16 ,
59112}
60113
114+ impl VerifyData {
115+ /// Encoded size in bytes.
116+ pub const SIZE : u16 = core:: mem:: size_of :: < Self > ( ) as u16 ;
117+
118+ /// Decode from the start of `bytes` (little-endian fields in declaration
119+ /// order); `None` when `bytes` is shorter than [`SIZE`](Self::SIZE).
120+ /// Bytes past `SIZE` are ignored, so a longer reply from a newer device
121+ /// still decodes.
122+ pub fn from_bytes ( bytes : & [ u8 ] ) -> Option < Self > {
123+ let b = bytes. get ( ..Self :: SIZE as usize ) ?;
124+ Some ( Self {
125+ crc : u16:: from_le_bytes ( [ b[ 0 ] , b[ 1 ] ] ) ,
126+ } )
127+ }
128+
129+ /// Encode as little-endian fields in declaration order.
130+ pub fn to_bytes ( & self ) -> [ u8 ; Self :: SIZE as usize ] {
131+ self . crc . to_le_bytes ( )
132+ }
133+ }
134+
61135/// Per-command flags occupying addr byte 3.
62136///
63137/// Each command can define its own bitflags type as a union variant.
@@ -448,6 +522,89 @@ mod tests {
448522 assert_eq ! ( InfoData :: SIZE , 18 ) ;
449523 }
450524
525+ fn union_bytes < const L : usize > ( d : & Data ) -> [ u8 ; L ] {
526+ let mut b = [ 0 ; L ] ;
527+ b. copy_from_slice ( unsafe { & d. raw [ ..L ] } ) ;
528+ b
529+ }
530+
531+ fn info ( ) -> InfoData {
532+ InfoData {
533+ capacity : 0x0403_0201 ,
534+ erase_size : 0x0605 ,
535+ boot_version : 0x0807 ,
536+ app_version : 0x0A09 ,
537+ mode : 0x0B ,
538+ boot_baud : 0x0C ,
539+ compat : 0x100F_0E0D ,
540+ max_payload : 0x1211 ,
541+ }
542+ }
543+
544+ fn assert_info_eq ( a : & InfoData , b : & InfoData ) {
545+ assert_eq ! ( { a. capacity } , { b. capacity } ) ;
546+ assert_eq ! ( { a. erase_size } , { b. erase_size } ) ;
547+ assert_eq ! ( { a. boot_version } , { b. boot_version } ) ;
548+ assert_eq ! ( { a. app_version } , { b. app_version } ) ;
549+ assert_eq ! ( a. mode, b. mode) ;
550+ assert_eq ! ( a. boot_baud, b. boot_baud) ;
551+ assert_eq ! ( { a. compat } , { b. compat } ) ;
552+ assert_eq ! ( { a. max_payload } , { b. max_payload } ) ;
553+ }
554+
555+ #[ test]
556+ fn info_bytes_match_union ( ) {
557+ let d = Data { info : info ( ) } ;
558+ let raw = union_bytes :: < { InfoData :: SIZE as usize } > ( & d) ;
559+ assert_info_eq ( & InfoData :: from_bytes ( & raw) . unwrap ( ) , & info ( ) ) ;
560+ assert_eq ! ( info( ) . to_bytes( ) , raw) ;
561+ }
562+
563+ #[ test]
564+ fn info_from_bytes_length ( ) {
565+ let raw = info ( ) . to_bytes ( ) ;
566+ assert ! ( InfoData :: from_bytes( & raw[ ..raw. len( ) - 1 ] ) . is_none( ) ) ;
567+ let mut long = [ 0xEE ; InfoData :: SIZE as usize + 3 ] ;
568+ long[ ..raw. len ( ) ] . copy_from_slice ( & raw) ;
569+ assert_info_eq ( & InfoData :: from_bytes ( & long) . unwrap ( ) , & info ( ) ) ;
570+ }
571+
572+ #[ test]
573+ fn erase_bytes_match_union ( ) {
574+ let d = Data {
575+ erase : EraseData { byte_count : 0x0201 } ,
576+ } ;
577+ let raw = union_bytes :: < { EraseData :: SIZE as usize } > ( & d) ;
578+ assert_eq ! ( EraseData :: from_bytes( & raw) . unwrap( ) . byte_count, 0x0201 ) ;
579+ assert_eq ! ( EraseData { byte_count: 0x0201 } . to_bytes( ) , raw) ;
580+ }
581+
582+ #[ test]
583+ fn erase_from_bytes_length ( ) {
584+ assert_eq ! ( EraseData :: SIZE , 2 ) ;
585+ assert ! ( EraseData :: from_bytes( & [ 0x01 ] ) . is_none( ) ) ;
586+ let long = [ 0x01 , 0x02 , 0xEE , 0xEE , 0xEE ] ;
587+ assert_eq ! ( EraseData :: from_bytes( & long) . unwrap( ) . byte_count, 0x0201 ) ;
588+ }
589+
590+ #[ test]
591+ fn verify_bytes_match_union ( ) {
592+ let d = Data {
593+ verify : VerifyData { crc : 0x0201 } ,
594+ } ;
595+ let raw = union_bytes :: < { VerifyData :: SIZE as usize } > ( & d) ;
596+ assert_eq ! ( VerifyData :: from_bytes( & raw) . unwrap( ) . crc, 0x0201 ) ;
597+ assert_eq ! ( VerifyData { crc: 0x0201 } . to_bytes( ) , raw) ;
598+ }
599+
600+ #[ test]
601+ fn verify_from_bytes_length ( ) {
602+ assert_eq ! ( VerifyData :: SIZE , 2 ) ;
603+ assert ! ( VerifyData :: from_bytes( & [ 0x01 ] ) . is_none( ) ) ;
604+ let long = [ 0x01 , 0x02 , 0xEE , 0xEE , 0xEE ] ;
605+ assert_eq ! ( VerifyData :: from_bytes( & long) . unwrap( ) . crc, 0x0201 ) ;
606+ }
607+
451608 #[ test]
452609 fn large_payload_round_trip ( ) {
453610 let data = [ 0x3C ; 240 ] ;
0 commit comments