bacnet_emb/application_protocol/services/
write_property.rs

1use crate::{
2    application_protocol::primitives::data_value::ApplicationDataValueWrite,
3    common::{
4        error::Error,
5        helper::{
6            decode_context_object_id, decode_context_property_id, decode_unsigned,
7            encode_closing_tag, encode_context_enumerated, encode_context_object_id,
8            encode_context_unsigned, encode_opening_tag,
9        },
10        io::{Reader, Writer},
11        object_id::ObjectId,
12        property_id::PropertyId,
13        spec::BACNET_ARRAY_ALL,
14        tag::{Tag, TagNumber},
15    },
16};
17
18#[derive(Debug, Clone)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub struct WriteProperty<'a> {
21    pub object_id: ObjectId,
22    pub property_id: PropertyId,
23    pub priority: Option<u8>,
24    pub array_index: Option<u32>,
25    pub value: ApplicationDataValueWrite<'a>,
26}
27
28impl<'a> WriteProperty<'a> {
29    const TAG_OBJECT_ID: u8 = 0;
30    const TAG_PROPERTY_ID: u8 = 1;
31    const TAG_ARRAY_INDEX: u8 = 2;
32    const TAG_VALUE: u8 = 3;
33    const TAG_PRIORITY: u8 = 4;
34    const LOWEST_PRIORITY: u8 = 16;
35
36    pub fn new(
37        object_id: ObjectId,
38        property_id: PropertyId,
39        priority: Option<u8>,
40        array_index: Option<u32>,
41        value: ApplicationDataValueWrite<'a>,
42    ) -> Self {
43        Self {
44            object_id,
45            property_id,
46            priority,
47            array_index,
48            value,
49        }
50    }
51
52    #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
53    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
54        let object_id = decode_context_object_id(
55            reader,
56            buf,
57            Self::TAG_OBJECT_ID,
58            "WriteProperty decode object_id",
59        )?;
60        let property_id = decode_context_property_id(
61            reader,
62            buf,
63            Self::TAG_PROPERTY_ID,
64            "WriteProperty decode property_id",
65        )?;
66
67        // array_index
68        let mut tag = Tag::decode(reader, buf)?;
69        let mut array_index = None;
70        if let TagNumber::ContextSpecific(Self::TAG_ARRAY_INDEX) = tag.number {
71            let array_index_tmp = decode_unsigned(tag.value, reader, buf)? as u32;
72            if array_index_tmp != BACNET_ARRAY_ALL {
73                array_index = Some(array_index_tmp)
74            }
75
76            // read another tag
77            tag = Tag::decode(reader, buf)?;
78        }
79
80        // value
81        tag.expect_number(
82            "WriteProperty decode value",
83            TagNumber::ContextSpecificOpening(Self::TAG_VALUE),
84        )?;
85        let value = ApplicationDataValueWrite::decode(&object_id, &property_id, reader, buf)?;
86        Tag::decode_expected(
87            reader,
88            buf,
89            TagNumber::ContextSpecificClosing(Self::TAG_VALUE),
90            "WriteProperty decode value",
91        )?;
92
93        // priority
94        let tag = Tag::decode_expected(
95            reader,
96            buf,
97            TagNumber::ContextSpecific(Self::TAG_PRIORITY),
98            "WriteProperty decode priority",
99        )?;
100        let priority = tag.value as u8;
101        let priority = if priority == Self::LOWEST_PRIORITY {
102            None
103        } else {
104            Some(priority)
105        };
106
107        Ok(Self {
108            object_id,
109            property_id,
110            array_index,
111            value,
112            priority,
113        })
114    }
115
116    pub fn encode(&self, writer: &mut Writer) {
117        // object_id
118        encode_context_object_id(writer, Self::TAG_OBJECT_ID, &self.object_id);
119
120        // property_id
121        encode_context_enumerated(writer, Self::TAG_PROPERTY_ID, &self.property_id);
122
123        // array_index
124        if let Some(array_index) = self.array_index {
125            encode_context_unsigned(writer, Self::TAG_ARRAY_INDEX, array_index);
126        }
127
128        // value
129        encode_opening_tag(writer, Self::TAG_VALUE);
130        self.value.encode(writer);
131        encode_closing_tag(writer, Self::TAG_VALUE);
132
133        // priority 0-16 (16 being lowest priority)
134        let priority = self
135            .priority
136            .unwrap_or(Self::LOWEST_PRIORITY)
137            .min(Self::LOWEST_PRIORITY) as u32;
138        encode_context_unsigned(writer, Self::TAG_PRIORITY, priority);
139    }
140}