1use crate::{
2 application_protocol::{
3 confirmed::ConfirmedServiceChoice,
4 primitives::data_value::{BitString, Date, Time},
5 },
6 common::{
7 error::{Error, Unimplemented},
8 helper::{
9 decode_context_object_id, decode_context_property_id, decode_signed, decode_unsigned,
10 encode_application_signed, encode_application_unsigned, encode_closing_tag,
11 encode_context_enumerated, encode_context_object_id, encode_context_unsigned,
12 encode_opening_tag, get_tagged_body_for_tag,
13 },
14 io::{Reader, Writer},
15 object_id::ObjectId,
16 property_id::PropertyId,
17 spec::BACNET_ARRAY_ALL,
18 tag::{ApplicationTagNumber, Tag, TagNumber},
19 },
20};
21
22#[derive(Debug, Clone)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub struct ReadRange {
25 pub object_id: ObjectId, pub property_id: PropertyId, pub array_index: u32, pub request_type: ReadRangeRequestType,
29}
30
31#[derive(Debug, Clone)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33pub enum ReadRangeRequestType {
34 ByPosition(ReadRangeByPosition),
35 BySequence(ReadRangeBySequence),
36 ByTime(ReadRangeByTime),
37 All,
38}
39
40#[derive(Debug, Clone)]
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub struct ReadRangeByPosition {
43 pub index: u32,
44 pub count: u32,
45}
46
47#[derive(Debug, Clone)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub struct ReadRangeBySequence {
50 pub sequence_num: u32,
51 pub count: u32,
52}
53
54#[derive(Debug, Clone)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56pub struct ReadRangeByTime {
57 pub date: Date,
58 pub time: Time,
59 pub count: u32,
60}
61
62#[derive(Debug, Clone)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64pub struct ReadRangeAck<'a> {
65 pub object_id: ObjectId,
66 pub property_id: PropertyId,
67 pub array_index: u32,
68 pub result_flags: BitString<'a>,
69 pub item_count: usize,
70 pub item_data: ReadRangeItems<'a>,
71}
72
73impl<'a> ReadRangeAck<'a> {
74 const OBJECT_ID_TAG: u8 = 0;
75 const PROPERTY_ID_TAG: u8 = 1;
76 const ARRAY_INDEX_TAG: u8 = 2;
77 const RESULT_FLAGS_TAG: u8 = 3;
78 const ITEM_COUNT_TAG: u8 = 4;
79 const ITEM_DATA_TAG: u8 = 5;
80
81 pub fn encode(&self, writer: &mut Writer) {
82 writer.push(ConfirmedServiceChoice::ReadRange as u8);
83 encode_context_object_id(writer, Self::OBJECT_ID_TAG, &self.object_id);
84 encode_context_enumerated(writer, Self::PROPERTY_ID_TAG, &self.property_id);
85 if self.array_index != BACNET_ARRAY_ALL {
86 encode_context_unsigned(writer, Self::ARRAY_INDEX_TAG, self.array_index)
87 }
88 self.result_flags
89 .encode_context(Self::RESULT_FLAGS_TAG, writer);
90 encode_context_unsigned(writer, Self::ITEM_COUNT_TAG, self.item_count as u32);
91
92 encode_opening_tag(writer, Self::ITEM_DATA_TAG);
94 self.item_data.encode(writer);
95 encode_closing_tag(writer, Self::ITEM_DATA_TAG);
96 }
97
98 pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
99 let tag = Tag::decode_expected(
101 reader,
102 buf,
103 TagNumber::ContextSpecific(Self::OBJECT_ID_TAG),
104 "ReadRangeAck decode object_id",
105 )?;
106 let object_id = ObjectId::decode(tag.value, reader, buf)?;
107
108 let property_id = decode_context_property_id(
110 reader,
111 buf,
112 Self::PROPERTY_ID_TAG,
113 "ReadRangeAck decode property_id",
114 )?;
115
116 let mut tag = Tag::decode(reader, buf)?;
118 let mut array_index = BACNET_ARRAY_ALL;
119 if let TagNumber::ContextSpecific(Self::ARRAY_INDEX_TAG) = tag.number {
120 array_index = decode_unsigned(tag.value, reader, buf)? as u32;
121
122 tag = Tag::decode(reader, buf)?;
124 }
125
126 tag.expect_number(
128 "ReadRangeAck decode result_flag",
129 TagNumber::ContextSpecific(Self::RESULT_FLAGS_TAG),
130 )?;
131 let result_flags = BitString::decode(&property_id, tag.value, reader, buf)?;
132
133 let tag = Tag::decode_expected(
135 reader,
136 buf,
137 TagNumber::ContextSpecific(Self::ITEM_COUNT_TAG),
138 "ReadRangeAck decode item_count",
139 )?;
140 let item_count = decode_unsigned(tag.value, reader, buf)? as usize;
141
142 let buf = if reader.eof() {
144 &[]
145 } else {
146 get_tagged_body_for_tag(
147 reader,
148 buf,
149 Self::ITEM_DATA_TAG,
150 "ReadRangeAck decode item_data",
151 )?
152 };
153 let item_data = ReadRangeItems::new_from_buf(buf);
154
155 Ok(Self {
156 object_id,
157 property_id,
158 array_index,
159 result_flags,
160 item_count,
161 item_data,
162 })
163 }
164}
165
166#[derive(Debug, Clone)]
167#[cfg_attr(feature = "defmt", derive(defmt::Format))]
168pub struct ReadRangeItems<'a> {
169 items: &'a [ReadRangeItem<'a>],
170 buf: &'a [u8],
171}
172
173#[derive(Debug, Clone)]
174#[cfg_attr(feature = "defmt", derive(defmt::Format))]
175#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176pub enum ReadRangeValue {
177 Status,
178 Bool(bool),
179 Real(f32),
180 Enum(u32),
181 Unsigned(u32),
182 Signed(i32),
183 Bits,
184 Null,
185 Error,
186 Delta,
187 Any,
188}
189
190#[derive(Debug, Clone)]
191#[cfg_attr(feature = "defmt", derive(defmt::Format))]
192#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
193#[repr(u8)]
194pub enum ReadRangeValueType {
195 Status = 0,
196 Bool = 1,
197 Real = 2,
198 Enum = 3,
199 Unsigned = 4,
200 Signed = 5,
201 Bits = 6,
202 Null = 7,
203 Error = 8,
204 Delta = 9,
205 Any = 10,
206}
207
208impl TryFrom<u8> for ReadRangeValueType {
209 type Error = u8;
210
211 fn try_from(value: u8) -> Result<Self, u8> {
212 match value {
213 0 => Ok(Self::Status),
214 1 => Ok(Self::Bool),
215 2 => Ok(Self::Real),
216 3 => Ok(Self::Enum),
217 4 => Ok(Self::Unsigned),
218 5 => Ok(Self::Signed),
219 6 => Ok(Self::Bits),
220 7 => Ok(Self::Null),
221 8 => Ok(Self::Error),
222 9 => Ok(Self::Delta),
223 10 => Ok(Self::Any),
224 unknown => Err(unknown),
225 }
226 }
227}
228
229impl<'a> ReadRangeItems<'a> {
230 pub fn new_from_buf(buf: &'a [u8]) -> Self {
231 Self { items: &[], buf }
232 }
233
234 pub fn new(items: &'a [ReadRangeItem<'a>]) -> Self {
235 Self { items, buf: &[] }
236 }
237
238 pub fn encode(&self, writer: &mut Writer) {
239 for item in self.items {
240 item.encode(writer)
241 }
242 }
243}
244
245impl<'a> IntoIterator for &'_ ReadRangeItems<'a> {
246 type Item = Result<ReadRangeItem<'a>, Error>;
247
248 type IntoIter = ReadRangeItemsIter<'a>;
249
250 fn into_iter(self) -> Self::IntoIter {
251 ReadRangeItemsIter {
252 buf: self.buf,
253 reader: Reader::new_with_len(self.buf.len()),
254 }
255 }
256}
257
258pub struct ReadRangeItemsIter<'a> {
259 reader: Reader,
260 buf: &'a [u8],
261}
262
263impl<'a> Iterator for ReadRangeItemsIter<'a> {
264 type Item = Result<ReadRangeItem<'a>, Error>;
265
266 fn next(&mut self) -> Option<Self::Item> {
267 if self.reader.eof() {
268 return None;
269 }
270
271 let item = ReadRangeItem::decode(&mut self.reader, self.buf);
272 Some(item)
273 }
274}
275
276#[derive(Debug, Clone)]
277#[cfg_attr(feature = "defmt", derive(defmt::Format))]
278pub struct ReadRangeItem<'a> {
279 pub date: Date,
280 pub time: Time,
281 pub value: ReadRangeValue,
282 pub status_flags: BitString<'a>,
283}
284
285impl<'a> ReadRangeItem<'a> {
286 const DATE_TIME_TAG: u8 = 0;
287 const VALUE_TAG: u8 = 1;
288 const STATUS_FLAGS_TAG: u8 = 2;
289
290 pub fn encode(&self, writer: &mut Writer) {
291 Tag::new(TagNumber::ContextSpecificOpening(Self::DATE_TIME_TAG), 0).encode(writer);
293 Tag::new(
294 TagNumber::Application(ApplicationTagNumber::Date),
295 Date::LEN,
296 )
297 .encode(writer);
298 self.date.encode(writer);
299 Tag::new(
300 TagNumber::Application(ApplicationTagNumber::Time),
301 Time::LEN,
302 )
303 .encode(writer);
304 self.time.encode(writer);
305 Tag::new(TagNumber::ContextSpecificClosing(Self::DATE_TIME_TAG), 0).encode(writer);
306
307 Tag::new(TagNumber::ContextSpecificOpening(Self::VALUE_TAG), 0).encode(writer);
309 match self.value {
310 ReadRangeValue::Real(value) => {
311 Tag::new(
312 TagNumber::ContextSpecific(ReadRangeValueType::Real as u8),
313 4,
314 )
315 .encode(writer);
316 writer.extend_from_slice(&value.to_be_bytes());
317 }
318 _ => todo!("{:?}", self.value),
319 }
320 Tag::new(TagNumber::ContextSpecificClosing(Self::VALUE_TAG), 0).encode(writer);
321
322 self.status_flags
324 .encode_context(Self::STATUS_FLAGS_TAG, writer);
325 }
326
327 pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
328 Tag::decode_expected(
330 reader,
331 buf,
332 TagNumber::ContextSpecificOpening(Self::DATE_TIME_TAG),
333 "ReadRangeItem decode",
334 )?;
335 Tag::decode_expected(
336 reader,
337 buf,
338 TagNumber::Application(ApplicationTagNumber::Date),
339 "ReadRangeItem decode",
340 )?;
341 let date = Date::decode(reader, buf)?;
342 Tag::decode_expected(
343 reader,
344 buf,
345 TagNumber::Application(ApplicationTagNumber::Time),
346 "ReadRangeItem decode",
347 )?;
348 let time = Time::decode(reader, buf)?;
349 Tag::decode_expected(
350 reader,
351 buf,
352 TagNumber::ContextSpecificClosing(Self::DATE_TIME_TAG),
353 "ReadRangeItem decode",
354 )?;
355
356 Tag::decode_expected(
358 reader,
359 buf,
360 TagNumber::ContextSpecificOpening(Self::VALUE_TAG),
361 "ReadRangeItem decode",
362 )?;
363 let tag = Tag::decode(reader, buf)?;
364 let value_type: ReadRangeValueType = match tag.number {
365 TagNumber::ContextSpecific(tag_number) => tag_number
366 .try_into()
367 .map_err(|x| Error::InvalidVariant(("ReadRangeValueType", x as u32)))?,
368 x => return Err(Error::TagNotSupported(("ReadRangeItems next value", x))),
369 };
370 let value = match value_type {
371 ReadRangeValueType::Real => {
372 let value = f32::from_be_bytes(reader.read_bytes(buf)?);
373 ReadRangeValue::Real(value)
374 }
375 x => return Err(Error::Unimplemented(Unimplemented::ReadRangeValueType(x))),
376 };
377 Tag::decode_expected(
378 reader,
379 buf,
380 TagNumber::ContextSpecificClosing(Self::VALUE_TAG),
381 "ReadRangeItem decode",
382 )?;
383
384 Tag::decode_expected(
386 reader,
387 buf,
388 TagNumber::ContextSpecific(Self::STATUS_FLAGS_TAG),
389 "ReadRangeItem decode",
390 )?;
391 let status_flags = BitString::decode(&PropertyId::PropStatusFlags, tag.value, reader, buf)?;
392
393 Ok(ReadRangeItem {
394 date,
395 time,
396 value,
397 status_flags,
398 })
399 }
400}
401
402impl ReadRange {
403 const OBJECT_ID_TAG: u8 = 0;
404 const PROPERTY_ID_TAG: u8 = 1;
405 const ARRAY_INDEX_TAG: u8 = 2;
406 const BY_POSITION_TAG: u8 = 3;
407 const BY_SEQUENCE_TAG: u8 = 6;
408 const BY_TIME_TAG: u8 = 7;
409
410 pub fn new(
411 object_id: ObjectId,
412 property_id: PropertyId,
413 request_type: ReadRangeRequestType,
414 ) -> Self {
415 Self {
416 object_id,
417 property_id,
418 array_index: BACNET_ARRAY_ALL,
419 request_type,
420 }
421 }
422
423 pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
424 let object_id = decode_context_object_id(
425 reader,
426 buf,
427 Self::OBJECT_ID_TAG,
428 "ReadRange decode object_id",
429 )?;
430 let property_id = decode_context_property_id(
431 reader,
432 buf,
433 Self::PROPERTY_ID_TAG,
434 "ReadRange decode property_id",
435 )?;
436
437 let mut tag = Tag::decode(reader, buf)?;
438 let array_index = if tag.number == TagNumber::ContextSpecific(Self::ARRAY_INDEX_TAG) {
439 let value = decode_unsigned(tag.value, reader, buf)? as u32;
440 tag = Tag::decode(reader, buf)?;
441 value
442 } else {
443 BACNET_ARRAY_ALL
444 };
445
446 let request_type = match tag.number {
447 TagNumber::ContextSpecificOpening(Self::BY_POSITION_TAG) => {
448 let index_tag = Tag::decode_expected(
450 reader,
451 buf,
452 TagNumber::Application(ApplicationTagNumber::UnsignedInt),
453 "ReadRange decode index",
454 )?;
455 let index = decode_unsigned(index_tag.value, reader, buf)? as u32;
456
457 let count_tag = Tag::decode(reader, buf)?;
459 let count = match count_tag.number {
460 TagNumber::Application(ApplicationTagNumber::UnsignedInt) => {
461 decode_unsigned(count_tag.value, reader, buf)? as u32
462 }
463 TagNumber::Application(ApplicationTagNumber::SignedInt) => {
464 let count = decode_signed(count_tag.value, reader, buf)?;
465 if count < 0 {
466 return Err(Error::InvalidValue("ReadRange count cannot be negative"));
467 }
468
469 count as u32
470 }
471 _ => {
472 return Err(Error::TagNotSupported((
473 "ReadRange count tag",
474 count_tag.number,
475 )))
476 }
477 };
478
479 Tag::decode_expected(
481 reader,
482 buf,
483 TagNumber::ContextSpecificClosing(Self::BY_POSITION_TAG),
484 "ReadRange decode closing position",
485 )?;
486
487 ReadRangeRequestType::ByPosition(ReadRangeByPosition {
488 count: count as u32,
489 index,
490 })
491 }
492 number => return Err(Error::TagNotSupported(("ReadRange opening tag", number))),
493 };
494
495 Ok(Self {
496 array_index,
497 object_id,
498 property_id,
499 request_type,
500 })
501 }
502
503 pub fn encode(&self, writer: &mut Writer) {
504 encode_context_object_id(writer, Self::OBJECT_ID_TAG, &self.object_id);
506
507 encode_context_enumerated(writer, Self::PROPERTY_ID_TAG, &self.property_id);
509
510 if self.array_index != BACNET_ARRAY_ALL {
512 encode_context_unsigned(writer, Self::ARRAY_INDEX_TAG, self.array_index);
513 }
514
515 match &self.request_type {
516 ReadRangeRequestType::ByPosition(x) => {
517 encode_opening_tag(writer, Self::BY_POSITION_TAG);
518 encode_application_unsigned(writer, x.index as u64);
519 encode_application_signed(writer, x.count as i32);
520 encode_closing_tag(writer, Self::BY_POSITION_TAG);
521 }
522 ReadRangeRequestType::BySequence(x) => {
523 encode_opening_tag(writer, Self::BY_SEQUENCE_TAG);
524 encode_application_unsigned(writer, x.sequence_num as u64);
525 encode_application_signed(writer, x.count as i32);
526 encode_closing_tag(writer, Self::BY_SEQUENCE_TAG);
527 }
528 ReadRangeRequestType::ByTime(x) => {
529 encode_opening_tag(writer, Self::BY_TIME_TAG);
530 x.date.encode(writer);
531 x.time.encode(writer);
532 encode_application_signed(writer, x.count as i32);
533 encode_closing_tag(writer, Self::BY_TIME_TAG);
534 }
535 ReadRangeRequestType::All => {
536 }
538 }
539 }
540}