wireless_mbus_link_layer/
lib.rs1use m_bus_core::{DeviceType, Function, IdentificationNumber, ManufacturerCode};
2
3fn crc16_en13757(data: &[u8]) -> u16 {
6 let mut crc: u16 = 0x0000;
7 for &byte in data {
8 crc ^= (byte as u16) << 8;
9 for _ in 0..8 {
10 if crc & 0x8000 != 0 {
11 crc = (crc << 1) ^ 0x3D65;
12 } else {
13 crc <<= 1;
14 }
15 }
16 }
17 crc ^ 0xFFFF
18}
19
20pub fn strip_format_a_crcs<'a>(data: &[u8], output: &'a mut [u8]) -> Option<&'a [u8]> {
30 if data.len() < 12 || output.len() < data.len() {
31 return None;
32 }
33
34 if crc16_en13757(&data[0..10]) != u16::from_be_bytes([data[10], data[11]]) {
36 return None;
37 }
38
39 let mut out_pos = 10;
40 output[..10].copy_from_slice(&data[..10]);
41
42 let mut pos = 12;
43 while pos < data.len() {
44 let remaining = data.len() - pos;
45 if remaining < 3 {
46 output[out_pos..out_pos + remaining].copy_from_slice(&data[pos..pos + remaining]);
47 out_pos += remaining;
48 break;
49 }
50
51 let max_data_len = 16.min(remaining - 2);
52 let mut found = false;
53
54 for data_len in (1..=max_data_len).rev() {
55 let crc_start = pos + data_len;
56 if crc_start + 2 > data.len() {
57 continue;
58 }
59 if crc16_en13757(&data[pos..crc_start])
60 == u16::from_be_bytes([data[crc_start], data[crc_start + 1]])
61 {
62 output[out_pos..out_pos + data_len].copy_from_slice(&data[pos..crc_start]);
63 out_pos += data_len;
64 pos = crc_start + 2;
65 found = true;
66 break;
67 }
68 }
69
70 if !found {
71 let remaining = data.len() - pos;
72 output[out_pos..out_pos + remaining].copy_from_slice(&data[pos..]);
73 out_pos += remaining;
74 break;
75 }
76 }
77
78 output[0] = (out_pos - 1) as u8;
79 Some(&output[..out_pos])
80}
81
82#[derive(Debug, Clone, Copy, PartialEq)]
83#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
84pub struct WirelessFrame<'a> {
85 pub function: Function,
86 pub manufacturer_id: ManufacturerId,
87 pub data: &'a [u8],
88}
89
90#[derive(Debug, Clone, Copy, PartialEq)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
92pub struct ManufacturerId {
93 pub manufacturer_code: ManufacturerCode,
94 pub identification_number: IdentificationNumber,
95 pub device_type: DeviceType,
96 pub version: u8,
97 pub is_unique_globally: bool,
98}
99
100impl TryFrom<&[u8]> for ManufacturerId {
101 type Error = FrameError;
102 fn try_from(data: &[u8]) -> Result<Self, FrameError> {
103 let mut iter = data.iter();
104 Ok(ManufacturerId {
105 manufacturer_code: ManufacturerCode::from_id(u16::from_le_bytes([
106 *iter.next().ok_or(FrameError::TooShort)?,
107 *iter.next().ok_or(FrameError::TooShort)?,
108 ]))
109 .map_err(|_| FrameError::TooShort)?,
110 identification_number: IdentificationNumber::from_bcd_hex_digits([
111 *iter.next().ok_or(FrameError::TooShort)?,
112 *iter.next().ok_or(FrameError::TooShort)?,
113 *iter.next().ok_or(FrameError::TooShort)?,
114 *iter.next().ok_or(FrameError::TooShort)?,
115 ])
116 .map_err(|_| FrameError::TooShort)?,
117 version: *iter.next().ok_or(FrameError::TooShort)?,
118 device_type: {
123 let device_byte = *iter.next().ok_or(FrameError::TooShort)?;
124 let ci_byte = *data.get(8).ok_or(FrameError::TooShort)?;
126 let device_type_code = if (0xA0..=0xAF).contains(&ci_byte) {
127 (device_byte >> 4) & 0x0F
129 } else {
130 device_byte
132 };
133 DeviceType::from(device_type_code)
134 },
135 is_unique_globally: false, })
137 }
138}
139
140#[derive(Debug, Copy, Clone, PartialEq)]
141#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
142pub enum FrameError {
143 EmptyData,
144 TooShort,
145 WrongLength { expected: usize, actual: usize },
146}
147
148impl<'a> TryFrom<&'a [u8]> for WirelessFrame<'a> {
149 type Error = FrameError;
150
151 fn try_from(data: &'a [u8]) -> Result<Self, FrameError> {
152 let length = data.len();
153 let length_byte = *data.first().ok_or(FrameError::EmptyData)? as usize;
154 let _c_field = *data.get(1).ok_or(FrameError::TooShort)? as usize;
155 let manufacturer_id = ManufacturerId::try_from(&data[2..])?;
156
157 if length_byte + 1 == length {
159 return Ok(WirelessFrame {
160 function: Function::SndNk { prm: false },
161 manufacturer_id,
162 data: &data[10..],
163 });
164 }
165
166 Err(FrameError::WrongLength {
167 expected: length_byte + 1,
168 actual: data.len(),
169 })
170 }
171}
172
173#[cfg(test)]
174mod test {
175 use super::*;
176
177 #[test]
178 fn test_dummy() {
179 let _id = 33225544;
180 let _medium = 7; let _man = "SEN";
182 let _version = 104;
183 let frame: &[u8] = &[
184 0x18, 0x44, 0xAE, 0x4C, 0x44, 0x55, 0x22, 0x33, 0x68, 0x07, 0x7A, 0x55, 0x00, 0x00,
185 0x00, 0x00, 0x04, 0x13, 0x89, 0xE2, 0x01, 0x00, 0x02, 0x3B, 0x00, 0x00,
186 ];
187 let parsed = WirelessFrame::try_from(frame);
188 println!("{:#?}", parsed);
189 }
190}