@@ -42,9 +42,11 @@ enum Pos {
4242 SerialRevision ,
4343 ByteCount ,
4444 Data ,
45- // Byte following a 0x7d
45+ // Byte following a 0x7d in Data state
4646 DataEscaped ,
4747 Check ,
48+ // Byte following a 0x7d in Check state (FCS bytes can also be escaped)
49+ CheckEscaped ,
4850 FrameEnd ,
4951}
5052
@@ -192,7 +194,31 @@ impl MctpSerialHandler {
192194 }
193195 }
194196 Pos :: Check => {
195- self . rxbuf . push ( b) . unwrap ( ) ;
197+ match b {
198+ // Unexpected framing, restart
199+ FRAMING_FLAG => self . rxpos = Pos :: SerialRevision ,
200+ FRAMING_ESCAPE => self . rxpos = Pos :: CheckEscaped ,
201+ _ => {
202+ self . rxbuf . push ( b) . unwrap ( ) ;
203+ if self . rxbuf . len ( ) == self . rxcount + RXBUF_FRAMING {
204+ self . rxpos = Pos :: FrameEnd ;
205+ }
206+ }
207+ }
208+ }
209+ Pos :: CheckEscaped => {
210+ match b {
211+ FLAG_ESCAPED => {
212+ self . rxbuf . push ( FRAMING_FLAG ) . unwrap ( ) ;
213+ self . rxpos = Pos :: Check ;
214+ }
215+ ESCAPE_ESCAPED => {
216+ self . rxbuf . push ( FRAMING_ESCAPE ) . unwrap ( ) ;
217+ self . rxpos = Pos :: Check ;
218+ }
219+ // Unexpected escape, restart
220+ _ => self . rxpos = Pos :: FrameSearch ,
221+ }
196222 if self . rxbuf . len ( ) == self . rxcount + RXBUF_FRAMING {
197223 self . rxpos = Pos :: FrameEnd ;
198224 }
@@ -261,7 +287,7 @@ impl MctpSerialHandler {
261287
262288 output. write_all ( & start) . await ?;
263289 Self :: write_escaped_async ( p, output) . await ?;
264- output . write_all ( & cs. to_be_bytes ( ) ) . await ?;
290+ Self :: write_escaped_async ( & cs. to_be_bytes ( ) , output ) . await ?;
265291 output. write_all ( & [ FRAMING_FLAG ] ) . await ?;
266292 Ok ( ( ) )
267293 }
@@ -285,7 +311,7 @@ impl MctpSerialHandler {
285311
286312 output. write_all ( & start) ?;
287313 Self :: write_escaped_sync ( p, output) ?;
288- output . write_all ( & cs. to_be_bytes ( ) ) ?;
314+ Self :: write_escaped_sync ( & cs. to_be_bytes ( ) , output ) ?;
289315 output. write_all ( & [ FRAMING_FLAG ] ) ?;
290316 Ok ( ( ) )
291317 }
@@ -432,4 +458,154 @@ mod tests {
432458 do_roundtrip_sync( & payload)
433459 }
434460 }
461+
462+ /// Helper to parse a manually-constructed frame
463+ fn parse_frame ( frame : & [ u8 ] ) -> std:: vec:: Vec < u8 > {
464+ let mut h = MctpSerialHandler :: new ( ) ;
465+ let mut s = frame;
466+ h. recv_sync ( & mut s) . unwrap ( ) . to_vec ( )
467+ }
468+
469+ // Test vectors with known FCS values:
470+ // payload=[01, 00, 00, 00, 00, 49] -> FCS=[7e, 10] (FLAG in first byte)
471+ // payload=[01, 00, 00, 00, 00, 65] -> FCS=[95, 7e] (FLAG in second byte)
472+ // payload=[01, 00, 00, 00, 00, 7a] -> FCS=[7d, 08] (ESCAPE in first byte)
473+ // payload=[01, 00, 00, 00, 01, 7f] -> FCS=[33, 7d] (ESCAPE in second byte)
474+ // payload=[01, 00, 00, 00, 16, cd] -> FCS=[7d, 7d] (both bytes need escaping)
475+
476+ /// Test FCS with 0x7e (FLAG) in first byte
477+ #[ test]
478+ fn fcs_escape_flag_first_byte ( ) {
479+ start_log ( ) ;
480+ // payload produces FCS = [0x7e, 0x10]
481+ let payload = [ 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x49 ] ;
482+ do_roundtrip_sync ( & payload) ;
483+
484+ // Also test RX directly with manually escaped frame
485+ let frame = [
486+ FRAMING_FLAG ,
487+ 0x01 ,
488+ 0x06 , // revision, length
489+ 0x01 ,
490+ 0x00 ,
491+ 0x00 ,
492+ 0x00 ,
493+ 0x00 ,
494+ 0x49 , // payload
495+ FRAMING_ESCAPE ,
496+ FLAG_ESCAPED ,
497+ 0x10 , // FCS with escaped first byte
498+ FRAMING_FLAG ,
499+ ] ;
500+ assert_eq ! ( parse_frame( & frame) , payload) ;
501+ }
502+
503+ /// Test FCS with 0x7e (FLAG) in second byte
504+ #[ test]
505+ fn fcs_escape_flag_second_byte ( ) {
506+ start_log ( ) ;
507+ // payload produces FCS = [0x95, 0x7e]
508+ let payload = [ 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x65 ] ;
509+ do_roundtrip_sync ( & payload) ;
510+
511+ // Also test RX directly with manually escaped frame
512+ let frame = [
513+ FRAMING_FLAG ,
514+ 0x01 ,
515+ 0x06 , // revision, length
516+ 0x01 ,
517+ 0x00 ,
518+ 0x00 ,
519+ 0x00 ,
520+ 0x00 ,
521+ 0x65 , // payload
522+ 0x95 ,
523+ FRAMING_ESCAPE ,
524+ FLAG_ESCAPED , // FCS with escaped second byte
525+ FRAMING_FLAG ,
526+ ] ;
527+ assert_eq ! ( parse_frame( & frame) , payload) ;
528+ }
529+
530+ /// Test FCS with 0x7d (ESCAPE) in first byte
531+ #[ test]
532+ fn fcs_escape_escape_first_byte ( ) {
533+ start_log ( ) ;
534+ // payload produces FCS = [0x7d, 0x08]
535+ let payload = [ 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x7a ] ;
536+ do_roundtrip_sync ( & payload) ;
537+
538+ // Also test RX directly with manually escaped frame
539+ let frame = [
540+ FRAMING_FLAG ,
541+ 0x01 ,
542+ 0x06 , // revision, length
543+ 0x01 ,
544+ 0x00 ,
545+ 0x00 ,
546+ 0x00 ,
547+ 0x00 ,
548+ 0x7a , // payload
549+ FRAMING_ESCAPE ,
550+ ESCAPE_ESCAPED ,
551+ 0x08 , // FCS with escaped first byte
552+ FRAMING_FLAG ,
553+ ] ;
554+ assert_eq ! ( parse_frame( & frame) , payload) ;
555+ }
556+
557+ /// Test FCS with 0x7d (ESCAPE) in second byte
558+ #[ test]
559+ fn fcs_escape_escape_second_byte ( ) {
560+ start_log ( ) ;
561+ // payload produces FCS = [0x33, 0x7d]
562+ let payload = [ 0x01 , 0x00 , 0x00 , 0x00 , 0x01 , 0x7f ] ;
563+ do_roundtrip_sync ( & payload) ;
564+
565+ // Also test RX directly with manually escaped frame
566+ let frame = [
567+ FRAMING_FLAG ,
568+ 0x01 ,
569+ 0x06 , // revision, length
570+ 0x01 ,
571+ 0x00 ,
572+ 0x00 ,
573+ 0x00 ,
574+ 0x01 ,
575+ 0x7f , // payload
576+ 0x33 ,
577+ FRAMING_ESCAPE ,
578+ ESCAPE_ESCAPED , // FCS with escaped second byte
579+ FRAMING_FLAG ,
580+ ] ;
581+ assert_eq ! ( parse_frame( & frame) , payload) ;
582+ }
583+
584+ /// Test FCS where both bytes need escaping
585+ #[ test]
586+ fn fcs_escape_both_bytes ( ) {
587+ start_log ( ) ;
588+ // payload produces FCS = [0x7d, 0x7d]
589+ let payload = [ 0x01 , 0x00 , 0x00 , 0x00 , 0x16 , 0xcd ] ;
590+ do_roundtrip_sync ( & payload) ;
591+
592+ // Also test RX directly with manually escaped frame
593+ let frame = [
594+ FRAMING_FLAG ,
595+ 0x01 ,
596+ 0x06 , // revision, length
597+ 0x01 ,
598+ 0x00 ,
599+ 0x00 ,
600+ 0x00 ,
601+ 0x16 ,
602+ 0xcd , // payload
603+ FRAMING_ESCAPE ,
604+ ESCAPE_ESCAPED , // first FCS byte escaped
605+ FRAMING_ESCAPE ,
606+ ESCAPE_ESCAPED , // second FCS byte escaped
607+ FRAMING_FLAG ,
608+ ] ;
609+ assert_eq ! ( parse_frame( & frame) , payload) ;
610+ }
435611}
0 commit comments