1#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4#[derive(Debug, PartialEq)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub enum Frame<'a> {
7 SingleCharacter {
8 character: u8,
9 },
10 ShortFrame {
11 function: Function,
12 address: Address,
13 },
14 LongFrame {
15 function: Function,
16 address: Address,
17 #[cfg_attr(feature = "serde", serde(skip_serializing))]
18 data: &'a [u8],
19 },
20 ControlFrame {
21 function: Function,
22 address: Address,
23 #[cfg_attr(feature = "serde", serde(skip_serializing))]
24 data: &'a [u8],
25 },
26}
27
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29#[derive(Debug, Clone, PartialEq)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub enum Function {
32 SndNk,
33 SndUd { fcb: bool },
34 ReqUd2 { fcb: bool },
35 ReqUd1 { fcb: bool },
36 RspUd { acd: bool, dfc: bool },
37}
38
39#[cfg(feature = "std")]
40impl std::fmt::Display for Function {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 match self {
43 Function::SndNk => write!(f, "SndNk"),
44 Function::SndUd { fcb } => write!(f, "SndUd (FCB: {})", fcb),
45 Function::ReqUd2 { fcb } => write!(f, "ReqUd2 (FCB: {})", fcb),
46 Function::ReqUd1 { fcb } => write!(f, "ReqUd1 (FCB: {})", fcb),
47 Function::RspUd { acd, dfc } => write!(f, "RspUd (ACD: {}, DFC: {})", acd, dfc),
48 }
49 }
50}
51
52impl TryFrom<u8> for Function {
53 type Error = FrameError;
54
55 fn try_from(byte: u8) -> Result<Self, Self::Error> {
56 match byte {
57 0x40 => Ok(Self::SndNk),
58 0x53 => Ok(Self::SndUd { fcb: false }),
59 0x73 => Ok(Self::SndUd { fcb: true }),
60 0x5B => Ok(Self::ReqUd2 { fcb: false }),
61 0x7B => Ok(Self::ReqUd2 { fcb: true }),
62 0x5A => Ok(Self::ReqUd1 { fcb: false }),
63 0x7A => Ok(Self::ReqUd1 { fcb: true }),
64 0x08 => Ok(Self::RspUd {
65 acd: false,
66 dfc: false,
67 }),
68 0x18 => Ok(Self::RspUd {
69 acd: false,
70 dfc: true,
71 }),
72 0x28 => Ok(Self::RspUd {
73 acd: true,
74 dfc: false,
75 }),
76 0x38 => Ok(Self::RspUd {
77 acd: true,
78 dfc: true,
79 }),
80 _ => Err(FrameError::InvalidFunction { byte }),
81 }
82 }
83}
84#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
85#[derive(Debug, Clone, PartialEq)]
86#[cfg_attr(feature = "defmt", derive(defmt::Format))]
87pub enum Address {
88 Uninitalized,
89 Primary(u8),
90 Secondary,
91 Broadcast { reply_required: bool },
92}
93
94#[cfg(feature = "std")]
95impl std::fmt::Display for Address {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 match self {
98 Address::Uninitalized => write!(f, "Uninitalized"),
99 Address::Primary(byte) => write!(f, "Primary ({})", byte),
100 Address::Secondary => write!(f, "Secondary"),
101 Address::Broadcast { reply_required } => {
102 write!(f, "Broadcast (Reply Required: {})", reply_required)
103 }
104 }
105 }
106}
107
108impl Address {
109 const fn from(byte: u8) -> Self {
110 match byte {
111 0 => Self::Uninitalized,
112 253 => Self::Secondary,
113 254 => Self::Broadcast {
114 reply_required: true,
115 },
116 255 => Self::Broadcast {
117 reply_required: false,
118 },
119 _ => Self::Primary(byte),
120 }
121 }
122}
123
124#[derive(Debug, PartialEq, Eq)]
125#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126#[cfg_attr(feature = "defmt", derive(defmt::Format))]
127pub enum FrameError {
128 EmptyData,
129 InvalidStartByte,
130 InvalidStopByte,
131 WrongLengthIndication,
132 LengthShort,
133 LengthShorterThanSix { length: usize },
134 WrongChecksum { expected: u8, actual: u8 },
135 InvalidControlInformation { byte: u8 },
136 InvalidFunction { byte: u8 },
137}
138
139impl<'a> TryFrom<&'a [u8]> for Frame<'a> {
140 type Error = FrameError;
141
142 fn try_from(data: &'a [u8]) -> Result<Self, FrameError> {
143 let first_byte = *data.first().ok_or(FrameError::EmptyData)?;
144
145 if first_byte == 0xE5 {
146 return Ok(Frame::SingleCharacter { character: 0xE5 });
147 }
148
149 let second_byte = *data.get(1).ok_or(FrameError::LengthShort)?;
150 let third_byte = *data.get(2).ok_or(FrameError::LengthShort)?;
151
152 match first_byte {
153 0x68 => {
154 validate_checksum(data.get(4..).ok_or(FrameError::LengthShort)?)?;
155
156 let length = *data.get(1).ok_or(FrameError::LengthShort)? as usize;
157
158 if second_byte != third_byte || data.len() != length + 6 {
159 return Err(FrameError::WrongLengthIndication);
160 }
161
162 if *data.last().ok_or(FrameError::LengthShort)? != 0x16 {
163 return Err(FrameError::InvalidStopByte);
164 }
165 let control_field = *data.get(4).ok_or(FrameError::LengthShort)?;
166 let address_field = *data.get(5).ok_or(FrameError::LengthShort)?;
167 match control_field {
168 0x53 => Ok(Frame::ControlFrame {
169 function: Function::try_from(control_field)?,
170 address: Address::from(address_field),
171 data: data.get(6..data.len() - 2).ok_or(FrameError::LengthShort)?,
172 }),
173 _ => Ok(Frame::LongFrame {
174 function: Function::try_from(control_field)?,
175 address: Address::from(address_field),
176 data: data.get(6..data.len() - 2).ok_or(FrameError::LengthShort)?,
177 }),
178 }
179 }
180 0x10 => {
181 validate_checksum(data.get(1..).ok_or(FrameError::LengthShort)?)?;
182 if data.len() == 5 && *data.last().ok_or(FrameError::InvalidStopByte)? == 0x16 {
183 Ok(Frame::ShortFrame {
184 function: Function::try_from(second_byte)?,
185 address: Address::from(third_byte),
186 })
187 } else {
188 Err(FrameError::LengthShort)
189 }
190 }
191 _ => Err(FrameError::InvalidStartByte),
192 }
193 }
194}
195
196fn validate_checksum(data: &[u8]) -> Result<(), FrameError> {
197 let checksum_byte_index = data.len() - 2;
199 let checksum_byte = *data
200 .get(checksum_byte_index)
201 .ok_or(FrameError::LengthShort)?;
202
203 let calculated_checksum = data
204 .get(..checksum_byte_index)
205 .ok_or(FrameError::LengthShort)?
206 .iter()
207 .fold(0, |acc: u8, &x| acc.wrapping_add(x));
208
209 if checksum_byte == calculated_checksum {
210 Ok(())
211 } else {
212 Err(FrameError::WrongChecksum {
213 expected: checksum_byte,
214 actual: calculated_checksum,
215 })
216 }
217}
218
219#[cfg(feature = "std")]
220impl std::error::Error for FrameError {}
221
222#[cfg(feature = "std")]
223impl std::fmt::Display for FrameError {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 match self {
226 FrameError::EmptyData => write!(f, "Data is empty"),
227 FrameError::InvalidStartByte => write!(f, "Invalid start byte"),
228 FrameError::InvalidStopByte => write!(f, "Invalid stop byte"),
229 FrameError::LengthShort => write!(f, "Length mismatch"),
230 FrameError::LengthShorterThanSix { length } => {
231 write!(f, "Length is shorter than six: {}", length)
232 }
233 FrameError::WrongChecksum { expected, actual } => write!(
234 f,
235 "Wrong checksum, expected: {}, actual: {}",
236 expected, actual
237 ),
238 FrameError::InvalidControlInformation { byte } => {
239 write!(f, "Invalid control information: {}", byte)
240 }
241 FrameError::InvalidFunction { byte } => write!(f, "Invalid function: {}", byte),
242 FrameError::WrongLengthIndication => write!(f, "Wrong length indication"),
243 }
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn test_detect_frame_type() {
253 let single_character_frame: &[u8] = &[0xE5];
254 let short_frame: &[u8] = &[0x10, 0x7B, 0x8b, 0x06, 0x16];
255 let control_frame: &[u8] = &[0x68, 0x03, 0x03, 0x68, 0x53, 0x01, 0x51, 0xA5, 0x16];
256
257 let example: &[u8] = &[
258 0x68, 0x4D, 0x4D, 0x68, 0x08, 0x01, 0x72, 0x01, 0x00, 0x00, 0x00, 0x96, 0x15, 0x01,
259 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x78, 0x56, 0x00, 0x00, 0x00, 0x01, 0xFD, 0x1B,
260 0x00, 0x02, 0xFC, 0x03, 0x48, 0x52, 0x25, 0x74, 0x44, 0x0D, 0x22, 0xFC, 0x03, 0x48,
261 0x52, 0x25, 0x74, 0xF1, 0x0C, 0x12, 0xFC, 0x03, 0x48, 0x52, 0x25, 0x74, 0x63, 0x11,
262 0x02, 0x65, 0xB4, 0x09, 0x22, 0x65, 0x86, 0x09, 0x12, 0x65, 0xB7, 0x09, 0x01, 0x72,
263 0x00, 0x72, 0x65, 0x00, 0x00, 0xB2, 0x01, 0x65, 0x00, 0x00, 0x1F, 0xB3, 0x16,
264 ];
265
266 assert_eq!(
267 Frame::try_from(single_character_frame),
268 Ok(Frame::SingleCharacter { character: 0xE5 })
269 );
270 assert_eq!(
271 Frame::try_from(short_frame),
272 Ok(Frame::ShortFrame {
273 function: Function::try_from(0x7B).unwrap(),
274 address: Address::from(0x8B)
275 })
276 );
277 assert_eq!(
278 Frame::try_from(control_frame),
279 Ok(Frame::ControlFrame {
280 function: Function::try_from(0x53).unwrap(),
281 address: Address::from(0x01),
282 data: &[0x51]
283 })
284 );
285
286 assert_eq!(
287 Frame::try_from(example),
288 Ok(Frame::LongFrame {
289 function: Function::try_from(8).unwrap(),
290 address: Address::from(1),
291 data: &[
292 114, 1, 0, 0, 0, 150, 21, 1, 0, 24, 0, 0, 0, 12, 120, 86, 0, 0, 0, 1, 253, 27,
293 0, 2, 252, 3, 72, 82, 37, 116, 68, 13, 34, 252, 3, 72, 82, 37, 116, 241, 12,
294 18, 252, 3, 72, 82, 37, 116, 99, 17, 2, 101, 180, 9, 34, 101, 134, 9, 18, 101,
295 183, 9, 1, 114, 0, 114, 101, 0, 0, 178, 1, 101, 0, 0, 31
296 ]
297 })
298 );
299 }
300}