bacnet_emb/application_protocol/services/
read_range.rs

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