embedded_bacnet/application_protocol/services/
change_of_value.rs1use crate::{
4 application_protocol::primitives::data_value::ApplicationDataValue,
5 common::{
6 error::Error,
7 helper::{
8 decode_unsigned, encode_context_bool, encode_context_object_id,
9 encode_context_unsigned, get_tagged_body_for_tag,
10 },
11 io::{Reader, Writer},
12 object_id::{ObjectId, ObjectType},
13 property_id::PropertyId,
14 tag::{Tag, TagNumber},
15 },
16};
17
18#[derive(Debug, Clone)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub struct CovNotification<'a> {
21 pub process_id: u32,
22 pub device_id: ObjectId,
23 pub object_id: ObjectId,
24 pub time_remaining_seconds: u32,
25 pub values: CovNotificationValues<'a>,
26}
27
28#[derive(Debug, Clone)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30pub struct CovNotificationValues<'a> {
31 _property_results: &'a [PropertyResult<'a>], object_id: ObjectId,
33 buf: &'a [u8],
34}
35
36#[derive(Debug, Clone)]
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38pub struct PropertyResult<'a> {
39 pub id: PropertyId,
40 pub value: ApplicationDataValue<'a>,
41}
42
43impl<'a> PropertyResult<'a> {
44 pub fn decode(reader: &mut Reader, buf: &'a [u8], object_id: &ObjectId) -> Result<Self, Error> {
45 let tag = Tag::decode_expected(
47 reader,
48 buf,
49 TagNumber::ContextSpecific(0),
50 "CovNotification next property_id",
51 )?;
52 let property_id: PropertyId = (decode_unsigned(tag.value, reader, buf)? as u32).into();
53
54 Tag::decode_expected(
56 reader,
57 buf,
58 TagNumber::ContextSpecificOpening(2),
59 "CovNotification next expected value opening tag",
60 )?;
61 let tag = Tag::decode(reader, buf)?;
62 let value = ApplicationDataValue::decode(&tag, object_id, &property_id, reader, buf)?;
63 Tag::decode_expected(
64 reader,
65 buf,
66 TagNumber::ContextSpecificClosing(2),
67 "CovNotification next expected value closing tag",
68 )?;
69
70 Ok(PropertyResult {
71 id: property_id,
72 value,
73 })
74 }
75}
76
77impl<'a> CovNotification<'a> {
78 const TAG_PROCESS_ID: u8 = 0;
79 const TAG_DEVICE_ID: u8 = 1;
80 const TAG_OBJECT_ID: u8 = 2;
81 const TAG_LIFETIME: u8 = 3;
82 const TAG_LIST_OF_VALUES: u8 = 4;
83
84 pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
85 let tag = Tag::decode_expected(
89 reader,
90 buf,
91 TagNumber::ContextSpecific(Self::TAG_PROCESS_ID),
92 "CovNotification process_id",
93 )?;
94 let process_id = decode_unsigned(tag.value, reader, buf)? as u32;
95
96 let tag = Tag::decode_expected(
98 reader,
99 buf,
100 TagNumber::ContextSpecific(Self::TAG_DEVICE_ID),
101 "CovNotification device_id tag",
102 )?;
103 let device_id = ObjectId::decode(tag.value, reader, buf)?;
104 if device_id.object_type != ObjectType::ObjectDevice {
105 return Err(Error::InvalidValue(
106 "expected device object type for CovNotification device_id field",
107 ));
108 }
109
110 let tag = Tag::decode_expected(
112 reader,
113 buf,
114 TagNumber::ContextSpecific(Self::TAG_OBJECT_ID),
115 "CovNotification object_id",
116 )?;
117 let object_id = ObjectId::decode(tag.value, reader, buf)?;
118
119 let tag = Tag::decode_expected(
121 reader,
122 buf,
123 TagNumber::ContextSpecific(Self::TAG_LIFETIME),
124 "CovNotification lifetime",
125 )?;
126 let time_remaining_seconds = decode_unsigned(tag.value, reader, buf)? as u32;
127
128 let buf = get_tagged_body_for_tag(
130 reader,
131 buf,
132 Self::TAG_LIST_OF_VALUES,
133 "CovNotification decode list of values",
134 )?;
135 let values = CovNotificationValues {
136 buf,
137 _property_results: &[],
138 object_id,
139 };
140
141 Ok(Self {
142 process_id,
143 device_id,
144 object_id,
145 time_remaining_seconds,
146 values,
147 })
148 }
149}
150
151impl<'a> IntoIterator for &'_ CovNotificationValues<'a> {
152 type Item = Result<PropertyResult<'a>, Error>;
153 type IntoIter = CovNotificationIter<'a>;
154
155 fn into_iter(self) -> Self::IntoIter {
156 CovNotificationIter {
157 buf: self.buf,
158 reader: Reader::new_with_len(self.buf.len()),
159 object_id: self.object_id,
160 }
161 }
162}
163
164pub struct CovNotificationIter<'a> {
165 object_id: ObjectId,
166 reader: Reader,
167 buf: &'a [u8],
168}
169
170impl<'a> Iterator for CovNotificationIter<'a> {
171 type Item = Result<PropertyResult<'a>, Error>;
172
173 fn next(&mut self) -> Option<Self::Item> {
174 if self.reader.eof() {
175 return None;
176 }
177
178 let result = PropertyResult::decode(&mut self.reader, self.buf, &self.object_id);
179 Some(result)
180 }
181}
182
183#[derive(Debug, Clone)]
184#[cfg_attr(feature = "defmt", derive(defmt::Format))]
185pub struct SubscribeCov {
186 process_id: u32,
187 object_id: ObjectId,
188 issue_confirmed_notifications: bool,
189 lifetime_seconds: u32, }
191
192impl SubscribeCov {
193 const TAG_PROCESS_ID: u8 = 0;
194 const TAG_OBJECT_ID: u8 = 1;
195 const TAG_CONFIRMED: u8 = 2;
196 const TAG_LIFETIME: u8 = 3;
197
198 pub fn new(
199 process_id: u32,
200 object_id: ObjectId,
201 issue_confirmed_notifications: bool,
202 lifetime_seconds: u32,
203 ) -> Self {
204 Self {
205 process_id,
206 object_id,
207 issue_confirmed_notifications,
208 lifetime_seconds,
209 }
210 }
211
212 pub fn encode(&self, writer: &mut Writer) {
213 encode_context_unsigned(writer, Self::TAG_PROCESS_ID, self.process_id);
215
216 encode_context_object_id(writer, Self::TAG_OBJECT_ID, &self.object_id);
218
219 encode_context_bool(
221 writer,
222 Self::TAG_CONFIRMED,
223 self.issue_confirmed_notifications,
224 );
225
226 encode_context_unsigned(writer, Self::TAG_LIFETIME, self.lifetime_seconds);
228 }
229}