embedded_bacnet/common/
tag.rs

1use super::{
2    error::{Error, ExpectedTag},
3    io::{Reader, Writer},
4};
5
6// byte0:
7// bits 7-4 tag_num
8// bit  3   class (0 = application tag_num, 1 = context specific tag_num)
9// bits 2-0 length / value / type
10//
11// Can use additional bytes as specified in bits 2-0 above
12
13#[derive(Debug, Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16#[repr(u8)]
17pub enum ApplicationTagNumber {
18    Null = 0,
19    Boolean = 1,
20    UnsignedInt = 2,
21    SignedInt = 3,
22    Real = 4,
23    Double = 5,
24    OctetString = 6,
25    CharacterString = 7,
26    BitString = 8,
27    Enumerated = 9,
28    Date = 10,
29    Time = 11,
30    ObjectId = 12,
31    Reserve1 = 13,
32    Reserve2 = 14,
33    Reserve3 = 15,
34}
35
36impl From<u8> for ApplicationTagNumber {
37    fn from(tag_number: u8) -> Self {
38        match tag_number {
39            0 => Self::Null,
40            1 => Self::Boolean,
41            2 => Self::UnsignedInt,
42            3 => Self::SignedInt,
43            4 => Self::Real,
44            5 => Self::Double,
45            6 => Self::OctetString,
46            7 => Self::CharacterString,
47            8 => Self::BitString,
48            9 => Self::Enumerated,
49            10 => Self::Date,
50            11 => Self::Time,
51            12 => Self::ObjectId,
52            13 => Self::Reserve1,
53            14 => Self::Reserve2,
54            15 => Self::Reserve3,
55            _ => unreachable!(), // tag_number is only 4 bits
56        }
57    }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq)]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63pub enum TagNumber {
64    Application(ApplicationTagNumber),
65    ContextSpecific(u8),
66    ContextSpecificOpening(u8),
67    ContextSpecificClosing(u8),
68}
69
70#[derive(Debug, Clone)]
71#[cfg_attr(feature = "defmt", derive(defmt::Format))]
72#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
73pub struct Tag {
74    pub number: TagNumber,
75    pub value: u32,
76}
77
78impl Tag {
79    pub fn new(number: TagNumber, value: u32) -> Self {
80        Self { number, value }
81    }
82
83    pub fn encode(&self, writer: &mut Writer) {
84        let mut buf: [u8; 10] = [0; 10];
85        let mut len = 1;
86
87        match &self.number {
88            TagNumber::Application(num) => {
89                buf[0] |= (num.clone() as u8) << 4;
90            }
91            TagNumber::ContextSpecificOpening(num) => {
92                let num = *num;
93                buf[0] |= 0b1000; // set class to context specific
94
95                if num <= 14 {
96                    buf[0] |= num << 4;
97                } else {
98                    buf[0] |= 0xF0;
99                    buf[1] = num;
100                    len += 1;
101                }
102
103                // set type field to opening tag
104                buf[0] |= 6;
105            }
106            TagNumber::ContextSpecificClosing(num) => {
107                let num = *num;
108                buf[0] |= 0b1000; // set class to context specific
109
110                if num <= 14 {
111                    buf[0] |= num << 4;
112                } else {
113                    buf[0] |= 0xF0;
114                    buf[1] = num;
115                    len += 1;
116                }
117
118                // set type field to closing tag
119                buf[0] |= 7;
120            }
121            TagNumber::ContextSpecific(num) => {
122                let num = *num;
123                buf[0] |= 0b1000; // set class to context specific
124
125                if num <= 14 {
126                    buf[0] |= num << 4;
127                } else {
128                    buf[0] |= 0xF0;
129                    buf[1] = num;
130                    len += 1;
131                }
132            }
133        }
134
135        if self.value <= 4 {
136            buf[0] |= self.value as u8;
137        } else {
138            buf[0] |= 5;
139
140            if self.value <= 253 {
141                buf[len] = self.value as u8;
142                len += 1;
143            } else if self.value < u16::MAX as u32 {
144                buf[len] = self.value as u8;
145                len += 1;
146                let tmp = u16::to_be_bytes(self.value as u16);
147                buf[len..len + tmp.len()].copy_from_slice(&tmp);
148                len += tmp.len();
149            } else {
150                buf[len] = self.value as u8;
151                len += 1;
152                let tmp = u32::to_be_bytes(self.value);
153                buf[len..len + tmp.len()].copy_from_slice(&tmp);
154                len += tmp.len();
155            }
156        }
157
158        writer.extend_from_slice(&buf[..len]);
159    }
160
161    pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
162        let (number, byte0) = decode_tag_number(reader, buf)?;
163
164        let value = if is_extended_value(byte0) {
165            let byte = reader.read_byte(buf)?;
166            match byte {
167                // tagged as u32
168                255 => {
169                    let bytes = reader.read_bytes(buf)?;
170                    let value = u32::from_be_bytes(bytes);
171                    Self { number, value }
172                }
173                // tagged as u16
174                254 => {
175                    let bytes = reader.read_bytes(buf)?;
176                    let value = u16::from_be_bytes(bytes) as u32;
177                    Self { number, value }
178                }
179                // no tag
180                _ => Self {
181                    number,
182                    value: byte.into(),
183                },
184            }
185        } else if is_opening_tag(byte0) | is_closing_tag(byte0) {
186            Self { number, value: 0 }
187        } else {
188            let value = (byte0 & 0x07).into();
189            Self { number, value }
190        };
191
192        Ok(value)
193    }
194
195    pub fn decode_expected(
196        reader: &mut Reader,
197        buf: &[u8],
198        expected: TagNumber,
199        context: &'static str,
200    ) -> Result<Self, Error> {
201        let tag = Self::decode(reader, buf)?;
202        if tag.number == expected {
203            Ok(tag)
204        } else {
205            Err(Error::ExpectedTag(ExpectedTag {
206                context,
207                expected,
208                actual: tag.number,
209            }))
210        }
211    }
212
213    pub fn expect_value(&self, context: &'static str, value: u32) -> Result<(), Error> {
214        if self.value != value {
215            Err(Error::TagValueInvalid((context, self.clone(), value)))
216        } else {
217            Ok(())
218        }
219    }
220
221    pub fn expect_number(&self, context: &'static str, tag_number: TagNumber) -> Result<(), Error> {
222        if self.number == tag_number {
223            Ok(())
224        } else {
225            Err(Error::ExpectedTag(ExpectedTag {
226                actual: self.number.clone(),
227                expected: tag_number,
228                context,
229            }))
230        }
231    }
232}
233
234// returns tag_number and byte0 because we need to reuse byte0 elsewhere
235fn decode_tag_number(reader: &mut Reader, buf: &[u8]) -> Result<(TagNumber, u8), Error> {
236    let byte0 = reader.read_byte(buf)?;
237
238    let value = if is_context_specific(byte0) {
239        // context specific tag num
240        if is_extended_tag_number(byte0) {
241            let num = reader.read_byte(buf)?;
242            (TagNumber::ContextSpecific(num), byte0)
243        } else {
244            let num = byte0 >> 4;
245            if is_opening_tag(byte0) {
246                (TagNumber::ContextSpecificOpening(num), 0)
247            } else if is_closing_tag(byte0) {
248                (TagNumber::ContextSpecificClosing(num), 0)
249            } else {
250                (TagNumber::ContextSpecific(num), byte0)
251            }
252        }
253    } else {
254        // application tag num
255        let num = (byte0 >> 4).into();
256        (TagNumber::Application(num), byte0)
257    };
258
259    Ok(value)
260}
261
262fn is_extended_tag_number(byte0: u8) -> bool {
263    byte0 & 0xF0 == 0xF0
264}
265
266fn is_extended_value(byte0: u8) -> bool {
267    byte0 & 0x07 == 0x05
268}
269
270fn is_context_specific(byte0: u8) -> bool {
271    byte0 & 0x08 == 0x08
272}
273
274fn is_opening_tag(byte0: u8) -> bool {
275    byte0 & 0x07 == 0x06
276}
277
278fn is_closing_tag(byte0: u8) -> bool {
279    byte0 & 0x07 == 0x07
280}