embedded_bacnet/application_protocol/
confirmed.rs

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