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, pub max_adpu: MaxAdpu, pub invoke_id: u8, pub sequence_num: u8, pub proposed_window_size: u8, 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 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 #[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 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 AtomicReadFile = 6,
126 AtomicWriteFile = 7,
127
128 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 DeviceCommunicationControl = 17,
143 PrivateTransfer = 18,
144 TextMessage = 19,
145 ReinitializeDevice = 20,
146
147 VtOpen = 21,
149 VtClose = 22,
150 VtData = 23,
151
152 Authenticate = 24,
154 RequestKey = 25,
155
156 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 }
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 }
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}