Skip to content

Commit 2b81fe4

Browse files
committed
Properly parse the control byte
For completeness if nothing else, but having this written out will be useful for writing the encoding part later
1 parent d98a6b9 commit 2b81fe4

File tree

2 files changed

+115
-9
lines changed

2 files changed

+115
-9
lines changed

src/bin/test_parse.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ fn do_file(fname: &str) -> Result<(), Box<dyn error::Error>> {
1414
let packet: Packet = Packet::parse
1515
.parse(Bytes::new(&data[..]))
1616
.map_err(|e| e.into_inner().to_string())?;
17+
18+
println!("{packet:?}");
19+
1720
match packet {
1821
Packet::Long { data, .. } => {
1922
let mut data = Bytes::new(data);

src/parse/link_layer.rs

Lines changed: 112 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,125 @@
22
// Licensed under the EUPL-1.2
33

44
use winnow::binary;
5+
use winnow::binary::bits;
56
use winnow::combinator::{alt, cut_err, preceded};
67
use winnow::error::{AddContext, ErrMode, ErrorKind, ParserError, StrContext};
78
use winnow::prelude::*;
89
use winnow::stream::Stream;
910
use winnow::Bytes;
1011

11-
use super::error::MBResult;
12+
use super::error::{MBResult, MBusError};
1213

1314
const LONG_FRAME_HEADER: u8 = 0x68;
1415
const SHORT_FRAME_HEADER: u8 = 0x10;
1516
const FRAME_TAIL: u8 = 0x16;
1617
const 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)]
19116
pub 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

93193
fn 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

Comments
 (0)