embedded_bacnet/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    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
53        let object_id = decode_context_object_id(
54            reader,
55            buf,
56            Self::TAG_OBJECT_ID,
57            "WriteProperty decode object_id",
58        )?;
59        let property_id = decode_context_property_id(
60            reader,
61            buf,
62            Self::TAG_PROPERTY_ID,
63            "WriteProperty decode property_id",
64        )?;
65
66        // array_index
67        let mut tag = Tag::decode(reader, buf)?;
68        let mut array_index = None;
69        if let TagNumber::ContextSpecific(Self::TAG_ARRAY_INDEX) = tag.number {
70            let array_index_tmp = decode_unsigned(tag.value, reader, buf)? as u32;
71            if array_index_tmp != BACNET_ARRAY_ALL {
72                array_index = Some(array_index_tmp)
73            }
74
75            // read another tag
76            tag = Tag::decode(reader, buf)?;
77        }
78
79        // value
80        tag.expect_number(
81            "WriteProperty decode value",
82            TagNumber::ContextSpecificOpening(Self::TAG_VALUE),
83        )?;
84        let value = ApplicationDataValueWrite::decode(&object_id, &property_id, reader, buf)?;
85        Tag::decode_expected(
86            reader,
87            buf,
88            TagNumber::ContextSpecificClosing(Self::TAG_VALUE),
89            "WriteProperty decode value",
90        )?;
91
92        // priority
93        let tag = Tag::decode_expected(
94            reader,
95            buf,
96            TagNumber::ContextSpecific(Self::TAG_PRIORITY),
97            "WriteProperty decode priority",
98        )?;
99        let priority = tag.value as u8;
100        let priority = if priority == Self::LOWEST_PRIORITY {
101            None
102        } else {
103            Some(priority)
104        };
105
106        Ok(Self {
107            object_id,
108            property_id,
109            array_index,
110            value,
111            priority,
112        })
113    }
114
115    pub fn encode(&self, writer: &mut Writer) {
116        // object_id
117        encode_context_object_id(writer, Self::TAG_OBJECT_ID, &self.object_id);
118
119        // property_id
120        encode_context_enumerated(writer, Self::TAG_PROPERTY_ID, &self.property_id);
121
122        // array_index
123        if let Some(array_index) = self.array_index {
124            encode_context_unsigned(writer, Self::TAG_ARRAY_INDEX, array_index);
125        }
126
127        // value
128        encode_opening_tag(writer, Self::TAG_VALUE);
129        self.value.encode(writer);
130        encode_closing_tag(writer, Self::TAG_VALUE);
131
132        // priority 0-16 (16 being lowest priority)
133        let priority = self
134            .priority
135            .unwrap_or(Self::LOWEST_PRIORITY)
136            .min(Self::LOWEST_PRIORITY) as u32;
137        encode_context_unsigned(writer, Self::TAG_PRIORITY, priority);
138    }
139}