embedded_bacnet/application_protocol/services/
read_property_multiple.rs

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#[derive(Debug, Clone)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub struct ReadPropertyMultipleAck<'a> {
28    pub objects_with_results: &'a [ObjectWithResults<'a>],
29    buf: &'a [u8],
30}
31
32impl<'a> IntoIterator for &'_ ReadPropertyMultipleAck<'a> {
33    type Item = Result<ObjectWithResults<'a>, Error>;
34
35    type IntoIter = ObjectWithResultsIter<'a>;
36
37    fn into_iter(self) -> Self::IntoIter {
38        ObjectWithResultsIter {
39            buf: self.buf,
40            reader: Reader::new_with_len(self.buf.len()),
41        }
42    }
43}
44
45impl<'a> TryFrom<DataLink<'a>> for ReadPropertyMultipleAck<'a> {
46    type Error = Error;
47
48    fn try_from(value: DataLink<'a>) -> Result<Self, Self::Error> {
49        let ack: ComplexAck = value.try_into()?;
50        match ack.service {
51            ComplexAckService::ReadPropertyMultiple(ack) => Ok(ack),
52            _ => Err(Error::ConvertDataLink(
53                "apdu message is not a ComplexAckService ReadPropertyMultipleAck",
54            )),
55        }
56    }
57}
58
59#[derive(Debug, Clone)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61pub struct ObjectWithResults<'a> {
62    pub object_id: ObjectId,
63    pub property_results: PropertyResultList<'a>,
64}
65
66impl<'a> ObjectWithResults<'a> {
67    pub fn encode(&self, writer: &mut Writer) {
68        encode_context_object_id(writer, 0, &self.object_id);
69        encode_opening_tag(writer, 1);
70        self.property_results.encode(writer);
71        encode_closing_tag(writer, 1);
72    }
73
74    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
75        let object_id =
76            decode_context_object_id(reader, buf, 0, "ObjectWithResults decode object_id")?;
77        let buf =
78            get_tagged_body_for_tag(reader, buf, 1, "ObjectWithResults decode list of results")?;
79
80        let property_results = PropertyResultList {
81            object_id,
82            buf,
83            property_results: &[],
84        };
85
86        Ok(ObjectWithResults {
87            object_id,
88            property_results,
89        })
90    }
91}
92
93impl<'a> IntoIterator for &'_ PropertyResultList<'a> {
94    type Item = Result<PropertyResult<'a>, Error>;
95    type IntoIter = PropertyResultIter<'a>;
96
97    fn into_iter(self) -> Self::IntoIter {
98        PropertyResultIter {
99            buf: self.buf,
100            reader: Reader::new_with_len(self.buf.len()),
101            object_id: self.object_id,
102        }
103    }
104}
105
106impl<'a> Iterator for PropertyResultIter<'a> {
107    type Item = Result<PropertyResult<'a>, Error>;
108
109    fn next(&mut self) -> Option<Self::Item> {
110        if self.reader.eof() {
111            return None;
112        }
113
114        Some(PropertyResult::decode(
115            &mut self.reader,
116            self.buf,
117            &self.object_id,
118        ))
119    }
120}
121
122fn read_error(reader: &mut Reader, buf: &[u8]) -> Result<PropertyAccessError, Error> {
123    // error class enumerated
124    let tag = Tag::decode_expected(
125        reader,
126        buf,
127        TagNumber::Application(ApplicationTagNumber::Enumerated),
128        "read_error error_class",
129    )?;
130    let value = decode_unsigned(tag.value, reader, buf)? as u32;
131    let error_class = value
132        .try_into()
133        .map_err(|x| Error::InvalidVariant(("ErrorClass", x)))?;
134
135    // error code enumerated
136    let tag = Tag::decode_expected(
137        reader,
138        buf,
139        TagNumber::Application(ApplicationTagNumber::Enumerated),
140        "read_error error code",
141    )?;
142    let value = decode_unsigned(tag.value, reader, buf)? as u32;
143    let error_code = value
144        .try_into()
145        .map_err(|x| Error::InvalidVariant(("ErrorCode", x)))?;
146
147    Ok(PropertyAccessError {
148        error_class,
149        error_code,
150    })
151}
152
153#[derive(Debug, Clone)]
154#[cfg_attr(feature = "defmt", derive(defmt::Format))]
155pub struct PropertyResultList<'a> {
156    pub property_results: &'a [PropertyResult<'a>],
157    object_id: ObjectId,
158    buf: &'a [u8],
159}
160
161#[derive(Debug, Clone)]
162#[cfg_attr(feature = "defmt", derive(defmt::Format))]
163pub struct PropertyResultIter<'a> {
164    object_id: ObjectId,
165    reader: Reader,
166    buf: &'a [u8],
167}
168
169impl<'a> PropertyResultList<'a> {
170    pub fn new(property_results: &'a [PropertyResult<'a>]) -> Self {
171        Self {
172            property_results,
173            object_id: ObjectId::new(ObjectType::Invalid, 0),
174            buf: &[],
175        }
176    }
177
178    pub fn encode(&self, writer: &mut Writer) {
179        for item in self.property_results {
180            item.encode(writer);
181        }
182    }
183}
184
185#[derive(Debug, Clone)]
186#[cfg_attr(feature = "defmt", derive(defmt::Format))]
187pub struct PropertyResult<'a> {
188    pub id: PropertyId,
189    pub value: PropertyValue<'a>,
190}
191
192impl<'a> PropertyResult<'a> {
193    const PROPERTY_ID_TAG: u8 = 2;
194
195    pub fn encode(&self, writer: &mut Writer) {
196        encode_context_unsigned(writer, Self::PROPERTY_ID_TAG, self.id as u32);
197        self.value.encode(writer);
198    }
199
200    pub fn decode(reader: &mut Reader, buf: &'a [u8], object_id: &ObjectId) -> Result<Self, Error> {
201        let property_id = decode_context_property_id(
202            reader,
203            buf,
204            Self::PROPERTY_ID_TAG,
205            "PropertyResultList next property_id",
206        )?;
207
208        let value = PropertyValue::decode(reader, buf, object_id, &property_id)?;
209
210        Ok(PropertyResult {
211            id: property_id,
212            value,
213        })
214    }
215}
216
217#[derive(Debug, Clone)]
218#[cfg_attr(feature = "defmt", derive(defmt::Format))]
219pub enum PropertyValue<'a> {
220    PropValue(ApplicationDataValue<'a>),
221    PropError(PropertyAccessError),
222    // TODO: figure out if we need these
223    PropDescription(&'a str),
224    PropObjectName(&'a str),
225}
226
227impl<'a> PropertyValue<'a> {
228    const PROPERTY_VALUE_TAG: u8 = 4;
229    const PROPERTY_ERROR_TAG: u8 = 5;
230
231    pub fn encode(&self, writer: &mut Writer) {
232        match self {
233            Self::PropValue(val) => {
234                encode_opening_tag(writer, Self::PROPERTY_VALUE_TAG);
235                val.encode(writer);
236                encode_closing_tag(writer, Self::PROPERTY_VALUE_TAG);
237            }
238            Self::PropError(_) => todo!(),
239            Self::PropObjectName(_) => todo!(),
240            Self::PropDescription(_) => todo!(),
241        }
242    }
243
244    pub fn decode(
245        reader: &mut Reader,
246        buf: &'a [u8],
247        object_id: &ObjectId,
248        property_id: &PropertyId,
249    ) -> Result<Self, Error> {
250        let (buf, tag_number) = get_tagged_body(reader, buf)?;
251        let mut reader = Reader {
252            index: 0,
253            end: buf.len(),
254        };
255
256        let property_value = match tag_number {
257            Self::PROPERTY_VALUE_TAG => {
258                match &property_id {
259                    PropertyId::PropEventTimeStamps => {
260                        // ignore for now
261                        PropertyValue::PropValue(ApplicationDataValue::Boolean(false))
262                    }
263                    PropertyId::PropWeeklySchedule => {
264                        let weekly_schedule = WeeklySchedule::decode(&mut reader, buf)?;
265                        PropertyValue::PropValue(ApplicationDataValue::WeeklySchedule(
266                            weekly_schedule,
267                        ))
268                    }
269                    property_id => {
270                        let tag = Tag::decode(&mut reader, buf)?;
271                        let value = ApplicationDataValue::decode(
272                            &tag,
273                            object_id,
274                            property_id,
275                            &mut reader,
276                            buf,
277                        )?;
278                        PropertyValue::PropValue(value)
279                    }
280                }
281            }
282            Self::PROPERTY_ERROR_TAG => {
283                // property read error
284                let error = read_error(&mut reader, buf)?;
285                PropertyValue::PropError(error)
286            }
287            x => {
288                return Err(Error::TagNotSupported((
289                    "PropertyResultList next",
290                    TagNumber::ContextSpecificOpening(x),
291                )));
292            }
293        };
294
295        Ok(property_value)
296    }
297}
298
299#[derive(Debug, Clone)]
300#[cfg_attr(feature = "defmt", derive(defmt::Format))]
301pub struct PropertyAccessError {
302    pub error_class: ErrorClass,
303    pub error_code: ErrorCode,
304}
305
306impl<'a> Display for PropertyValue<'a> {
307    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
308        match &self {
309            Self::PropValue(x) => write!(f, "{}", x),
310            _ => write!(f, "property value unprintable",),
311        }
312    }
313}
314
315impl<'a> ReadPropertyMultipleAck<'a> {
316    pub fn new(objects_with_results: &'a [ObjectWithResults<'a>]) -> Self {
317        Self {
318            objects_with_results,
319            buf: &[],
320        }
321    }
322
323    pub fn new_from_buf(buf: &'a [u8]) -> Self {
324        Self {
325            buf,
326            objects_with_results: &[],
327        }
328    }
329
330    pub fn encode(&self, writer: &mut Writer) {
331        writer.push(ConfirmedServiceChoice::ReadPropMultiple as u8);
332        for item in self.objects_with_results {
333            item.encode(writer);
334        }
335    }
336}
337
338pub struct ObjectWithResultsIter<'a> {
339    buf: &'a [u8],
340    reader: Reader,
341}
342
343impl<'a> Iterator for ObjectWithResultsIter<'a> {
344    type Item = Result<ObjectWithResults<'a>, Error>;
345
346    fn next(&mut self) -> Option<Self::Item> {
347        if self.reader.eof() {
348            return None;
349        }
350
351        let object_with_results = ObjectWithResults::decode(&mut self.reader, self.buf);
352        Some(object_with_results)
353    }
354}
355
356#[derive(Debug, Clone)]
357#[cfg_attr(feature = "defmt", derive(defmt::Format))]
358pub struct ReadPropertyMultiple<'a> {
359    _array_index: u32, // use BACNET_ARRAY_ALL for all
360    objects: &'a [ReadPropertyMultipleObject<'a>],
361    buf: &'a [u8],
362}
363
364#[derive(Debug, Clone)]
365#[cfg_attr(feature = "defmt", derive(defmt::Format))]
366pub struct PropertyIdList<'a> {
367    pub property_ids: &'a [PropertyId],
368    buf: &'a [u8],
369}
370
371impl<'a> IntoIterator for &'_ PropertyIdList<'a> {
372    type Item = Result<PropertyId, Error>;
373
374    type IntoIter = PropertyIdIter<'a>;
375
376    fn into_iter(self) -> Self::IntoIter {
377        PropertyIdIter {
378            buf: self.buf,
379            reader: Reader::new_with_len(self.buf.len()),
380        }
381    }
382}
383
384pub struct PropertyIdIter<'a> {
385    reader: Reader,
386    buf: &'a [u8],
387}
388
389impl<'a> Iterator for PropertyIdIter<'a> {
390    type Item = Result<PropertyId, Error>;
391
392    fn next(&mut self) -> Option<Self::Item> {
393        if self.reader.eof() {
394            None
395        } else {
396            match decode_context_property_id(
397                &mut self.reader,
398                self.buf,
399                0,
400                "PropertyIdList next property_id",
401            ) {
402                Ok(property_id) => Some(Ok(property_id)),
403                Err(e) => Some(Err(e)),
404            }
405        }
406    }
407}
408
409impl<'a> PropertyIdList<'a> {
410    pub fn new(property_ids: &'a [PropertyId]) -> Self {
411        Self {
412            property_ids,
413            buf: &[],
414        }
415    }
416
417    pub fn encode(&self, writer: &mut Writer) {
418        encode_opening_tag(writer, 1);
419
420        for property_id in self.property_ids {
421            // property_id
422            encode_context_enumerated(writer, 0, property_id);
423
424            // array_index
425            //if self.array_index != BACNET_ARRAY_ALL {
426            //    encode_context_unsigned(writer, 1, self.array_index);
427            //}
428        }
429
430        encode_closing_tag(writer, 1);
431    }
432}
433
434#[derive(Debug, Clone)]
435#[cfg_attr(feature = "defmt", derive(defmt::Format))]
436pub struct ReadPropertyMultipleObject<'a> {
437    pub object_id: ObjectId, // e.g ObjectDevice:20088
438    pub property_ids: PropertyIdList<'a>,
439}
440
441impl<'a> ReadPropertyMultipleObject<'a> {
442    pub fn new(object_id: ObjectId, property_ids: &'a [PropertyId]) -> Self {
443        let property_ids = PropertyIdList::new(property_ids);
444        Self {
445            object_id,
446            property_ids,
447        }
448    }
449
450    pub fn encode(&self, writer: &mut Writer) {
451        // object_id
452        encode_context_object_id(writer, 0, &self.object_id);
453
454        encode_opening_tag(writer, 1);
455
456        for property_id in self.property_ids.property_ids {
457            // property_id
458            encode_context_enumerated(writer, 0, property_id);
459
460            // array_index
461            //if self.array_index != BACNET_ARRAY_ALL {
462            //    encode_context_unsigned(writer, 1, self.array_index);
463            //}
464        }
465
466        encode_closing_tag(writer, 1);
467    }
468
469    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
470        let object_id =
471            decode_context_object_id(reader, buf, 0, "ReadPropertyMultiple next object_id")?;
472
473        let buf =
474            get_tagged_body_for_tag(reader, buf, 1, "ReadPropertyMultiple next list of results")?;
475        let property_ids = PropertyIdList {
476            property_ids: &[],
477            buf,
478        };
479
480        Ok(ReadPropertyMultipleObject {
481            object_id,
482            property_ids,
483        })
484    }
485}
486
487impl<'a> ReadPropertyMultiple<'a> {
488    pub fn new(objects: &'a [ReadPropertyMultipleObject]) -> Self {
489        Self {
490            objects,
491            _array_index: BACNET_ARRAY_ALL,
492            buf: &[],
493        }
494    }
495
496    pub fn new_from_buf(buf: &'a [u8]) -> Self {
497        Self {
498            objects: &[],
499            _array_index: BACNET_ARRAY_ALL,
500            buf,
501        }
502    }
503
504    pub fn encode(&self, writer: &mut Writer) {
505        for object in self.objects {
506            object.encode(writer)
507        }
508    }
509
510    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Self {
511        let buf = &buf[reader.index..reader.end];
512        Self {
513            buf,
514            _array_index: BACNET_ARRAY_ALL,
515            objects: &[],
516        }
517    }
518}
519
520impl<'a> IntoIterator for &'_ ReadPropertyMultiple<'a> {
521    type Item = Result<ReadPropertyMultipleObject<'a>, Error>;
522
523    type IntoIter = ReadPropertyMultipleIter<'a>;
524
525    fn into_iter(self) -> Self::IntoIter {
526        ReadPropertyMultipleIter {
527            buf: self.buf,
528            reader: Reader::new_with_len(self.buf.len()),
529        }
530    }
531}
532
533pub struct ReadPropertyMultipleIter<'a> {
534    buf: &'a [u8],
535    reader: Reader,
536}
537
538impl<'a> Iterator for ReadPropertyMultipleIter<'a> {
539    type Item = Result<ReadPropertyMultipleObject<'a>, Error>;
540
541    fn next(&mut self) -> Option<Self::Item> {
542        if self.reader.eof() {
543            return None;
544        }
545
546        let object_with_property_ids =
547            ReadPropertyMultipleObject::decode(&mut self.reader, self.buf);
548        Some(object_with_property_ids)
549    }
550}