Skip to main content

bacnet_mstp_codec/
error.rs

1//! Typed failures emitted by the frame codec.
2
3use core::fmt;
4
5use crate::SinkFull;
6
7/// A frame could not be encoded or decoded.
8///
9/// Encode and decode share the variants that mean the same thing in both
10/// directions; the caller knows which one it asked for. Later releases may
11/// add variants, so a match outside this crate needs a wildcard arm.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13#[non_exhaustive]
14pub enum FrameError {
15    /// Decode: the input ended before the header was complete.
16    TooShort {
17        /// Octets needed for the preamble and header.
18        needed: usize,
19        /// Octets supplied.
20        available: usize,
21    },
22    /// Decode: the input does not start with the preamble `0x55, 0xFF`.
23    InvalidPreamble {
24        /// First input octet.
25        first: u8,
26        /// Second input octet.
27        second: u8,
28    },
29    /// Decode: the header CRC does not match.
30    HeaderCrcMismatch,
31    /// A reserved COBS-encoded frame type, 34-127, which the codec doesn't
32    /// implement. The header passed every other check first, source and
33    /// Length included, so it is a good header (Clause 9.5.8).
34    UnsupportedCobsFrame {
35        /// The frame type octet.
36        raw_type: u8,
37    },
38    /// The source address is 255, the broadcast address, which no station may
39    /// send from (Clause 9.3).
40    BroadcastSource,
41    /// A COBS-encoded frame's Length is outside
42    /// [`MIN_COBS_LENGTH`](crate::MIN_COBS_LENGTH)..=[`MAX_COBS_LENGTH`](crate::MAX_COBS_LENGTH),
43    /// so the header is bad (Clause 9.5.8). On encode, the data is empty or
44    /// encodes to more than the largest Length allows.
45    InvalidCobsLength {
46        /// The Length declared by the header (decode), or the one the data
47        /// would need (encode).
48        length: usize,
49    },
50    /// Decode with [`decode_frame`](crate::decode_frame): a good extended
51    /// frame header, whose COBS-encoded data can't be borrowed from the
52    /// input. It says only "decode this in place": nothing after the header
53    /// was checked, and
54    /// [`decode_frame_in_place`](crate::decode_frame_in_place) gives the
55    /// verdict on the rest of the frame.
56    ExtendedFrame {
57        /// The frame type octet, 32 or 33.
58        raw_type: u8,
59    },
60    /// The data field of a standard (not COBS-encoded) frame is longer than
61    /// one allows.
62    Oversize {
63        /// Data length declared by the header (decode) or supplied (encode).
64        length: usize,
65        /// Largest standard data field, [`crate::MAX_STANDARD_MPDU_DATA`].
66        maximum: usize,
67    },
68    /// Encode: data was supplied for a frame type that never carries any (see
69    /// [`crate::FrameType::allows_data`]).
70    UnexpectedData {
71        /// The frame type octet.
72        raw_type: u8,
73        /// Length of the supplied data.
74        length: usize,
75    },
76    /// Encode: a proprietary frame (type 128-255) has fewer than the two data
77    /// octets its vendor identifier takes (Clause 9.3.11).
78    MissingVendorId {
79        /// The frame type octet.
80        raw_type: u8,
81        /// Length of the supplied data.
82        length: usize,
83    },
84    /// Decode: the input ended before the frame did: before a standard
85    /// frame's data and data CRC, or an extended frame's encoded fields, were
86    /// complete.
87    Truncated {
88        /// The Length declared by the header.
89        length: usize,
90        /// Octets supplied after the header.
91        available: usize,
92    },
93    /// Decode: the frame's data failed its check. For a standard frame the
94    /// data CRC doesn't match. For an extended frame the CRC-32K doesn't, or
95    /// a code octet in either encoded field is zero or runs past the field's
96    /// end, which Clause 9.10.3 treats as a bad CRC too.
97    DataCrcMismatch {
98        /// The Length declared by the header.
99        length: usize,
100    },
101    /// Stream decode: a candidate frame is longer than the decoder's whole
102    /// storage, so it can never be buffered. See [`crate::StreamDecoder`].
103    FrameTooLong {
104        /// Octets the candidate needs, from its preamble to its last octet.
105        needed: usize,
106        /// The decoder's storage capacity.
107        capacity: usize,
108    },
109    /// There was no room for the octets. It comes from three places:
110    ///
111    /// - Encode, before writing: the sink reports a capacity, and the frame
112    ///   doesn't fit it. `needed` is the frame's wire length, `available`
113    ///   the sink's remaining capacity, and nothing was written.
114    /// - Encode, part way through: one of the sink's own writes failed with
115    ///   a [`SinkFull`], as a growable sink's can, since it is never checked
116    ///   up front. `needed` and `available` are that write's, as the sink
117    ///   reported them, and the octets of the earlier writes stay in the
118    ///   sink (see [`FrameSink`](crate::FrameSink)).
119    /// - Stream decode: a pushed slice is longer than the decoder's free
120    ///   storage. `needed` is the slice less the octets of a frame the
121    ///   decoder is skipping, `available` the decoder's capacity less what
122    ///   it already buffers, and none of the slice was taken.
123    BufferExhausted {
124        /// Octets the refused call or write had to store.
125        needed: usize,
126        /// Room there was for them.
127        available: usize,
128    },
129}
130
131impl fmt::Display for FrameError {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        match self {
134            Self::TooShort { needed, available } => {
135                write!(f, "frame too short: need {needed}, have {available}")
136            }
137            Self::InvalidPreamble { first, second } => {
138                write!(f, "invalid preamble {first:#04X} {second:#04X}")
139            }
140            Self::HeaderCrcMismatch => f.write_str("header CRC mismatch"),
141            Self::UnsupportedCobsFrame { raw_type } => {
142                write!(f, "unsupported COBS frame type {raw_type}")
143            }
144            Self::BroadcastSource => f.write_str("source address is broadcast (0xFF)"),
145            Self::InvalidCobsLength { length } => {
146                write!(f, "COBS frame length {length} is out of range")
147            }
148            Self::ExtendedFrame { raw_type } => {
149                write!(f, "extended frame type {raw_type} must be decoded in place")
150            }
151            Self::Oversize { length, maximum } => {
152                write!(f, "data length {length} exceeds maximum {maximum}")
153            }
154            Self::UnexpectedData { raw_type, length } => {
155                write!(
156                    f,
157                    "frame type {raw_type} carries no data, got {length} octets"
158                )
159            }
160            Self::MissingVendorId { raw_type, length } => write!(
161                f,
162                "proprietary frame type {raw_type} needs a 2-octet vendor ID, got {length} octets"
163            ),
164            Self::Truncated { length, available } => {
165                write!(f, "truncated frame length {length}, available {available}")
166            }
167            Self::DataCrcMismatch { .. } => f.write_str("data CRC mismatch"),
168            Self::FrameTooLong { needed, capacity } => write!(
169                f,
170                "frame needs {needed} octets, decoder storage holds {capacity}"
171            ),
172            Self::BufferExhausted { needed, available } => {
173                write!(f, "buffer exhausted: need {needed}, have {available}")
174            }
175        }
176    }
177}
178
179impl core::error::Error for FrameError {}
180
181impl From<SinkFull> for FrameError {
182    fn from(full: SinkFull) -> Self {
183        Self::BufferExhausted {
184            needed: full.needed,
185            available: full.available,
186        }
187    }
188}