1use super::{addresses::KnxAddress, tpdu::TPDU};
2use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
3use log::{debug, warn};
4use snafu::{whatever, Whatever};
5use std::io::{Cursor, Read};
6use tracing::instrument;
7
8#[derive(Debug)]
9pub struct LDataCon {
10 pub cemi: CEMI,
11 pub l_data: LData,
12 pub confirm: bool,
13}
14
15impl LDataCon {
16 pub fn from_cemi(cemi: CEMI) -> Result<Self, Whatever> {
17 let mut reader = Cursor::new(cemi.service_info.as_slice());
18 let control1 = match reader.read_u8() {
19 Ok(control1) => control1,
20 Err(e) => whatever!("Unable to read control 1 byte {:?}", e),
21 };
22 let _control2 = match reader.read_u8() {
23 Ok(control2) => control2,
24 Err(e) => whatever!("Unable to read control 2 byte {:?}", e),
25 };
26 let src = match reader.read_u16::<BigEndian>() {
27 Ok(src) => src,
28 Err(e) => whatever!("Unable to read source address {:?}", e),
29 };
30 let dest = match reader.read_u16::<BigEndian>() {
31 Ok(dest) => dest,
32 Err(e) => whatever!("Unable to read destination address {:?}", e),
33 };
34
35 let frame_type = (control1 & 0x80) > 0;
36 let repetition = (control1 & (1 << 5)) > 0;
37 let system_broadcast = (control1 & (1 << 4)) > 0;
38 let ack_request = (control1 & (1 << 1)) > 0;
39 let confirm = (control1 & 1) == 0;
40
41 Ok(Self {
42 cemi,
43 l_data: LData {
44 src,
45 dest,
46 frame_type,
47 repetition,
48 system_broadcast,
49 ack_request,
50 },
51 confirm,
52 })
53 }
54}
55
56#[derive(Debug)]
57pub struct LData {
58 pub src: u16,
59 pub dest: u16,
60 pub frame_type: bool,
61 pub repetition: bool, pub system_broadcast: bool,
63 pub ack_request: bool,
64}
65
66#[derive(Debug)]
69pub struct LDataInd {
70 pub cemi: CEMI,
71 pub l_data: LData,
72 pub value: Vec<u8>,
73}
74
75impl LDataInd {
76 #[instrument]
77 pub fn from_cemi(cemi: CEMI) -> Result<Self, Whatever> {
78 let mut reader = Cursor::new(cemi.service_info.as_slice());
79 let control1 = match reader.read_u8() {
80 Ok(control1) => control1,
81 Err(e) => whatever!("Unable to read control 1 byte {:?}", e),
82 };
83 let _control2 = match reader.read_u8() {
84 Ok(control2) => control2,
85 Err(e) => whatever!("Unable to read control 2 byte {:?}", e),
86 };
87 let src = match reader.read_u16::<BigEndian>() {
88 Ok(src) => src,
89 Err(e) => whatever!("Unable to read source address {:?}", e),
90 };
91 let dest = match reader.read_u16::<BigEndian>() {
92 Ok(dest) => dest,
93 Err(e) => whatever!("Unable to read destination address {:?}", e),
94 };
95 let length = match reader.read_u8() {
96 Ok(len) if len > 0 => len - 1,
97 Ok(_) => 0,
98 Err(e) => whatever!("Unable to read length {:?}", e),
99 };
100 let octects_6_7 = match reader.read_u16::<BigEndian>() {
101 Ok(word) => word,
102 Err(e) => whatever!("Unable to read octets 6 and 7 {:?}", e),
103 };
104
105 let frame_type = (control1 & 0x80) > 0;
106 let repetition = (control1 & (1 << 5)) > 0;
107 let system_broadcast = (control1 & (1 << 4)) > 0;
108 let ack_request = (control1 & (1 << 1)) > 0;
109
110 let apci = (octects_6_7 & 0x03c0) >> 6;
111 debug!("Length {:?}", length);
112 debug!("Octects 6 and 7: {:0x?}", octects_6_7);
113 debug!("Apci: {:0x?}", apci);
114
115 let mut value = vec![0; length as usize];
116 if length > 0 {
117 if let Err(e) = reader.read(&mut value) {
118 whatever!("Unable to read value of length {}, {:?}", length, e);
119 }
120 } else {
121 let data = (octects_6_7 & 0x3f) as u8;
122 value.push(data);
123 }
124 debug!("Value: {:0x?}", value);
125
126 Ok(Self {
127 cemi,
128 l_data: LData {
129 src,
130 dest,
131 frame_type,
132 repetition,
133 system_broadcast,
134 ack_request,
135 },
136 value,
137 })
138 }
139}
140
141#[derive(Debug)]
144pub struct LDataReqMessage {
145 priority: u8,
146 dest_address: KnxAddress,
147 tpdu: TPDU,
148}
149
150impl LDataReqMessage {
151 pub fn new(dest_address: KnxAddress, tpdu: TPDU) -> Self {
152 Self {
153 priority: 0b11,
154 dest_address,
155 tpdu,
156 }
157 }
158
159 pub fn set_priority(&mut self, priority: u8) {
160 self.priority = priority;
161 }
162
163 pub fn packet(&self) -> Vec<u8> {
164 let mut control = 0u8;
165 control |= 1 << 7; control |= 1 << 5; control |= 1 << 4; control |= (self.priority & 0x3) << 2;
169
170 let control2 = 0xe0u8;
171 let mut packet = vec![CEMIMessageCode::LDataReq as u8, 0, control, control2, 0, 0];
172
173 packet.write_u16::<BigEndian>(self.dest_address.to_u16()).unwrap();
175
176 let mut tpdu_packet = self.tpdu.packet();
177 packet.write_u8(tpdu_packet.len() as u8 - 1).unwrap(); packet.append(&mut tpdu_packet);
179
180 packet
181 }
182}
183
184#[derive(Debug)]
187pub struct CEMI {
188 pub msg_code: u8,
189 pub additional_infos: Vec<CEMIAdditionalInfo>,
190 pub service_info: Vec<u8>,
191}
192
193impl CEMI {
194 #[instrument]
195 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
196 let msg_code = match packet_reader.read_u8() {
197 Ok(code) => code,
198 Err(e) => whatever!("Unable to read message code {:?}", e),
199 };
200
201 let additional_infos_size = match packet_reader.read_u8() {
202 Ok(size) => size,
203 Err(e) => whatever!("Unable to read addition infos size {:?}", e),
204 };
205
206 let mut additional_infos = Vec::new();
207 let mut position = 0;
208 while position < additional_infos_size {
209 let additional_info_type: CEMIAdditionalInfoType = match packet_reader.read_u8() {
210 Ok(info_type) => match info_type.try_into() {
211 Ok(t) => t,
212 Err(e) => whatever!("Unknown additional info type {:?}", e),
213 },
214 Err(e) => whatever!("Unable to read addition info type {:?}", e),
215 };
216 let additional_info_size = match packet_reader.read_u8() {
217 Ok(size) => size,
218 Err(e) => whatever!("Unable to read addition info size {:?}", e),
219 };
220
221 let mut additional_info = vec![0; additional_info_size as usize];
222 if let Err(e) = packet_reader.read(&mut additional_info) {
223 whatever!("Unable to read additional info {:?}", e);
224 }
225
226 additional_infos.push(CEMIAdditionalInfo {
227 info_type: additional_info_type,
228 value: additional_info,
229 });
230 position += additional_info_size + 2;
231 }
232
233 let mut service_info = Vec::new();
234 if let Err(e) = packet_reader.read_to_end(&mut service_info) {
235 whatever!("Unable to read service information {:?}", e);
236 }
237
238 Ok(Self {
239 msg_code,
240 additional_infos,
241 service_info,
242 })
243 }
244}
245
246#[derive(Copy, Clone)]
247#[repr(u8)]
248pub enum CEMIMessageCode {
249 LBusmonInd = 0x2b, LDataReq = 0x11, LDataCon = 0x2e, LDataInd = 0x29, LRawReq = 0x10, LRawInd = 0x2d, LRawCon = 0x2f, LPollDataReq = 0x13, LPollDataCon = 0x25, TDataConnectedReq = 0x41,
261 TDataConnectedInd = 0x89,
262 TDataIndividualReq = 0x4a,
263 TDataIndividualInd = 0x94,
264
265 MPropReadReq = 0xFC, MPropReadCon = 0xfb, MPropWriteReq = 0xf6, MPropWriteCon = 0xf5, MPropInfoInd = 0xf7, MFuncPropCommandReq = 0xf8, MFuncPropStateReq = 0xf9, MFuncPropCommandCon = 0xfa, MResetReq = 0xf1, MResetInd = 0xf0, }
276
277#[derive(Debug)]
278pub enum CEMIAdditionalInfoType {
279 PLMediumInfo = 0x01,
280 RFMediumInfo = 0x02,
281 BusmonitorStatusInfo = 0x03,
282 TimestampRelative = 0x04,
283 TimeDelayUnitlSending = 0x05,
284 ExtendedRelativeTime = 0x06,
285 BiBatInfo = 0x07,
286 RFMultiInfo = 0x08,
287 PreambleAndPostamble = 0x09,
288 RFFastAckInfo = 0x0a,
289 ManufacturerSpecificData = 0xfe,
290}
291
292#[derive(Debug)]
293pub struct CEMIAdditionalInfo {
294 pub info_type: CEMIAdditionalInfoType,
295 pub value: Vec<u8>,
296}
297
298impl TryFrom<u8> for CEMIAdditionalInfoType {
299 type Error = ();
300
301 fn try_from(v: u8) -> Result<Self, Self::Error> {
302 match v {
303 x if x == CEMIAdditionalInfoType::PLMediumInfo as u8 => Ok(CEMIAdditionalInfoType::PLMediumInfo),
304 x if x == CEMIAdditionalInfoType::RFMediumInfo as u8 => Ok(CEMIAdditionalInfoType::RFMediumInfo),
305 x if x == CEMIAdditionalInfoType::BusmonitorStatusInfo as u8 => Ok(CEMIAdditionalInfoType::BusmonitorStatusInfo),
306 x if x == CEMIAdditionalInfoType::TimestampRelative as u8 => Ok(CEMIAdditionalInfoType::TimestampRelative),
307 x if x == CEMIAdditionalInfoType::TimeDelayUnitlSending as u8 => Ok(CEMIAdditionalInfoType::TimeDelayUnitlSending),
308 x if x == CEMIAdditionalInfoType::ExtendedRelativeTime as u8 => Ok(CEMIAdditionalInfoType::ExtendedRelativeTime),
309 x if x == CEMIAdditionalInfoType::BiBatInfo as u8 => Ok(CEMIAdditionalInfoType::BiBatInfo),
310 x if x == CEMIAdditionalInfoType::RFMultiInfo as u8 => Ok(CEMIAdditionalInfoType::RFMultiInfo),
311 x if x == CEMIAdditionalInfoType::PreambleAndPostamble as u8 => Ok(CEMIAdditionalInfoType::PreambleAndPostamble),
312 x if x == CEMIAdditionalInfoType::RFFastAckInfo as u8 => Ok(CEMIAdditionalInfoType::RFFastAckInfo),
313 x if x == CEMIAdditionalInfoType::ManufacturerSpecificData as u8 => Ok(CEMIAdditionalInfoType::ManufacturerSpecificData),
314 _ => Err(()),
315 }
316 }
317}
318
319#[cfg(test)]
320pub mod test {
321 use std::io::Cursor;
322
323 use crate::packets::emi::LDataInd;
324
325 use super::CEMI;
326
327 #[test]
328 pub fn bit_update() {
329 env_logger::init();
330 let packet_bytes: [u8; 11] = [0x29, 0x00, 0xbc, 0xe0, 0x11, 0x0b, 0x0a, 0x01, 0x01, 0x00, 0x81];
331 let mut cursor = Cursor::new(&packet_bytes[..]);
332 let cemi = CEMI::from_packet(&mut cursor).expect("It should be able to parse CEMI packet");
333 assert_eq!(0x29, cemi.msg_code, "Message code should be L_Data.ind");
334 assert_eq!(0, cemi.additional_infos.len(), "Additional infos should be empty");
335
336 let ind = LDataInd::from_cemi(cemi).expect("To be able to parse L_Data.ind from cemi");
337 assert_eq!(1, ind.value.len(), "Data value should have length 1");
338 }
339}