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