22// Licensed under the EUPL-1.2
33
44use winnow:: binary;
5+ use winnow:: binary:: bits;
56use winnow:: combinator:: { alt, cut_err, preceded} ;
67use winnow:: error:: { AddContext , ErrMode , ErrorKind , ParserError , StrContext } ;
78use winnow:: prelude:: * ;
89use winnow:: stream:: Stream ;
910use winnow:: Bytes ;
1011
11- use super :: error:: MBResult ;
12+ use super :: error:: { MBResult , MBusError } ;
1213
1314const LONG_FRAME_HEADER : u8 = 0x68 ;
1415const SHORT_FRAME_HEADER : u8 = 0x10 ;
1516const FRAME_TAIL : u8 = 0x16 ;
1617const ACK_FRAME : u8 = 0xE5 ;
1718
19+ #[ derive( Debug ) ]
20+ pub enum PrimaryControlMessage {
21+ ResetRemoteLink ,
22+ ResetUserProcess ,
23+ SendUserDataConfirmed ,
24+ SendUserDataUnconfirmed ,
25+ RequestAccessDemand ,
26+ RequestLinkStatus ,
27+ RequestUserData1 , // REQ UD1
28+ RequestUserData2 , // REQ UD2
29+ }
30+
31+ #[ derive( Debug ) ]
32+ pub enum SecondaryControlMessage {
33+ ACK ,
34+ NACK ,
35+ UserData ,
36+ UserDataUnavailable ,
37+ Status , // "Status of link or access demand"
38+ LinkNotFunctioning ,
39+ LinkNotImplemented ,
40+ }
41+
42+ #[ derive( Debug ) ]
43+ pub enum DataFlowControl {
44+ Continue , // "further messages are acceptable"
45+ Pause , // "further messages may cause data overflow"
46+ }
47+
48+ #[ derive( Debug ) ]
49+ pub enum Control {
50+ Primary {
51+ frame_count_bit : bool ,
52+ message : PrimaryControlMessage ,
53+ } ,
54+ Secondary {
55+ acess_demand : bool , // The secondary wants you to send it a REQ UD1 ASAP
56+ data_flow_control : DataFlowControl ,
57+ message : SecondaryControlMessage ,
58+ } ,
59+ }
60+
61+ impl Control {
62+ fn parse ( input : & mut & Bytes ) -> MBResult < Self > {
63+ bits:: bits :: < _ , _ , MBusError , _ , _ > ( (
64+ bits:: bool
65+ . context ( StrContext :: Label ( "reserved" ) )
66+ . verify ( |v| !v)
67+ . void ( ) ,
68+ bits:: bool. context ( StrContext :: Label ( "PRM" ) ) ,
69+ bits:: bool. context ( StrContext :: Label ( "FCB/ACD" ) ) ,
70+ bits:: bool. context ( StrContext :: Label ( "FCV/DFC" ) ) ,
71+ bits:: take :: < _ , u8 , _ , _ > ( 4_usize ) . context ( StrContext :: Label ( "function" ) ) ,
72+ ) )
73+ . verify_map ( |( _, prm, fcb_acd, fcv_dfc, function) | {
74+ Some ( if prm {
75+ Self :: Primary {
76+ frame_count_bit : fcb_acd,
77+ message : match ( fcv_dfc, function) {
78+ ( false , 0 ) => PrimaryControlMessage :: ResetRemoteLink ,
79+ ( false , 1 ) => PrimaryControlMessage :: ResetUserProcess ,
80+ ( _, 2 ) => return None , // "Reserved for balanced transmission procedure"
81+ ( true , 3 ) => PrimaryControlMessage :: SendUserDataConfirmed ,
82+ ( false , 4 ) => PrimaryControlMessage :: SendUserDataUnconfirmed ,
83+ ( false , 8 ) => PrimaryControlMessage :: RequestAccessDemand ,
84+ ( false , 9 ) => PrimaryControlMessage :: RequestLinkStatus ,
85+ ( true , 10 ) => PrimaryControlMessage :: RequestUserData1 ,
86+ ( true , 11 ) => PrimaryControlMessage :: RequestUserData2 ,
87+ _ => return None ,
88+ } ,
89+ }
90+ } else {
91+ Self :: Secondary {
92+ acess_demand : fcb_acd,
93+ data_flow_control : if fcv_dfc {
94+ DataFlowControl :: Pause
95+ } else {
96+ DataFlowControl :: Continue
97+ } ,
98+ message : match function {
99+ 0 => SecondaryControlMessage :: ACK ,
100+ 1 => SecondaryControlMessage :: NACK ,
101+ 8 => SecondaryControlMessage :: UserData ,
102+ 9 => SecondaryControlMessage :: UserDataUnavailable ,
103+ 11 => SecondaryControlMessage :: Status ,
104+ 14 => SecondaryControlMessage :: LinkNotFunctioning ,
105+ 15 => SecondaryControlMessage :: LinkNotFunctioning ,
106+ _ => return None ,
107+ } ,
108+ }
109+ } )
110+ } )
111+ . parse_next ( input)
112+ }
113+ }
114+
18115#[ derive( Debug ) ]
19116pub enum Packet < ' a > {
20117 Ack ,
21118 Short {
22- control : u8 ,
119+ control : Control ,
23120 address : u8 ,
24121 } ,
25122 Long {
26- control : u8 ,
123+ control : Control ,
27124 address : u8 ,
28125 data : & ' a [ u8 ] ,
29126 } ,
@@ -42,8 +139,11 @@ fn parse_variable<'a>(input: &mut &'a Bytes) -> MBResult<Packet<'a>> {
42139 . void ( )
43140 . context ( StrContext :: Label ( "frame marker" ) )
44141 . parse_next ( input) ?;
45- let ( control, address) = (
46- binary:: u8. context ( StrContext :: Label ( "control byte" ) ) ,
142+ let ( ( control, raw_control) , address) = (
143+ Control :: parse
144+ . context ( StrContext :: Label ( "control byte" ) )
145+ . with_recognized ( )
146+ . map ( |( control, raw_slice) | ( control, raw_slice[ 0 ] ) ) ,
47147 binary:: u8. context ( StrContext :: Label ( "address byte" ) ) ,
48148 )
49149 . parse_next ( input) ?;
@@ -70,7 +170,7 @@ fn parse_variable<'a>(input: &mut &'a Bytes) -> MBResult<Packet<'a>> {
70170 . copied ( )
71171 . reduce ( u8:: wrapping_add)
72172 . unwrap_or_default ( )
73- . wrapping_add ( control )
173+ . wrapping_add ( raw_control )
74174 . wrapping_add ( address) ;
75175
76176 if sum != checksum {
@@ -92,15 +192,18 @@ fn parse_variable<'a>(input: &mut &'a Bytes) -> MBResult<Packet<'a>> {
92192
93193fn parse_fixed < ' a > ( input : & mut & ' a Bytes ) -> MBResult < Packet < ' a > > {
94194 // mbus's fixed length datagrams are 2 bytes long, only control & address
95- let ( control, address, checksum, _) = (
96- binary:: u8. context ( StrContext :: Label ( "control byte" ) ) ,
195+ let ( ( control, raw_control) , address, checksum, _) = (
196+ Control :: parse
197+ . context ( StrContext :: Label ( "control byte" ) )
198+ . with_recognized ( )
199+ . map ( |( control, raw_slice) | ( control, raw_slice[ 0 ] ) ) ,
97200 binary:: u8. context ( StrContext :: Label ( "address byte" ) ) ,
98201 binary:: u8. context ( StrContext :: Label ( "checksum" ) ) ,
99202 FRAME_TAIL . void ( ) . context ( StrContext :: Label ( "frame tail" ) ) ,
100203 )
101204 . parse_next ( input) ?;
102205
103- let sum = control . wrapping_add ( address) ;
206+ let sum = raw_control . wrapping_add ( address) ;
104207 if sum != checksum {
105208 return Err (
106209 ErrMode :: from_error_kind ( input, ErrorKind :: Verify ) . add_context (
0 commit comments