knx_ip_client/packets/
tunneling.rs

1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use snafu::{ensure_whatever, whatever, Whatever};
3use std::io::{Cursor, Read};
4
5// Tunneling request
6// 03.08.04 Tunneling section 4.4.6
7//
8#[derive(Debug)]
9pub struct TunnelingRequest {
10    pub communication_channel_id: u8,
11    pub sequence_nr: u8,
12    pub cemi: Vec<u8>,
13}
14
15impl TunnelingRequest {
16    pub fn new(communication_channel_id: u8, sequence_nr: u8, cemi: Vec<u8>) -> Self {
17        Self {
18            communication_channel_id,
19            sequence_nr,
20            cemi,
21        }
22    }
23
24    pub fn get_cemi(&self) -> &Vec<u8> {
25        &self.cemi
26    }
27
28    pub fn packet(&self) -> Vec<u8> {
29        let mut packet = vec![0x06, 0x10, 0x04, 0x20];
30        packet.write_u16::<BigEndian>(10 + self.cemi.len() as u16).unwrap();
31        packet.write_u8(4).unwrap();
32        packet.write_u8(self.communication_channel_id).unwrap();
33        packet.write_u8(self.sequence_nr).unwrap();
34        packet.write_u8(0).unwrap();
35        packet.extend(&self.cemi);
36        packet
37    }
38
39    pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
40        verify_header(packet_reader)?;
41
42        match packet_reader.read_u16::<BigEndian>() {
43            Ok(code) => {
44                ensure_whatever!(code == 0x0420, "Code should be 0x0420 instead of {:0x?}", code);
45            }
46            Err(e) => whatever!("Unable to read code {:?}", e),
47        };
48
49        let size = match packet_reader.read_u16::<BigEndian>() {
50            Ok(size) => size,
51            Err(e) => whatever!("Unable to read packet size {:?}", e),
52        };
53
54        match packet_reader.read_u8() {
55            Ok(size) => {
56                ensure_whatever!(size == 0x04, "Size should be 0x04 instead of {}", size);
57            }
58            Err(e) => whatever!("Unable to read message code {:?}", e),
59        };
60
61        let communication_channel_id = match packet_reader.read_u8() {
62            Ok(id) => id,
63            Err(e) => whatever!("Unable to read communication channel id {:?}", e),
64        };
65
66        let sequence_nr = match packet_reader.read_u8() {
67            Ok(sequence_nr) => sequence_nr,
68            Err(e) => whatever!("Unable to read sequence number {:?}", e),
69        };
70
71        match packet_reader.read_u8() {
72            Ok(_) => (),
73            Err(e) => whatever!("Unable to read padding {:?}", e),
74        };
75
76        let mut cemi = vec![0; size as usize - 10];
77        if let Err(e) = packet_reader.read(&mut cemi) {
78            whatever!("Unable to read cemi part {:?}", e);
79        }
80
81        Ok(Self {
82            communication_channel_id,
83            sequence_nr,
84            cemi,
85        })
86    }
87}
88
89// Tunneling Ack
90// 03.08.04 Tunneling section 4.4.7
91//
92#[derive(Debug)]
93pub struct TunnelingAck {
94    pub communication_channel_id: u8,
95    pub sequence_nr: u8,
96    pub status: u8,
97}
98
99impl TunnelingAck {
100    pub fn new(communication_channel_id: u8, sequence_nr: u8, status: u8) -> Self {
101        Self {
102            communication_channel_id,
103            sequence_nr,
104            status,
105        }
106    }
107
108    pub fn packet(&self) -> Vec<u8> {
109        let mut packet = vec![0x06, 0x10, 0x04, 0x21, 0, 0x0a];
110        packet.write_u8(4).unwrap();
111        packet.write_u8(self.communication_channel_id).unwrap();
112        packet.write_u8(self.sequence_nr).unwrap();
113        packet.write_u8(self.status).unwrap();
114        packet
115    }
116
117    pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
118        verify_header(packet_reader)?;
119
120        match packet_reader.read_u16::<BigEndian>() {
121            Ok(code) => ensure_whatever!(code == 0x0421, "Response code should be 0x0421 instead of {:0x?}", code),
122            Err(e) => whatever!("Unable to read response code {:?}", e),
123        }
124
125        match packet_reader.read_u16::<BigEndian>() {
126            Ok(size) => ensure_whatever!(size == 0x0a, "Packet size should be 0x0a instead of {:0x?}", size),
127            Err(e) => whatever!("Unable to read packet size {:?}", e),
128        }
129
130        match packet_reader.read_u8() {
131            Ok(struct_size) => ensure_whatever!(struct_size == 0x04, "Structure size should be 0x04 instead of {:0x?}", struct_size),
132            Err(e) => whatever!("Unable to read struct size {:?}", e),
133        }
134
135        let communication_channel_id = match packet_reader.read_u8() {
136            Ok(id) => id,
137            Err(e) => whatever!("Unable to read communication channel id {:?}", e),
138        };
139
140        let sequence_nr = match packet_reader.read_u8() {
141            Ok(nr) => nr,
142            Err(e) => whatever!("Unable to read communication channel id {:?}", e),
143        };
144
145        let status = match packet_reader.read_u8() {
146            Ok(status) => status,
147            Err(e) => whatever!("Unable to read status {:?}", e),
148        };
149
150        Ok(Self {
151            communication_channel_id,
152            sequence_nr,
153            status,
154        })
155    }
156}
157
158#[derive(Copy, Clone, Debug)]
159#[repr(u8)]
160pub enum KnxIpFeature {
161    MaskVersion = 0x02,
162    IndividualAddress = 0x06,
163    MaxApduLength = 0x07,
164    InfoServiceEnable = 0x08,
165}
166
167#[derive(Debug)]
168pub struct FeatureSet {
169    feature: KnxIpFeature,
170    value: u8,
171    pub communication_channel_id: u8,
172    pub sequence_nr: u8,
173}
174
175impl FeatureSet {
176    pub fn new(communication_channel_id: u8, sequence_nr: u8, feature: KnxIpFeature, value: u8) -> Self {
177        Self {
178            communication_channel_id,
179            sequence_nr,
180            feature,
181            value,
182        }
183    }
184
185    pub fn packet(&self) -> Vec<u8> {
186        let mut packet = vec![0x06, 0x10, 0x04, 0x24, 0, 0x0d];
187        packet.write_u8(4).unwrap();
188        packet.write_u8(self.communication_channel_id).unwrap();
189        packet.write_u8(self.sequence_nr).unwrap();
190        packet.write_u8(0).unwrap();
191        packet.write_u8(self.feature as u8).unwrap();
192        packet.write_u8(0).unwrap();
193        packet.write_u8(self.value).unwrap();
194        packet
195    }
196}
197
198#[derive(Debug)]
199pub struct FeatureResp {
200    pub feature: KnxIpFeature,
201    pub value: u8,
202    pub status: u8,
203    pub communication_channel_id: u8,
204    pub sequence_nr: u8,
205}
206
207impl FeatureResp {
208    pub fn packet(&self) -> Vec<u8> {
209        let mut packet = vec![0x06, 0x10, 0x04, 0x24, 0, 0x0d];
210        packet.write_u8(4).unwrap();
211        packet.write_u8(self.communication_channel_id).unwrap();
212        packet.write_u8(self.sequence_nr).unwrap();
213        packet.write_u8(0).unwrap();
214        packet.write_u8(self.feature as u8).unwrap();
215        packet.write_u8(0).unwrap();
216        packet.write_u8(self.value).unwrap();
217        packet
218    }
219
220    pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
221        verify_header(packet_reader)?;
222
223        match packet_reader.read_u16::<BigEndian>() {
224            Ok(code) => ensure_whatever!(code == 0x0423, "Response code should be 0x0423 instead of {:0x?}", code),
225            Err(e) => whatever!("Unable to read response code {:?}", e),
226        }
227
228        match packet_reader.read_u16::<BigEndian>() {
229            Ok(size) => ensure_whatever!(size == 0x0d, "Packet size should be 0x0d instead of {:0x?}", size),
230            Err(e) => whatever!("Unable to read packet size {:?}", e),
231        }
232
233        match packet_reader.read_u8() {
234            Ok(struct_size) => ensure_whatever!(struct_size == 0x04, "Structure size should be 0x04 instead of {:0x?}", struct_size),
235            Err(e) => whatever!("Unable to read struct size {:?}", e),
236        }
237
238        let communication_channel_id = match packet_reader.read_u8() {
239            Ok(id) => id,
240            Err(e) => whatever!("Unable to read communication channel id {:?}", e),
241        };
242
243        let sequence_nr = match packet_reader.read_u8() {
244            Ok(nr) => nr,
245            Err(e) => whatever!("Unable to read communication channel id {:?}", e),
246        };
247
248        match packet_reader.read_u8() {
249            Ok(_) => (),
250            Err(e) => whatever!("Unable to read reserved field {:?}", e),
251        };
252
253        let feature: KnxIpFeature = match packet_reader.read_u8() {
254            Ok(feature) => feature.try_into()?,
255            Err(e) => whatever!("Unable to read status {:?}", e),
256        };
257
258        let status = match packet_reader.read_u8() {
259            Ok(status) => status,
260            Err(e) => whatever!("Unable to read status {:?}", e),
261        };
262
263        let value = match packet_reader.read_u8() {
264            Ok(value) => value,
265            Err(e) => whatever!("Unable to read value {:?}", e),
266        };
267
268        Ok(Self {
269            communication_channel_id,
270            sequence_nr,
271            status,
272            feature,
273            value,
274        })
275    }
276}
277
278fn verify_header(packet_reader: &mut Cursor<&[u8]>) -> Result<(), Whatever> {
279    match packet_reader.read_u8() {
280        Ok(size) => ensure_whatever!(size == 6, "Header size should be 6 instead of {}", size),
281        Err(_e) => whatever!("Unable to read header size"),
282    };
283
284    match packet_reader.read_u8() {
285        Ok(version) => ensure_whatever!(version == 0x10, "Version should be 0x10 instead of {:0x?}", version),
286        Err(_e) => whatever!("Unable to read header version"),
287    };
288
289    Ok(())
290}
291
292impl TryFrom<u8> for KnxIpFeature {
293    type Error = Whatever;
294
295    fn try_from(v: u8) -> Result<Self, Self::Error> {
296        match v {
297            x if x == KnxIpFeature::MaskVersion as u8 => Ok(KnxIpFeature::MaskVersion),
298            x if x == KnxIpFeature::IndividualAddress as u8 => Ok(KnxIpFeature::IndividualAddress),
299            x if x == KnxIpFeature::MaxApduLength as u8 => Ok(KnxIpFeature::MaxApduLength),
300            x if x == KnxIpFeature::InfoServiceEnable as u8 => Ok(KnxIpFeature::InfoServiceEnable),
301            _ => whatever!("Unknown KNXIP feature {:?}", v),
302        }
303    }
304}