embedded_bacnet/application_protocol/services/
read_property.rs

1use crate::{
2    application_protocol::{
3        confirmed::{ComplexAck, ComplexAckService, ConfirmedServiceChoice},
4        primitives::data_value::ApplicationDataValue,
5    },
6    common::{
7        error::Error,
8        helper::{
9            decode_context_object_id, decode_context_property_id, encode_closing_tag,
10            encode_context_enumerated, encode_context_object_id, encode_context_unsigned,
11            encode_opening_tag, get_tagged_body_for_tag,
12        },
13        io::{Reader, Writer},
14        object_id::ObjectId,
15        property_id::PropertyId,
16        spec::BACNET_ARRAY_ALL,
17        tag::{ApplicationTagNumber, Tag, TagNumber},
18    },
19    network_protocol::data_link::DataLink,
20};
21
22#[derive(Debug, Clone)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum ReadPropertyValue<'a> {
25    ObjectIdList(ObjectIdList<'a>),
26    ApplicationDataValue(ApplicationDataValue<'a>),
27}
28
29#[derive(Debug, Clone)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub struct ObjectIdList<'a> {
32    object_ids: &'a [ObjectId],
33    buf: &'a [u8],
34}
35
36#[derive(Debug, Clone)]
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38pub struct ObjectIdIter<'a> {
39    reader: Reader,
40    buf: &'a [u8],
41}
42
43impl<'a> ObjectIdList<'a> {
44    pub fn new(object_ids: &'a [ObjectId]) -> Self {
45        Self {
46            object_ids,
47            buf: &[],
48        }
49    }
50
51    pub fn new_from_buf(buf: &'a [u8]) -> Self {
52        Self {
53            object_ids: &[],
54            buf,
55        }
56    }
57
58    pub fn encode(&self, writer: &mut Writer) {
59        for object_id in self.object_ids {
60            Tag::new(
61                TagNumber::Application(ApplicationTagNumber::ObjectId),
62                ObjectId::LEN,
63            )
64            .encode(writer);
65            object_id.encode(writer);
66        }
67    }
68}
69
70impl<'a> ObjectIdIter<'a> {
71    pub fn new(buf: &'a [u8]) -> Self {
72        Self {
73            reader: Reader::new_with_len(buf.len()),
74            buf,
75        }
76    }
77
78    fn next_internal(&mut self) -> Result<ObjectId, Error> {
79        let tag = Tag::decode_expected(
80            &mut self.reader,
81            self.buf,
82            TagNumber::Application(ApplicationTagNumber::ObjectId),
83            "ObjectIdList nex",
84        )?;
85
86        ObjectId::decode(tag.value, &mut self.reader, self.buf)
87    }
88}
89
90impl<'a> IntoIterator for &'_ ObjectIdList<'a> {
91    type Item = Result<ObjectId, Error>;
92    type IntoIter = ObjectIdIter<'a>;
93
94    fn into_iter(self) -> Self::IntoIter {
95        ObjectIdIter::new(self.buf)
96    }
97}
98
99impl<'a> Iterator for ObjectIdIter<'a> {
100    type Item = Result<ObjectId, Error>;
101
102    fn next(&mut self) -> Option<Self::Item> {
103        if self.reader.eof() {
104            None
105        } else {
106            Some(self.next_internal())
107        }
108    }
109}
110
111#[derive(Debug, Clone)]
112#[cfg_attr(feature = "defmt", derive(defmt::Format))]
113pub struct ReadPropertyAck<'a> {
114    pub object_id: ObjectId,
115    pub property_id: PropertyId,
116    pub property_value: ReadPropertyValue<'a>,
117}
118
119impl<'a> TryFrom<DataLink<'a>> for ReadPropertyAck<'a> {
120    type Error = Error;
121
122    fn try_from(value: DataLink<'a>) -> Result<Self, Self::Error> {
123        let ack: ComplexAck = value.try_into()?;
124        match ack.service {
125            ComplexAckService::ReadProperty(ack) => Ok(ack),
126            _ => Err(Error::ConvertDataLink(
127                "apdu message is not a ComplexAckService ReadPropertyAck",
128            )),
129        }
130    }
131}
132
133impl<'a> ReadPropertyAck<'a> {
134    pub fn encode(&self, writer: &mut Writer) {
135        writer.push(ConfirmedServiceChoice::ReadProperty as u8);
136        encode_context_object_id(writer, 0, &self.object_id);
137        encode_context_enumerated(writer, 1, &self.property_id);
138        encode_opening_tag(writer, 3);
139        match &self.property_value {
140            ReadPropertyValue::ApplicationDataValue(value) => {
141                value.encode(writer);
142            }
143            ReadPropertyValue::ObjectIdList(value) => {
144                value.encode(writer);
145            }
146        }
147        encode_closing_tag(writer, 3);
148    }
149
150    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
151        let object_id =
152            decode_context_object_id(reader, buf, 0, "ReadPropertyAck decode object_id")?;
153        let property_id =
154            decode_context_property_id(reader, buf, 1, "ReadPropertyAck decode property_id")?;
155
156        let buf = get_tagged_body_for_tag(reader, buf, 3, "ReadPropertyAck decode data values")?;
157        let mut reader = Reader {
158            index: 0,
159            end: buf.len(),
160        };
161
162        match property_id {
163            PropertyId::PropObjectList => {
164                let property_value =
165                    ReadPropertyValue::ObjectIdList(ObjectIdList::new_from_buf(buf));
166
167                Ok(Self {
168                    object_id,
169                    property_id,
170                    property_value,
171                })
172            }
173            property_id => {
174                let tag = Tag::decode(&mut reader, buf)?;
175                let value =
176                    ApplicationDataValue::decode(&tag, &object_id, &property_id, &mut reader, buf)?;
177                let property_value = ReadPropertyValue::ApplicationDataValue(value);
178
179                Ok(Self {
180                    object_id,
181                    property_id,
182                    property_value,
183                })
184            }
185        }
186    }
187}
188
189#[derive(Debug, Clone)]
190#[cfg_attr(feature = "defmt", derive(defmt::Format))]
191pub struct ReadProperty {
192    pub object_id: ObjectId,     // e.g ObjectDevice:20088
193    pub property_id: PropertyId, // e.g. PropObjectList
194    pub array_index: u32,        // use BACNET_ARRAY_ALL for all
195}
196
197impl ReadProperty {
198    pub fn new(object_id: ObjectId, property_id: PropertyId) -> Self {
199        Self {
200            object_id,
201            property_id,
202            array_index: BACNET_ARRAY_ALL,
203        }
204    }
205
206    pub fn encode(&self, writer: &mut Writer) {
207        // object_id
208        encode_context_object_id(writer, 0, &self.object_id);
209
210        // property_id
211        encode_context_enumerated(writer, 1, &self.property_id);
212
213        // array_index
214        if self.array_index != BACNET_ARRAY_ALL {
215            encode_context_unsigned(writer, 2, self.array_index);
216        }
217    }
218
219    pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
220        // object_id
221        let object_id = decode_context_object_id(reader, buf, 0, "ReadProperty decode object_id")?;
222
223        // property_id
224        let property_id =
225            decode_context_property_id(reader, buf, 1, "ReadProperty decode property_id")?;
226
227        Ok(Self {
228            object_id,
229            property_id,
230            array_index: BACNET_ARRAY_ALL,
231        })
232    }
233}