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
253impl AbortPdu {
254 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
255 let b0 = r.read_u8()?;
256 if (b0 >> 4) != ApduType::Abort as u8 {
257 return Err(DecodeError::InvalidValue);
258 }
259 Ok(Self {
260 server: (b0 & 0x01) != 0,
261 invoke_id: r.read_u8()?,
262 reason: r.read_u8()?,
263 })
264 }
265}
266
267#[derive(Debug, Clone, Copy, PartialEq, Eq)]
269pub struct SegmentAck {
270 pub negative_ack: bool,
271 pub sent_by_server: bool,
272 pub invoke_id: u8,
273 pub sequence_number: u8,
274 pub actual_window_size: u8,
275}
276
277impl SegmentAck {
278 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
279 let mut b0 = (ApduType::SegmentAck as u8) << 4;
280 if self.negative_ack {
281 b0 |= 0b0000_0010;
282 }
283 if self.sent_by_server {
284 b0 |= 0b0000_0001;
285 }
286 w.write_u8(b0)?;
287 w.write_u8(self.invoke_id)?;
288 w.write_u8(self.sequence_number)?;
289 w.write_u8(self.actual_window_size)?;
290 Ok(())
291 }
292
293 pub fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
294 let b0 = r.read_u8()?;
295 if (b0 >> 4) != ApduType::SegmentAck as u8 {
296 return Err(DecodeError::InvalidValue);
297 }
298 Ok(Self {
299 negative_ack: (b0 & 0b0000_0010) != 0,
300 sent_by_server: (b0 & 0b0000_0001) != 0,
301 invoke_id: r.read_u8()?,
302 sequence_number: r.read_u8()?,
303 actual_window_size: r.read_u8()?,
304 })
305 }
306}
307
308#[cfg(test)]
309mod tests {
310 use super::BacnetError;
311 use crate::encoding::reader::Reader;
312
313 #[test]
314 fn bacnet_error_decodes_without_details() {
315 let mut r = Reader::new(&[0x50, 1, 15]);
316 let e = BacnetError::decode(&mut r).unwrap();
317 assert_eq!(e.invoke_id, 1);
318 assert_eq!(e.service_choice, 15);
319 assert_eq!(e.error_class, None);
320 assert_eq!(e.error_code, None);
321 }
322
323 #[test]
324 fn bacnet_error_decodes_with_details() {
325 let mut r = Reader::new(&[0x50, 1, 15, 0x09, 0x02, 0x19, 0x20]);
326 let e = BacnetError::decode(&mut r).unwrap();
327 assert_eq!(e.invoke_id, 1);
328 assert_eq!(e.service_choice, 15);
329 assert_eq!(e.error_class, Some(2));
330 assert_eq!(e.error_code, Some(32));
331 }
332
333 #[test]
334 fn bacnet_error_decodes_application_enumerated_details() {
335 let mut r = Reader::new(&[0x50, 1, 15, 0x91, 0x02, 0x91, 0x20]);
336 let e = BacnetError::decode(&mut r).unwrap();
337 assert_eq!(e.invoke_id, 1);
338 assert_eq!(e.service_choice, 15);
339 assert_eq!(e.error_class, Some(2));
340 assert_eq!(e.error_code, Some(32));
341 }
342
343 #[test]
344 fn bacnet_error_decodes_opening_wrapped_application_details() {
345 let mut r = Reader::new(&[0x50, 1, 15, 0x0E, 0x91, 0x02, 0x91, 0x20, 0x0F]);
346 let e = BacnetError::decode(&mut r).unwrap();
347 assert_eq!(e.invoke_id, 1);
348 assert_eq!(e.service_choice, 15);
349 assert_eq!(e.error_class, Some(2));
350 assert_eq!(e.error_code, Some(32));
351 }
352}