1use crate::apdu::ApduType;
2use crate::encoding::{
3 primitives::decode_unsigned,
4 reader::Reader,
5 tag::{AppTag, Tag},
6 writer::Writer,
7};
8use crate::{DecodeError, EncodeError};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct ConfirmedRequestHeader {
14 pub segmented: bool,
15 pub more_follows: bool,
16 pub segmented_response_accepted: bool,
17 pub max_segments: u8,
18 pub max_apdu: u8,
19 pub invoke_id: u8,
20 pub sequence_number: Option<u8>,
21 pub proposed_window_size: Option<u8>,
22 pub service_choice: u8,
23}
24
25impl ConfirmedRequestHeader {
26 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
27 let mut b0 = (ApduType::ConfirmedRequest as u8) << 4;
28 if self.segmented {
29 b0 |= 0b0000_1000;
30 }
31 if self.more_follows {
32 b0 |= 0b0000_0100;
33 }
34 if self.segmented_response_accepted {
35 b0 |= 0b0000_0010;
36 }
37
38 w.write_u8(b0)?;
39 w.write_u8((self.max_segments << 4) | (self.max_apdu & 0x0f))?;
40 w.write_u8(self.invoke_id)?;
41 if self.segmented {
42 w.write_u8(self.sequence_number.unwrap_or(0))?;
43 w.write_u8(self.proposed_window_size.unwrap_or(1))?;
44 }
45 w.write_u8(self.service_choice)?;
46 Ok(())
47 }
48
49 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
50 let b0 = r.read_u8()?;
51 if (b0 >> 4) != ApduType::ConfirmedRequest as u8 {
52 return Err(DecodeError::InvalidValue);
53 }
54 let segmented = (b0 & 0b0000_1000) != 0;
55 let more_follows = (b0 & 0b0000_0100) != 0;
56 let segmented_response_accepted = (b0 & 0b0000_0010) != 0;
57 let seg_apdu = r.read_u8()?;
58 let invoke_id = r.read_u8()?;
59 let (sequence_number, proposed_window_size) = if segmented {
60 (Some(r.read_u8()?), Some(r.read_u8()?))
61 } else {
62 (None, None)
63 };
64 let service_choice = r.read_u8()?;
65 Ok(Self {
66 segmented,
67 more_follows,
68 segmented_response_accepted,
69 max_segments: seg_apdu >> 4,
70 max_apdu: seg_apdu & 0x0f,
71 invoke_id,
72 sequence_number,
73 proposed_window_size,
74 service_choice,
75 })
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub struct ComplexAckHeader {
82 pub segmented: bool,
83 pub more_follows: bool,
84 pub invoke_id: u8,
85 pub sequence_number: Option<u8>,
86 pub proposed_window_size: Option<u8>,
87 pub service_choice: u8,
88}
89
90impl ComplexAckHeader {
91 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
92 let mut b0 = (ApduType::ComplexAck as u8) << 4;
93 if self.segmented {
94 b0 |= 0b0000_1000;
95 }
96 if self.more_follows {
97 b0 |= 0b0000_0100;
98 }
99 w.write_u8(b0)?;
100 w.write_u8(self.invoke_id)?;
101 if self.segmented {
102 w.write_u8(self.sequence_number.unwrap_or(0))?;
103 w.write_u8(self.proposed_window_size.unwrap_or(1))?;
104 }
105 w.write_u8(self.service_choice)
106 }
107
108 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
109 let b0 = r.read_u8()?;
110 if (b0 >> 4) != ApduType::ComplexAck as u8 {
111 return Err(DecodeError::InvalidValue);
112 }
113
114 let segmented = (b0 & 0b0000_1000) != 0;
115 let more_follows = (b0 & 0b0000_0100) != 0;
116 let invoke_id = r.read_u8()?;
117 let (sequence_number, proposed_window_size) = if segmented {
118 (Some(r.read_u8()?), Some(r.read_u8()?))
119 } else {
120 (None, None)
121 };
122 let service_choice = r.read_u8()?;
123
124 Ok(Self {
125 segmented,
126 more_follows,
127 invoke_id,
128 sequence_number,
129 proposed_window_size,
130 service_choice,
131 })
132 }
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub struct SimpleAck {
138 pub invoke_id: u8,
139 pub service_choice: u8,
140}
141
142impl SimpleAck {
143 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
144 w.write_u8((ApduType::SimpleAck as u8) << 4)?;
145 w.write_u8(self.invoke_id)?;
146 w.write_u8(self.service_choice)
147 }
148
149 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
150 let b0 = r.read_u8()?;
151 if (b0 >> 4) != ApduType::SimpleAck as u8 {
152 return Err(DecodeError::InvalidValue);
153 }
154 Ok(Self {
155 invoke_id: r.read_u8()?,
156 service_choice: r.read_u8()?,
157 })
158 }
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub struct BacnetError {
164 pub invoke_id: u8,
165 pub service_choice: u8,
166 pub error_class: Option<u32>,
167 pub error_code: Option<u32>,
168}
169
170impl BacnetError {
171 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
172 let b0 = r.read_u8()?;
173 if (b0 >> 4) != ApduType::Error as u8 {
174 return Err(DecodeError::InvalidValue);
175 }
176 let invoke_id = r.read_u8()?;
177 let service_choice = r.read_u8()?;
178 let mut error_class = None;
179 let mut error_code = None;
180 if !r.is_empty() {
181 match Tag::decode(r)? {
182 Tag::Opening { tag_num: 0 } => {
183 let class_tag = Tag::decode(r)?;
184 error_class = Some(decode_bacnet_error_value(r, class_tag, 0)?);
185 let code_tag = Tag::decode(r)?;
186 error_code = Some(decode_bacnet_error_value(r, code_tag, 1)?);
187 match Tag::decode(r)? {
188 Tag::Closing { tag_num: 0 } => {}
189 _ => return Err(DecodeError::InvalidTag),
190 }
191 }
192 first_tag => {
193 error_class = Some(decode_bacnet_error_value(r, first_tag, 0)?);
194 let second_tag = Tag::decode(r)?;
195 error_code = Some(decode_bacnet_error_value(r, second_tag, 1)?);
196 }
197 }
198 }
199 Ok(Self {
200 invoke_id,
201 service_choice,
202 error_class,
203 error_code,
204 })
205 }
206}
207
208fn decode_bacnet_error_value(
209 r: &mut Reader<'_>,
210 tag: Tag,
211 expected_ctx_tag: u8,
212) -> Result<u32, DecodeError> {
213 match tag {
214 Tag::Context { tag_num, len } if tag_num == expected_ctx_tag => {
215 decode_unsigned(r, len as usize)
216 }
217 Tag::Application {
218 tag: AppTag::Enumerated,
219 len,
220 } => decode_unsigned(r, len as usize),
221 _ => Err(DecodeError::InvalidTag),
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq)]
227pub struct RejectPdu {
228 pub invoke_id: u8,
229 pub reason: u8,
230}
231
232impl RejectPdu {
233 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
234 let b0 = r.read_u8()?;
235 if (b0 >> 4) != ApduType::Reject as u8 {
236 return Err(DecodeError::InvalidValue);
237 }
238 Ok(Self {
239 invoke_id: r.read_u8()?,
240 reason: r.read_u8()?,
241 })
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247pub struct AbortPdu {
248 pub server: bool,
249 pub invoke_id: u8,
250 pub reason: u8,
251}
252
253pub mod abort_reason {
255 pub const SEGMENTATION_NOT_SUPPORTED: u8 = 0x04;
257}
258
259impl AbortPdu {
260 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
261 let mut b0 = (ApduType::Abort as u8) << 4;
262 if self.server {
263 b0 |= 0x01;
264 }
265 w.write_u8(b0)?;
266 w.write_u8(self.invoke_id)?;
267 w.write_u8(self.reason)
268 }
269
270 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
271 let b0 = r.read_u8()?;
272 if (b0 >> 4) != ApduType::Abort as u8 {
273 return Err(DecodeError::InvalidValue);
274 }
275 Ok(Self {
276 server: (b0 & 0x01) != 0,
277 invoke_id: r.read_u8()?,
278 reason: r.read_u8()?,
279 })
280 }
281}
282
283#[derive(Debug, Clone, Copy, PartialEq, Eq)]
285pub struct SegmentAck {
286 pub negative_ack: bool,
287 pub sent_by_server: bool,
288 pub invoke_id: u8,
289 pub sequence_number: u8,
290 pub actual_window_size: u8,
291}
292
293impl SegmentAck {
294 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
295 let mut b0 = (ApduType::SegmentAck as u8) << 4;
296 if self.negative_ack {
297 b0 |= 0b0000_0010;
298 }
299 if self.sent_by_server {
300 b0 |= 0b0000_0001;
301 }
302 w.write_u8(b0)?;
303 w.write_u8(self.invoke_id)?;
304 w.write_u8(self.sequence_number)?;
305 w.write_u8(self.actual_window_size)?;
306 Ok(())
307 }
308
309 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
310 let b0 = r.read_u8()?;
311 if (b0 >> 4) != ApduType::SegmentAck as u8 {
312 return Err(DecodeError::InvalidValue);
313 }
314 Ok(Self {
315 negative_ack: (b0 & 0b0000_0010) != 0,
316 sent_by_server: (b0 & 0b0000_0001) != 0,
317 invoke_id: r.read_u8()?,
318 sequence_number: r.read_u8()?,
319 actual_window_size: r.read_u8()?,
320 })
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::BacnetError;
327 use crate::encoding::reader::Reader;
328
329 #[test]
330 fn bacnet_error_decodes_without_details() {
331 let mut r = Reader::new(&[0x50, 1, 15]);
332 let e = BacnetError::decode(&mut r).unwrap();
333 assert_eq!(e.invoke_id, 1);
334 assert_eq!(e.service_choice, 15);
335 assert_eq!(e.error_class, None);
336 assert_eq!(e.error_code, None);
337 }
338
339 #[test]
340 fn bacnet_error_decodes_with_details() {
341 let mut r = Reader::new(&[0x50, 1, 15, 0x09, 0x02, 0x19, 0x20]);
342 let e = BacnetError::decode(&mut r).unwrap();
343 assert_eq!(e.invoke_id, 1);
344 assert_eq!(e.service_choice, 15);
345 assert_eq!(e.error_class, Some(2));
346 assert_eq!(e.error_code, Some(32));
347 }
348
349 #[test]
350 fn bacnet_error_decodes_application_enumerated_details() {
351 let mut r = Reader::new(&[0x50, 1, 15, 0x91, 0x02, 0x91, 0x20]);
352 let e = BacnetError::decode(&mut r).unwrap();
353 assert_eq!(e.invoke_id, 1);
354 assert_eq!(e.service_choice, 15);
355 assert_eq!(e.error_class, Some(2));
356 assert_eq!(e.error_code, Some(32));
357 }
358
359 #[test]
360 fn bacnet_error_decodes_opening_wrapped_application_details() {
361 let mut r = Reader::new(&[0x50, 1, 15, 0x0E, 0x91, 0x02, 0x91, 0x20, 0x0F]);
362 let e = BacnetError::decode(&mut r).unwrap();
363 assert_eq!(e.invoke_id, 1);
364 assert_eq!(e.service_choice, 15);
365 assert_eq!(e.error_class, Some(2));
366 assert_eq!(e.error_code, Some(32));
367 }
368}