bacnet_emb/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#[cfg(feature = "alloc")]
23use {
24    crate::common::spooky::Phantom, alloc::vec::Vec, bacnet_macros::remove_lifetimes_from_fn_args,
25};
26
27#[derive(Debug, Clone)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum ReadPropertyValue<'a> {
30    ObjectIdList(ObjectIdList<'a>),
31    ApplicationDataValue(ApplicationDataValue<'a>),
32}
33
34#[cfg(not(feature = "alloc"))]
35#[derive(Debug, Clone)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37pub struct ObjectIdList<'a> {
38    object_ids: &'a [ObjectId],
39    buf: &'a [u8],
40}
41
42#[cfg(feature = "alloc")]
43#[derive(Debug, Clone)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub struct ObjectIdList<'a> {
46    pub object_ids: Vec<ObjectId>,
47    _phantom: &'a Phantom,
48}
49
50#[derive(Debug, Clone)]
51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
52pub struct ObjectIdIter<'a> {
53    reader: Reader,
54    buf: &'a [u8],
55}
56
57impl<'a> ObjectIdList<'a> {
58    #[cfg(not(feature = "alloc"))]
59    pub fn new(object_ids: &'a [ObjectId]) -> Self {
60        Self {
61            object_ids,
62            buf: &[],
63        }
64    }
65
66    #[cfg(not(feature = "alloc"))]
67    pub fn new_from_buf(buf: &'a [u8]) -> Self {
68        Self {
69            object_ids: &[],
70            buf,
71        }
72    }
73
74    #[cfg(feature = "alloc")]
75    pub fn new(object_ids: Vec<ObjectId>) -> Self {
76        use crate::common::spooky::PHANTOM;
77
78        Self {
79            object_ids,
80            _phantom: &PHANTOM,
81        }
82    }
83
84    pub fn encode(&self, writer: &mut Writer) {
85        for object_id in self.object_ids.iter() {
86            Tag::new(
87                TagNumber::Application(ApplicationTagNumber::ObjectId),
88                ObjectId::LEN,
89            )
90            .encode(writer);
91            object_id.encode(writer);
92        }
93    }
94
95    #[cfg(not(feature = "alloc"))]
96    pub fn decode(_reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
97        Ok(Self::new_from_buf(buf))
98    }
99
100    #[cfg(feature = "alloc")]
101    pub fn decode(_reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
102        let decoder = ObjectIdIter::new(buf);
103        let object_ids: Result<Vec<ObjectId>, Error> = decoder.into_iter().collect();
104        Ok(Self::new(object_ids?))
105    }
106}
107
108impl<'a> ObjectIdIter<'a> {
109    pub fn new(buf: &'a [u8]) -> Self {
110        Self {
111            reader: Reader::new_with_len(buf.len()),
112            buf,
113        }
114    }
115
116    fn next_internal(&mut self) -> Result<ObjectId, Error> {
117        let tag = Tag::decode_expected(
118            &mut self.reader,
119            self.buf,
120            TagNumber::Application(ApplicationTagNumber::ObjectId),
121            "ObjectIdList nex",
122        )?;
123
124        ObjectId::decode(tag.value, &mut self.reader, self.buf)
125    }
126}
127
128#[cfg(not(feature = "alloc"))]
129impl<'a> IntoIterator for &'_ ObjectIdList<'a> {
130    type Item = Result<ObjectId, Error>;
131    type IntoIter = ObjectIdIter<'a>;
132
133    fn into_iter(self) -> Self::IntoIter {
134        ObjectIdIter::new(self.buf)
135    }
136}
137
138impl<'a> Iterator for ObjectIdIter<'a> {
139    type Item = Result<ObjectId, Error>;
140
141    fn next(&mut self) -> Option<Self::Item> {
142        if self.reader.eof() {
143            None
144        } else {
145            Some(self.next_internal())
146        }
147    }
148}
149
150#[derive(Debug, Clone)]
151#[cfg_attr(feature = "defmt", derive(defmt::Format))]
152pub struct ReadPropertyAck<'a> {
153    pub object_id: ObjectId,
154    pub property_id: PropertyId,
155    pub property_value: ReadPropertyValue<'a>,
156}
157
158impl<'a> TryFrom<DataLink<'a>> for ReadPropertyAck<'a> {
159    type Error = Error;
160
161    fn try_from(value: DataLink<'a>) -> Result<Self, Self::Error> {
162        let ack: ComplexAck = value.try_into()?;
163        match ack.service {
164            ComplexAckService::ReadProperty(ack) => Ok(ack),
165            _ => Err(Error::ConvertDataLink(
166                "apdu message is not a ComplexAckService ReadPropertyAck",
167            )),
168        }
169    }
170}
171
172impl<'a> ReadPropertyAck<'a> {
173    pub fn encode(&self, writer: &mut Writer) {
174        writer.push(ConfirmedServiceChoice::ReadProperty as u8);
175        encode_context_object_id(writer, 0, &self.object_id);
176        encode_context_enumerated(writer, 1, &self.property_id);
177        encode_opening_tag(writer, 3);
178        match &self.property_value {
179            ReadPropertyValue::ApplicationDataValue(value) => {
180                value.encode(writer);
181            }
182            ReadPropertyValue::ObjectIdList(value) => {
183                value.encode(writer);
184            }
185        }
186        encode_closing_tag(writer, 3);
187    }
188
189    #[cfg_attr(feature = "alloc", remove_lifetimes_from_fn_args)]
190    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
191        let object_id =
192            decode_context_object_id(reader, buf, 0, "ReadPropertyAck decode object_id")?;
193        let property_id =
194            decode_context_property_id(reader, buf, 1, "ReadPropertyAck decode property_id")?;
195
196        let buf = get_tagged_body_for_tag(reader, buf, 3, "ReadPropertyAck decode data values")?;
197        let mut reader = Reader::new_with_len(buf.len());
198
199        match property_id {
200            PropertyId::PropObjectList => {
201                let object_ids = ObjectIdList::decode(&mut reader, buf)?;
202                let property_value = ReadPropertyValue::ObjectIdList(object_ids);
203
204                Ok(Self {
205                    object_id,
206                    property_id,
207                    property_value,
208                })
209            }
210            property_id => {
211                let tag = Tag::decode(&mut reader, buf)?;
212                let value =
213                    ApplicationDataValue::decode(&tag, &object_id, &property_id, &mut reader, buf)?;
214                let property_value = ReadPropertyValue::ApplicationDataValue(value);
215
216                Ok(Self {
217                    object_id,
218                    property_id,
219                    property_value,
220                })
221            }
222        }
223    }
224}
225
226#[derive(Debug, Clone)]
227#[cfg_attr(feature = "defmt", derive(defmt::Format))]
228pub struct ReadProperty {
229    pub object_id: ObjectId,     // e.g ObjectDevice:20088
230    pub property_id: PropertyId, // e.g. PropObjectList
231    pub array_index: u32,        // use BACNET_ARRAY_ALL for all
232}
233
234impl ReadProperty {
235    
236    pub fn new(object_id: ObjectId, property_id: PropertyId) -> Self {
237        Self {
238            object_id,
239            property_id,
240            array_index: BACNET_ARRAY_ALL,
241        }
242    }
243
244    pub fn encode(&self, writer: &mut Writer) {
245        // object_id
246        encode_context_object_id(writer, 0, &self.object_id);
247
248        // property_id
249        encode_context_enumerated(writer, 1, &self.property_id);
250
251        // array_index
252        if self.array_index != BACNET_ARRAY_ALL {
253            encode_context_unsigned(writer, 2, self.array_index);
254        }
255    }
256
257    pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
258        // object_id
259        let object_id = decode_context_object_id(reader, buf, 0, "ReadProperty decode object_id")?;
260
261        // property_id
262        let property_id =
263            decode_context_property_id(reader, buf, 1, "ReadProperty decode property_id")?;
264
265        Ok(Self {
266            object_id,
267            property_id,
268            array_index: BACNET_ARRAY_ALL,
269        })
270    }
271}