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