embedded_bacnet/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#[derive(Debug, Clone)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub struct ReadRange {
25    pub object_id: ObjectId,     // e.g ObjectTrendLog
26    pub property_id: PropertyId, // e.g. PropLogBuffer
27    pub array_index: u32,        // use BACNET_ARRAY_ALL for all
28    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        // item data
93        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        // object_id
100        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        // property_id
109        let property_id = decode_context_property_id(
110            reader,
111            buf,
112            Self::PROPERTY_ID_TAG,
113            "ReadRangeAck decode property_id",
114        )?;
115
116        // array_index
117        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            // read another tag
123            tag = Tag::decode(reader, buf)?;
124        }
125
126        // result flags
127        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        // item_count
134        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        // item_data
143        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        // date and time
292        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        // value
308        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        // status
323        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        // date and time
329        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        // value
357        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        // status flags
385        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                // index
449                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                // count
458                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                // closing tag
480                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        // object_id
505        encode_context_object_id(writer, Self::OBJECT_ID_TAG, &self.object_id);
506
507        // property_id
508        encode_context_enumerated(writer, Self::PROPERTY_ID_TAG, &self.property_id);
509
510        // array_index
511        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                // do nothing
537            }
538        }
539    }
540}