1use core::fmt::Display;
2
3use crate::{
4 application_protocol::{
5 confirmed::{ComplexAck, ComplexAckService, ConfirmedServiceChoice},
6 primitives::data_value::ApplicationDataValue,
7 },
8 common::{
9 daily_schedule::WeeklySchedule,
10 error::Error,
11 helper::{
12 decode_context_object_id, decode_context_property_id, decode_unsigned,
13 encode_closing_tag, encode_context_enumerated, encode_context_object_id,
14 encode_context_unsigned, encode_opening_tag, get_tagged_body, get_tagged_body_for_tag,
15 },
16 io::{Reader, Writer},
17 object_id::{ObjectId, ObjectType},
18 property_id::PropertyId,
19 spec::{ErrorClass, ErrorCode, BACNET_ARRAY_ALL},
20 tag::{ApplicationTagNumber, Tag, TagNumber},
21 },
22 network_protocol::data_link::DataLink,
23};
24
25#[cfg(feature = "alloc")]
26use {
27 crate::common::spooky::Phantom,
28 alloc::{string::String, vec::Vec},
29};
30
31#[cfg(not(feature = "alloc"))]
32#[derive(Debug, Clone)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub struct ReadPropertyMultipleAck<'a> {
35 pub objects_with_results: &'a [ObjectWithResults<'a>],
36 buf: &'a [u8],
37}
38
39#[cfg(feature = "alloc")]
40#[derive(Debug, Clone)]
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub struct ReadPropertyMultipleAck<'a> {
43 pub objects_with_results: Vec<ObjectWithResults<'a>>,
44}
45
46#[cfg(not(feature = "alloc"))]
47impl<'a> IntoIterator for &'_ ReadPropertyMultipleAck<'a> {
48 type Item = Result<ObjectWithResults<'a>, Error>;
49
50 type IntoIter = ObjectWithResultsIter<'a>;
51
52 fn into_iter(self) -> Self::IntoIter {
53 ObjectWithResultsIter {
54 buf: self.buf,
55 reader: Reader::new_with_len(self.buf.len()),
56 }
57 }
58}
59
60impl<'a> TryFrom<DataLink<'a>> for ReadPropertyMultipleAck<'a> {
61 type Error = Error;
62
63 fn try_from(value: DataLink<'a>) -> Result<Self, Self::Error> {
64 let ack: ComplexAck = value.try_into()?;
65 match ack.service {
66 ComplexAckService::ReadPropertyMultiple(ack) => Ok(ack),
67 _ => Err(Error::ConvertDataLink(
68 "apdu message is not a ComplexAckService ReadPropertyMultipleAck",
69 )),
70 }
71 }
72}
73
74#[cfg(not(feature = "alloc"))]
75#[derive(Debug, Clone)]
76#[cfg_attr(feature = "defmt", derive(defmt::Format))]
77pub struct ObjectWithResults<'a> {
78 pub object_id: ObjectId,
79 pub property_results: PropertyResultList<'a>,
80}
81
82#[cfg(feature = "alloc")]
83#[derive(Debug, Clone)]
84#[cfg_attr(feature = "defmt", derive(defmt::Format))]
85pub struct ObjectWithResults<'a> {
86 pub object_id: ObjectId,
87 pub property_results: Vec<PropertyResult<'a>>,
88}
89
90impl<'a> ObjectWithResults<'a> {
91 #[cfg(feature = "alloc")]
92 pub fn new(object_id: ObjectId, property_results: Vec<PropertyResult<'a>>) -> Self {
93 Self {
94 object_id,
95 property_results,
96 }
97 }
98
99 #[cfg(not(feature = "alloc"))]
100 pub fn encode(&self, writer: &mut Writer) {
101 encode_context_object_id(writer, 0, &self.object_id);
102 encode_opening_tag(writer, 1);
103 self.property_results.encode(writer);
104 encode_closing_tag(writer, 1);
105 }
106
107 #[cfg(feature = "alloc")]
108 pub fn encode(&self, writer: &mut Writer) {
109 encode_context_object_id(writer, 0, &self.object_id);
110 encode_opening_tag(writer, 1);
111 for item in self.property_results.iter() {
112 item.encode(writer);
113 }
114 encode_closing_tag(writer, 1);
115 }
116
117 #[cfg(not(feature = "alloc"))]
118 pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
119 let object_id =
120 decode_context_object_id(reader, buf, 0, "ObjectWithResults decode object_id")?;
121 let buf =
122 get_tagged_body_for_tag(reader, buf, 1, "ObjectWithResults decode list of results")?;
123
124 let property_results = PropertyResultList {
125 object_id,
126 buf,
127 property_results: &[],
128 };
129
130 Ok(ObjectWithResults {
131 object_id,
132 property_results,
133 })
134 }
135
136 #[cfg(feature = "alloc")]
137 pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
138 let object_id =
139 decode_context_object_id(reader, buf, 0, "ObjectWithResults decode object_id")?;
140 let inner_buf =
141 get_tagged_body_for_tag(reader, buf, 1, "ObjectWithResults decode list of results")?;
142 let mut inner_reader = Reader::new_with_len(inner_buf.len());
143
144 let mut property_results = Vec::new();
145 while !inner_reader.eof() {
146 let property_result = PropertyResult::decode(&mut inner_reader, inner_buf, &object_id)?;
147 property_results.push(property_result);
148 }
149
150 Ok(Self::new(object_id, property_results))
151 }
152}
153
154impl<'a> IntoIterator for &'_ PropertyResultList<'a> {
155 type Item = Result<PropertyResult<'a>, Error>;
156 type IntoIter = PropertyResultIter<'a>;
157
158 fn into_iter(self) -> Self::IntoIter {
159 PropertyResultIter {
160 buf: self.buf,
161 reader: Reader::new_with_len(self.buf.len()),
162 object_id: self.object_id,
163 }
164 }
165}
166
167impl<'a> Iterator for PropertyResultIter<'a> {
168 type Item = Result<PropertyResult<'a>, Error>;
169
170 fn next(&mut self) -> Option<Self::Item> {
171 if self.reader.eof() {
172 return None;
173 }
174
175 Some(PropertyResult::decode(
176 &mut self.reader,
177 self.buf,
178 &self.object_id,
179 ))
180 }
181}
182
183fn read_error(reader: &mut Reader, buf: &[u8]) -> Result<PropertyAccessError, Error> {
184 let tag = Tag::decode_expected(
186 reader,
187 buf,
188 TagNumber::Application(ApplicationTagNumber::Enumerated),
189 "read_error error_class",
190 )?;
191 let value = decode_unsigned(tag.value, reader, buf)? as u32;
192 let error_class = value
193 .try_into()
194 .map_err(|x| Error::InvalidVariant(("ErrorClass", x)))?;
195
196 let tag = Tag::decode_expected(
198 reader,
199 buf,
200 TagNumber::Application(ApplicationTagNumber::Enumerated),
201 "read_error error code",
202 )?;
203 let value = decode_unsigned(tag.value, reader, buf)? as u32;
204 let error_code = value
205 .try_into()
206 .map_err(|x| Error::InvalidVariant(("ErrorCode", x)))?;
207
208 Ok(PropertyAccessError {
209 error_class,
210 error_code,
211 })
212}
213
214#[derive(Debug, Clone)]
215#[cfg_attr(feature = "defmt", derive(defmt::Format))]
216pub struct PropertyResultList<'a> {
217 pub property_results: &'a [PropertyResult<'a>],
218 object_id: ObjectId,
219 buf: &'a [u8],
220}
221
222#[derive(Debug, Clone)]
223#[cfg_attr(feature = "defmt", derive(defmt::Format))]
224pub struct PropertyResultIter<'a> {
225 object_id: ObjectId,
226 reader: Reader,
227 buf: &'a [u8],
228}
229
230impl<'a> PropertyResultList<'a> {
231 pub fn new(property_results: &'a [PropertyResult<'a>]) -> Self {
232 Self {
233 property_results,
234 object_id: ObjectId::new(ObjectType::Invalid, 0),
235 buf: &[],
236 }
237 }
238
239 pub fn encode(&self, writer: &mut Writer) {
240 for item in self.property_results {
241 item.encode(writer);
242 }
243 }
244}
245
246#[derive(Debug, Clone)]
247#[cfg_attr(feature = "defmt", derive(defmt::Format))]
248pub struct PropertyResult<'a> {
249 pub id: PropertyId,
250 pub value: PropertyValue<'a>,
251}
252
253impl<'a> PropertyResult<'a> {
254 const PROPERTY_ID_TAG: u8 = 2;
255 const PROPERTY_VALUE_TAG: u8 = 4;
256 const PROPERTY_VALUE_ERROR_TAG: u8 = 5;
257
258 pub fn encode(&self, writer: &mut Writer) {
259 encode_context_unsigned(writer, Self::PROPERTY_ID_TAG, self.id as u32);
260 match &self.value {
261 PropertyValue::PropValue(val) => {
262 encode_opening_tag(writer, Self::PROPERTY_VALUE_TAG);
263 val.encode(writer);
264 encode_closing_tag(writer, Self::PROPERTY_VALUE_TAG);
265 }
266 PropertyValue::PropError(_) => todo!(),
267 PropertyValue::PropObjectName(_) => todo!(),
268 PropertyValue::PropDescription(_) => todo!(),
269 }
270 }
271
272 #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
273 pub fn decode(reader: &mut Reader, buf: &'a [u8], object_id: &ObjectId) -> Result<Self, Error> {
274 let property_id = decode_context_property_id(
275 reader,
276 buf,
277 Self::PROPERTY_ID_TAG,
278 "PropertyResultList next property_id",
279 )?;
280
281 let (inner_buf, tag_number) = get_tagged_body(reader, buf)?;
282 let mut inner_reader = Reader {
283 index: 0,
284 end: inner_buf.len(),
285 };
286
287 let property_value = Self::decode_property_value(
288 &mut inner_reader,
289 inner_buf,
290 tag_number,
291 &property_id,
292 object_id,
293 )?;
294
295 Ok(PropertyResult {
296 id: property_id,
297 value: property_value,
298 })
299 }
300
301 #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
302 fn decode_property_value(
303 reader: &mut Reader,
304 buf: &'a [u8],
305 tag_number: u8,
306 property_id: &PropertyId,
307 object_id: &ObjectId,
308 ) -> Result<PropertyValue<'a>, Error> {
309 if tag_number == Self::PROPERTY_VALUE_TAG {
310 match property_id {
311 PropertyId::PropEventTimeStamps => {
312 Ok(PropertyValue::PropValue(ApplicationDataValue::Boolean(
314 false,
315 )))
316 }
317 PropertyId::PropWeeklySchedule => {
318 let weekly_schedule = WeeklySchedule::decode(reader, buf)?;
319 Ok(PropertyValue::PropValue(
320 ApplicationDataValue::WeeklySchedule(weekly_schedule),
321 ))
322 }
323 property_id => {
324 let tag = Tag::decode(reader, buf)?;
325 let value =
326 ApplicationDataValue::decode(&tag, object_id, property_id, reader, buf)?;
327 Ok(PropertyValue::PropValue(value))
328 }
329 }
330 } else if tag_number == Self::PROPERTY_VALUE_ERROR_TAG {
331 let error = read_error(reader, buf)?;
333 Ok(PropertyValue::PropError(error))
334 } else {
335 Err(Error::TagNotSupported((
336 "PropertyResultList next",
337 TagNumber::ContextSpecificOpening(tag_number),
338 )))
339 }
340 }
341}
342
343#[cfg(not(feature = "alloc"))]
344#[derive(Debug, Clone)]
345#[cfg_attr(feature = "defmt", derive(defmt::Format))]
346pub enum PropertyValue<'a> {
347 PropValue(ApplicationDataValue<'a>),
348 PropError(PropertyAccessError),
349 PropDescription(&'a str),
351 PropObjectName(&'a str),
352}
353
354#[cfg(feature = "alloc")]
355#[derive(Debug, Clone)]
356#[cfg_attr(feature = "defmt", derive(defmt::Format))]
357pub enum PropertyValue<'a> {
358 PropValue(ApplicationDataValue<'a>),
359 PropError(PropertyAccessError),
360 PropDescription(String),
362 PropObjectName(String),
363}
364
365#[derive(Debug, Clone)]
366#[cfg_attr(feature = "defmt", derive(defmt::Format))]
367pub struct PropertyAccessError {
368 pub error_class: ErrorClass,
369 pub error_code: ErrorCode,
370}
371
372impl<'a> Display for PropertyValue<'a> {
373 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
374 match &self {
375 Self::PropValue(x) => write!(f, "{}", x),
376 _ => write!(f, "property value unprintable",),
377 }
378 }
379}
380
381impl<'a> ReadPropertyMultipleAck<'a> {
382 #[cfg(not(feature = "alloc"))]
383 pub fn new(objects_with_results: &'a [ObjectWithResults<'a>]) -> Self {
384 Self {
385 objects_with_results,
386 buf: &[],
387 }
388 }
389
390 #[cfg(not(feature = "alloc"))]
391 pub fn new_from_buf(buf: &'a [u8]) -> Self {
392 Self {
393 buf,
394 objects_with_results: &[],
395 }
396 }
397
398 #[cfg(feature = "alloc")]
399 pub fn new(objects_with_results: Vec<ObjectWithResults<'a>>) -> Self {
400 Self {
401 objects_with_results,
402 }
403 }
404
405 pub fn encode(&self, writer: &mut Writer) {
406 writer.push(ConfirmedServiceChoice::ReadPropMultiple as u8);
407 for item in self.objects_with_results.iter() {
408 item.encode(writer);
409 }
410 }
411
412 #[cfg(feature = "alloc")]
413 pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
414 let mut objects_with_results = Vec::new();
415
416 while !reader.eof() {
417 let object_with_results = ObjectWithResults::decode(reader, buf)?;
418 objects_with_results.push(object_with_results);
419 }
420
421 Ok(Self::new(objects_with_results))
422 }
423
424 #[cfg(not(feature = "alloc"))]
425 pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
426 let buf = &buf[reader.index..reader.end];
427 Ok(Self {
428 buf,
429 objects_with_results: &[],
430 })
431 }
432}
433
434pub struct ObjectWithResultsIter<'a> {
435 buf: &'a [u8],
436 reader: Reader,
437}
438
439impl<'a> Iterator for ObjectWithResultsIter<'a> {
440 type Item = Result<ObjectWithResults<'a>, Error>;
441
442 fn next(&mut self) -> Option<Self::Item> {
443 if self.reader.eof() {
444 return None;
445 }
446
447 let object_with_results = ObjectWithResults::decode(&mut self.reader, self.buf);
448 Some(object_with_results)
449 }
450}
451
452#[cfg(not(feature = "alloc"))]
453#[derive(Debug, Clone)]
454#[cfg_attr(feature = "defmt", derive(defmt::Format))]
455pub struct ReadPropertyMultiple<'a> {
456 _array_index: u32, objects: &'a [ReadPropertyMultipleObject<'a>],
458 buf: &'a [u8],
459}
460
461#[cfg(feature = "alloc")]
462#[derive(Debug, Clone)]
463#[cfg_attr(feature = "defmt", derive(defmt::Format))]
464pub struct ReadPropertyMultiple<'a> {
465 _array_index: u32, pub objects: Vec<ReadPropertyMultipleObject<'a>>,
467}
468
469#[derive(Debug, Clone)]
470#[cfg_attr(feature = "defmt", derive(defmt::Format))]
471pub struct PropertyIdList<'a> {
472 pub property_ids: &'a [PropertyId],
473 buf: &'a [u8],
474}
475
476impl<'a> IntoIterator for &'_ PropertyIdList<'a> {
477 type Item = Result<PropertyId, Error>;
478 type IntoIter = PropertyIdIter<'a>;
479
480 fn into_iter(self) -> Self::IntoIter {
481 PropertyIdIter {
482 buf: self.buf,
483 reader: Reader::new_with_len(self.buf.len()),
484 }
485 }
486}
487
488pub struct PropertyIdIter<'a> {
489 reader: Reader,
490 buf: &'a [u8],
491}
492
493impl<'a> Iterator for PropertyIdIter<'a> {
494 type Item = Result<PropertyId, Error>;
495
496 fn next(&mut self) -> Option<Self::Item> {
497 if self.reader.eof() {
498 None
499 } else {
500 match decode_context_property_id(
501 &mut self.reader,
502 self.buf,
503 0,
504 "PropertyIdList next property_id",
505 ) {
506 Ok(property_id) => Some(Ok(property_id)),
507 Err(e) => Some(Err(e)),
508 }
509 }
510 }
511}
512
513impl<'a> PropertyIdList<'a> {
514 pub fn new(property_ids: &'a [PropertyId]) -> Self {
515 Self {
516 property_ids,
517 buf: &[],
518 }
519 }
520
521 pub fn encode(&self, writer: &mut Writer) {
522 encode_opening_tag(writer, 1);
523
524 for property_id in self.property_ids {
525 encode_context_enumerated(writer, 0, property_id);
527
528 }
533
534 encode_closing_tag(writer, 1);
535 }
536}
537
538#[cfg(not(feature = "alloc"))]
539#[derive(Debug, Clone)]
540#[cfg_attr(feature = "defmt", derive(defmt::Format))]
541pub struct ReadPropertyMultipleObject<'a> {
542 pub object_id: ObjectId, pub property_ids: PropertyIdList<'a>,
544}
545
546#[cfg(feature = "alloc")]
547#[derive(Debug, Clone)]
548#[cfg_attr(feature = "defmt", derive(defmt::Format))]
549pub struct ReadPropertyMultipleObject<'a> {
550 pub object_id: ObjectId, pub property_ids: Vec<PropertyId>,
552 pub _phantom: &'a Phantom,
553}
554
555impl<'a> ReadPropertyMultipleObject<'a> {
556 #[cfg(not(feature = "alloc"))]
557 pub fn new(object_id: ObjectId, property_ids: &'a [PropertyId]) -> Self {
558 let property_ids = PropertyIdList::new(property_ids);
559 Self {
560 object_id,
561 property_ids,
562 }
563 }
564
565 #[cfg(feature = "alloc")]
566 pub fn new(object_id: ObjectId, property_ids: Vec<PropertyId>) -> Self {
567 use crate::common::spooky::PHANTOM;
568
569 Self {
570 object_id,
571 property_ids,
572 _phantom: &PHANTOM,
573 }
574 }
575
576 #[cfg(feature = "alloc")]
577 pub fn encode(&self, writer: &mut Writer) {
578 encode_context_object_id(writer, 0, &self.object_id);
580
581 encode_opening_tag(writer, 1);
582
583 for property_id in self.property_ids.iter() {
584 encode_context_enumerated(writer, 0, property_id);
586
587 }
592
593 encode_closing_tag(writer, 1);
594 }
595
596 #[cfg(not(feature = "alloc"))]
597 pub fn encode(&self, writer: &mut Writer) {
598 encode_context_object_id(writer, 0, &self.object_id);
600
601 encode_opening_tag(writer, 1);
602
603 for property_id in self.property_ids.property_ids {
604 encode_context_enumerated(writer, 0, property_id);
606
607 }
612
613 encode_closing_tag(writer, 1);
614 }
615
616 #[cfg(not(feature = "alloc"))]
617 pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
618 let object_id =
619 decode_context_object_id(reader, buf, 0, "ReadPropertyMultiple next object_id")?;
620
621 let buf =
622 get_tagged_body_for_tag(reader, buf, 1, "ReadPropertyMultiple next list of results")?;
623 let property_ids = PropertyIdList {
624 property_ids: &[],
625 buf,
626 };
627
628 Ok(ReadPropertyMultipleObject {
629 object_id,
630 property_ids,
631 })
632 }
633
634 #[cfg(feature = "alloc")]
635 pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
636 let object_id =
637 decode_context_object_id(reader, buf, 0, "ReadPropertyMultiple next object_id")?;
638
639 let body_buf =
640 get_tagged_body_for_tag(reader, buf, 1, "ReadPropertyMultiple next list of results")?;
641 let mut property_ids = Vec::new();
642 let mut inner_reader = Reader::new_with_len(body_buf.len());
643
644 while !inner_reader.eof() {
645 let property_id = decode_context_property_id(
646 &mut inner_reader,
647 body_buf,
648 0,
649 "ReadPropertyMultipleObject decode property_id",
650 )?;
651 property_ids.push(property_id);
652 }
653
654 Ok(ReadPropertyMultipleObject::new(object_id, property_ids))
655 }
656}
657
658impl<'a> ReadPropertyMultiple<'a> {
659 #[cfg(not(feature = "alloc"))]
660 pub fn new(objects: &'a [ReadPropertyMultipleObject]) -> Self {
661 Self {
662 objects,
663 _array_index: BACNET_ARRAY_ALL,
664 buf: &[],
665 }
666 }
667
668 #[cfg(not(feature = "alloc"))]
669 pub fn new_from_buf(buf: &'a [u8]) -> Self {
670 Self {
671 objects: &[],
672 _array_index: BACNET_ARRAY_ALL,
673 buf,
674 }
675 }
676
677 #[cfg(feature = "alloc")]
678 pub fn new(objects: Vec<ReadPropertyMultipleObject<'a>>) -> Self {
679 Self {
680 objects,
681 _array_index: BACNET_ARRAY_ALL,
682 }
683 }
684
685 pub fn encode(&self, writer: &mut Writer) {
686 for object in self.objects.iter() {
687 object.encode(writer)
688 }
689 }
690
691 #[cfg(not(feature = "alloc"))]
692 pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
693 let buf = &buf[reader.index..reader.end];
694 Ok(Self {
695 buf,
696 _array_index: BACNET_ARRAY_ALL,
697 objects: &[],
698 })
699 }
700
701 #[cfg(feature = "alloc")]
702 pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
703 let inner_buf = &buf[reader.index..reader.end];
704 let mut inner_reader = Reader::new_with_len(inner_buf.len());
705 let mut objects = Vec::new();
706
707 while !inner_reader.eof() {
708 let object_with_property_ids =
709 ReadPropertyMultipleObject::decode(&mut inner_reader, inner_buf)?;
710 objects.push(object_with_property_ids);
711 }
712
713 Ok(Self::new(objects))
714 }
715}
716
717#[cfg(not(feature = "alloc"))]
718impl<'a> IntoIterator for &'_ ReadPropertyMultiple<'a> {
719 type Item = Result<ReadPropertyMultipleObject<'a>, Error>;
720
721 type IntoIter = ReadPropertyMultipleIter<'a>;
722
723 fn into_iter(self) -> Self::IntoIter {
724 ReadPropertyMultipleIter {
725 buf: self.buf,
726 reader: Reader::new_with_len(self.buf.len()),
727 }
728 }
729}
730
731pub struct ReadPropertyMultipleIter<'a> {
732 buf: &'a [u8],
733 reader: Reader,
734}
735
736impl<'a> Iterator for ReadPropertyMultipleIter<'a> {
737 type Item = Result<ReadPropertyMultipleObject<'a>, Error>;
738
739 fn next(&mut self) -> Option<Self::Item> {
740 if self.reader.eof() {
741 return None;
742 }
743
744 let object_with_property_ids =
745 ReadPropertyMultipleObject::decode(&mut self.reader, self.buf);
746 Some(object_with_property_ids)
747 }
748}