bacnet_emb/application_protocol/
confirmed.rs

1use crate::{
2    application_protocol::{
3        application_pdu::{ApduType, ApplicationPdu, MaxAdpu, MaxSegments, PduFlags},
4        services::{
5            change_of_value::SubscribeCov,
6            read_property::{ReadProperty, ReadPropertyAck},
7            read_property_multiple::{ReadPropertyMultiple, ReadPropertyMultipleAck},
8            read_range::{ReadRange, ReadRangeAck},
9            write_property::WriteProperty,
10        },
11    },
12    common::{
13        error::{Error, Unimplemented},
14        helper::decode_unsigned,
15        io::{Reader, Writer},
16        spec::{ErrorClass, ErrorCode},
17        tag::{ApplicationTagNumber, Tag, TagNumber},
18    },
19    network_protocol::{data_link::DataLink, network_pdu::NetworkMessage},
20};
21
22#[derive(Debug, Clone)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub struct ConfirmedRequest<'a> {
25    pub max_segments: MaxSegments, // default 65
26    pub max_adpu: MaxAdpu,         // default 1476
27    pub invoke_id: u8,             // starts at 0
28    pub sequence_num: u8,          // default to 0
29    pub proposed_window_size: u8,  // default to 0
30    pub service: ConfirmedRequestService<'a>,
31}
32
33impl<'a> ConfirmedRequest<'a> {
34    pub fn new(invoke_id: u8, service: ConfirmedRequestService<'a>) -> Self {
35        Self {
36            max_segments: MaxSegments::_65,
37            max_adpu: MaxAdpu::_1476,
38            invoke_id,
39            sequence_num: 0,
40            proposed_window_size: 0,
41            service,
42        }
43    }
44
45    pub fn encode(&self, writer: &mut Writer) {
46        let max_segments_flag = match self.max_segments {
47            MaxSegments::_0 => 0,
48            _ => PduFlags::SegmentedResponseAccepted as u8,
49        };
50
51        let control = ((ApduType::ConfirmedServiceRequest as u8) << 4) | max_segments_flag;
52        writer.push(control);
53        writer.push(self.max_segments.clone() as u8 | self.max_adpu.clone() as u8);
54        writer.push(self.invoke_id);
55
56        // NOTE: Segment pdu not supported / implemented
57        match &self.service {
58            ConfirmedRequestService::ReadProperty(service) => {
59                writer.push(ConfirmedServiceChoice::ReadProperty as u8);
60                service.encode(writer)
61            }
62            ConfirmedRequestService::ReadPropertyMultiple(service) => {
63                writer.push(ConfirmedServiceChoice::ReadPropMultiple as u8);
64                service.encode(writer)
65            }
66            ConfirmedRequestService::SubscribeCov(service) => {
67                writer.push(ConfirmedServiceChoice::SubscribeCov as u8);
68                service.encode(writer)
69            }
70            ConfirmedRequestService::WriteProperty(service) => {
71                writer.push(ConfirmedServiceChoice::WriteProperty as u8);
72                service.encode(writer)
73            }
74            ConfirmedRequestService::ReadRange(service) => {
75                writer.push(ConfirmedServiceChoice::ReadRange as u8);
76                service.encode(writer)
77            }
78        };
79    }
80
81    // the control byte has already been read
82    #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
83    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
84        let byte0 = reader.read_byte(buf)?;
85        let max_segments: MaxSegments = (byte0 & 0xF0).into();
86        let max_adpu: MaxAdpu = (byte0 & 0x0F).into();
87        let invoke_id = reader.read_byte(buf)?;
88
89        let choice: ConfirmedServiceChoice = reader.read_byte(buf)?.try_into().map_err(|e| {
90            Error::InvalidVariant(("ConfirmedRequest decode ConfirmedServiceChoice", e as u32))
91        })?;
92        let service = ConfirmedRequestService::decode(choice, reader, buf)?;
93
94        Ok(Self {
95            max_segments,
96            max_adpu,
97            sequence_num: 0,
98            proposed_window_size: 0,
99            invoke_id,
100            service,
101        })
102    }
103}
104
105#[derive(Debug, Clone)]
106#[cfg_attr(feature = "defmt", derive(defmt::Format))]
107#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
108#[repr(u8)]
109pub enum ConfirmedServiceChoice {
110    // alarm and event services
111    AcknowledgeAlarm = 0,
112    AuditNotification = 32,
113    CovNotification = 1,
114    CovNotificationMultiple = 31,
115    EventNotification = 2,
116    GetAlarmSummary = 3,
117    GetEnrollmentSummary = 4,
118    GetEventInformation = 29,
119    LifeSafetyOperation = 27,
120    SubscribeCov = 5,
121    SubscribeCovProperty = 28,
122    SubscribeCovPropertyMultiple = 30,
123
124    // file access services
125    AtomicReadFile = 6,
126    AtomicWriteFile = 7,
127
128    // object access services
129    AddListElement = 8,
130    RemoveListElement = 9,
131    CreateObject = 10,
132    DeleteObject = 11,
133    ReadProperty = 12,
134    ReadPropConditional = 13,
135    ReadPropMultiple = 14,
136    ReadRange = 26,
137    WriteProperty = 15,
138    WritePropMultiple = 16,
139    AuditLogQuery = 33,
140
141    // remote device management services
142    DeviceCommunicationControl = 17,
143    PrivateTransfer = 18,
144    TextMessage = 19,
145    ReinitializeDevice = 20,
146
147    // virtual terminal services
148    VtOpen = 21,
149    VtClose = 22,
150    VtData = 23,
151
152    // security services
153    Authenticate = 24,
154    RequestKey = 25,
155
156    // services added after 1995
157    // readRange [26] see Object Access Services
158    // lifeSafetyOperation [27] see Alarm and Event Services
159    // subscribeCOVProperty [28] see Alarm and Event Services
160    // getEventInformation [29] see Alarm and Event Services
161
162    // services added after 2012
163    // subscribe-cov-property-multiple [30] see Alarm and Event Services
164    // confirmed-cov-notification-multiple [31] see Alarm and Event Services
165
166    // services added after 2016
167    // confirmed-audit-notification [32] see Alarm and Event Services
168    // audit-log-query [33] see Object Access Services
169    MaxBacnetConfirmedService = 34,
170}
171
172impl TryFrom<u8> for ConfirmedServiceChoice {
173    type Error = u8;
174
175    fn try_from(value: u8) -> Result<Self, u8> {
176        match value {
177            0 => Ok(Self::AcknowledgeAlarm),
178            1 => Ok(Self::CovNotification),
179            2 => Ok(Self::EventNotification),
180            3 => Ok(Self::GetAlarmSummary),
181            4 => Ok(Self::GetEnrollmentSummary),
182            5 => Ok(Self::SubscribeCov),
183            6 => Ok(Self::AtomicReadFile),
184            7 => Ok(Self::AtomicWriteFile),
185            8 => Ok(Self::AddListElement),
186            9 => Ok(Self::RemoveListElement),
187            10 => Ok(Self::CreateObject),
188            11 => Ok(Self::DeleteObject),
189            12 => Ok(Self::ReadProperty),
190            13 => Ok(Self::ReadPropConditional),
191            14 => Ok(Self::ReadPropMultiple),
192            15 => Ok(Self::WriteProperty),
193            16 => Ok(Self::WritePropMultiple),
194            17 => Ok(Self::DeviceCommunicationControl),
195            18 => Ok(Self::PrivateTransfer),
196            19 => Ok(Self::TextMessage),
197            20 => Ok(Self::ReinitializeDevice),
198            21 => Ok(Self::VtOpen),
199            22 => Ok(Self::VtClose),
200            23 => Ok(Self::VtData),
201            24 => Ok(Self::Authenticate),
202            25 => Ok(Self::RequestKey),
203            26 => Ok(Self::ReadRange),
204            27 => Ok(Self::LifeSafetyOperation),
205            28 => Ok(Self::SubscribeCovProperty),
206            29 => Ok(Self::GetEventInformation),
207            30 => Ok(Self::SubscribeCovPropertyMultiple),
208            31 => Ok(Self::CovNotificationMultiple),
209            32 => Ok(Self::AuditNotification),
210            33 => Ok(Self::AuditLogQuery),
211            34 => Ok(Self::MaxBacnetConfirmedService),
212            x => Err(x),
213        }
214    }
215}
216
217#[derive(Debug, Clone)]
218#[cfg_attr(feature = "defmt", derive(defmt::Format))]
219pub struct SimpleAck {
220    pub invoke_id: u8,
221    pub service_choice: ConfirmedServiceChoice,
222}
223
224impl<'a> TryFrom<DataLink<'a>> for SimpleAck {
225    type Error = Error;
226
227    fn try_from(value: DataLink<'a>) -> Result<Self, Self::Error> {
228        match value.npdu {
229            Some(x) => match x.network_message {
230                NetworkMessage::Apdu(ApplicationPdu::SimpleAck(ack)) => Ok(ack),
231                _ => Err(Error::ConvertDataLink(
232                    "npdu message is not an apdu simple ack",
233                )),
234            },
235            _ => Err(Error::ConvertDataLink("no npdu defined in message")),
236        }
237    }
238}
239
240impl SimpleAck {
241    pub fn encode(&self, writer: &mut Writer) {
242        let control = (ApduType::SimpleAck as u8) << 4;
243        writer.push(control);
244        writer.push(self.invoke_id);
245        writer.push(self.service_choice.clone() as u8);
246    }
247
248    pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
249        let invoke_id = reader.read_byte(buf)?;
250        let service_choice: ConfirmedServiceChoice =
251            reader.read_byte(buf)?.try_into().map_err(|e| {
252                Error::InvalidVariant(("SimpleAck decode ConfirmedServiceChoice", e as u32))
253            })?;
254
255        Ok(Self {
256            invoke_id,
257            service_choice,
258        })
259    }
260}
261
262#[derive(Debug, Clone)]
263#[cfg_attr(feature = "defmt", derive(defmt::Format))]
264pub struct ConfirmedBacnetError {
265    pub invoke_id: u8,
266    pub service_choice: ConfirmedServiceChoice,
267    pub error_class: ErrorClass,
268    pub error_code: ErrorCode,
269}
270
271impl ConfirmedBacnetError {
272    pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
273        let invoke_id = reader.read_byte(buf)?;
274        let service_choice: ConfirmedServiceChoice =
275            reader.read_byte(buf)?.try_into().map_err(|e| {
276                Error::InvalidVariant((
277                    "ConfirmedBacnetError decode ConfirmedServiceChoice",
278                    e as u32,
279                ))
280            })?;
281
282        let tag = Tag::decode_expected(
283            reader,
284            buf,
285            TagNumber::Application(ApplicationTagNumber::Enumerated),
286            "ConfirmedBacnetError error class",
287        )?;
288        let value = decode_unsigned(tag.value, reader, buf)? as u32;
289        let error_class =
290            ErrorClass::try_from(value).map_err(|e| Error::InvalidVariant(("ErrorClass", e)))?;
291
292        let tag = Tag::decode_expected(
293            reader,
294            buf,
295            TagNumber::Application(ApplicationTagNumber::Enumerated),
296            "ConfirmedBacnetError error code",
297        )?;
298        let value = decode_unsigned(tag.value, reader, buf)? as u32;
299        let error_code =
300            ErrorCode::try_from(value).map_err(|e| Error::InvalidVariant(("ErrorCode", e)))?;
301
302        Ok(Self {
303            invoke_id,
304            service_choice,
305            error_class,
306            error_code,
307        })
308    }
309}
310
311#[derive(Debug, Clone)]
312#[cfg_attr(feature = "defmt", derive(defmt::Format))]
313pub struct ComplexAck<'a> {
314    pub invoke_id: u8,
315    pub service: ComplexAckService<'a>,
316}
317
318impl<'a> TryFrom<DataLink<'a>> for ComplexAck<'a> {
319    type Error = Error;
320
321    fn try_from(value: DataLink<'a>) -> Result<Self, Self::Error> {
322        match value.npdu {
323            Some(x) => match x.network_message {
324                NetworkMessage::Apdu(ApplicationPdu::ComplexAck(ack)) => Ok(ack),
325                _ => Err(Error::ConvertDataLink(
326                    "npdu message is not an apdu complex ack",
327                )),
328            },
329            _ => Err(Error::ConvertDataLink("no npdu defined in message")),
330        }
331    }
332}
333
334impl<'a> ComplexAck<'a> {
335    pub fn encode(&self, writer: &mut Writer) {
336        let control = (ApduType::ComplexAck as u8) << 4;
337        writer.push(control);
338        writer.push(self.invoke_id);
339
340        match &self.service {
341            ComplexAckService::ReadProperty(service) => service.encode(writer),
342            ComplexAckService::ReadPropertyMultiple(service) => service.encode(writer),
343            ComplexAckService::ReadRange(service) => service.encode(writer),
344        }
345    }
346
347    #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
348    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
349        let invoke_id = reader.read_byte(buf)?;
350        let choice: ConfirmedServiceChoice = reader.read_byte(buf)?.try_into().map_err(|e| {
351            Error::InvalidVariant(("ComplexAck decode ConfirmedServiceChoice", e as u32))
352        })?;
353        let service = ComplexAckService::decode(choice, reader, buf)?;
354
355        Ok(Self { invoke_id, service })
356    }
357}
358
359#[derive(Debug, Clone)]
360#[cfg_attr(feature = "defmt", derive(defmt::Format))]
361pub enum ComplexAckService<'a> {
362    ReadProperty(ReadPropertyAck<'a>),
363    ReadPropertyMultiple(ReadPropertyMultipleAck<'a>),
364    ReadRange(ReadRangeAck<'a>),
365    // add more here
366}
367
368impl<'a> ComplexAckService<'a> {
369    #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
370    pub fn decode(
371        choice: ConfirmedServiceChoice,
372        reader: &mut Reader,
373        buf: &'a [u8],
374    ) -> Result<Self, Error> {
375        match choice {
376            ConfirmedServiceChoice::ReadProperty => {
377                let service = ReadPropertyAck::decode(reader, buf)?;
378                Ok(ComplexAckService::ReadProperty(service))
379            }
380            ConfirmedServiceChoice::ReadPropMultiple => {
381                let service = ReadPropertyMultipleAck::decode(reader, buf)?;
382                Ok(ComplexAckService::ReadPropertyMultiple(service))
383            }
384            ConfirmedServiceChoice::ReadRange => {
385                let service = ReadRangeAck::decode(reader, buf)?;
386                Ok(ComplexAckService::ReadRange(service))
387            }
388            s => Err(Error::Unimplemented(Unimplemented::ConfirmedServiceChoice(
389                s,
390            ))),
391        }
392    }
393}
394
395#[derive(Debug, Clone)]
396#[cfg_attr(feature = "defmt", derive(defmt::Format))]
397pub enum ConfirmedRequestService<'a> {
398    ReadProperty(ReadProperty),
399    ReadPropertyMultiple(ReadPropertyMultiple<'a>),
400    SubscribeCov(SubscribeCov),
401    WriteProperty(WriteProperty<'a>),
402    ReadRange(ReadRange),
403    // add more here (see ConfirmedServiceChoice enum)
404}
405
406impl<'a> ConfirmedRequestService<'a> {
407    #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
408    pub fn decode(
409        choice: ConfirmedServiceChoice,
410        reader: &mut Reader,
411        buf: &'a [u8],
412    ) -> Result<Self, Error> {
413        match choice {
414            ConfirmedServiceChoice::ReadProperty => {
415                let service = ReadProperty::decode(reader, buf)?;
416                Ok(ConfirmedRequestService::ReadProperty(service))
417            }
418            ConfirmedServiceChoice::ReadPropMultiple => {
419                let service = ReadPropertyMultiple::decode(reader, buf)?;
420                Ok(ConfirmedRequestService::ReadPropertyMultiple(service))
421            }
422            ConfirmedServiceChoice::ReadRange => {
423                let service = ReadRange::decode(reader, buf)?;
424                Ok(ConfirmedRequestService::ReadRange(service))
425            }
426            ConfirmedServiceChoice::WriteProperty => {
427                let service = WriteProperty::decode(reader, buf)?;
428                Ok(ConfirmedRequestService::WriteProperty(service))
429            }
430            s => Err(Error::Unimplemented(Unimplemented::ConfirmedServiceChoice(
431                s,
432            ))),
433        }
434    }
435}
436
437#[derive(Debug, Clone)]
438#[cfg_attr(feature = "defmt", derive(defmt::Format))]
439pub struct SegmentAck {
440    pub invoke_id: u8,
441    pub sequence_num: u8,
442    pub proposed_window_size: u8,
443}
444
445impl<'a> TryFrom<DataLink<'a>> for SegmentAck {
446    type Error = Error;
447
448    fn try_from(value: DataLink<'a>) -> Result<Self, Self::Error> {
449        match value.npdu {
450            Some(x) => match x.network_message {
451                NetworkMessage::Apdu(ApplicationPdu::SegmentAck(ack)) => Ok(ack),
452                _ => Err(Error::ConvertDataLink(
453                    "npdu message is not an apdu simple ack",
454                )),
455            },
456            _ => Err(Error::ConvertDataLink("no npdu defined in message")),
457        }
458    }
459}
460
461impl SegmentAck {
462    pub fn encode(&self, writer: &mut Writer) {
463        let control = (ApduType::SegmentAck as u8) << 4;
464        writer.push(control);
465        writer.push(self.invoke_id);
466        writer.push(self.sequence_num);
467        writer.push(self.proposed_window_size);
468    }
469
470    pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
471        let invoke_id = reader.read_byte(buf)?;
472        let sequence_num = reader.read_byte(buf)?;
473        let proposed_window_size = reader.read_byte(buf)?;
474
475        Ok(Self {
476            invoke_id,
477            sequence_num,
478            proposed_window_size,
479        })
480    }
481}