mini_slcan/
read.rs

1//! Decoding of SLCAN messages.
2
3#[cfg(test)]
4mod tests;
5
6use crate::{Bitrate, CanFrame, Error, ExtIdentifier, Identifier};
7use defmt::Format;
8
9/// A command sent from the host to the SLCAN device.
10#[derive(Debug, Eq, PartialEq, Format)]
11#[non_exhaustive]
12pub enum Command {
13    SetupWithBitrate {
14        bitrate: Bitrate,
15    },
16
17    Open,
18
19    Close,
20
21    TxStandard {
22        identifier: Identifier,
23        frame: CanFrame,
24    },
25
26    /// Transmit an extended CAN frame.
27    TxExt {
28        identifier: ExtIdentifier,
29        frame: CanFrame,
30    },
31
32    TxStandardRtr {
33        identifier: Identifier,
34        len: u8,
35    },
36
37    TxExtRtr {
38        identifier: ExtIdentifier,
39        len: u8,
40    },
41
42    ReadStatus,
43    ReadVersion,
44    ReadSerial,
45    SetRxTimestamp {
46        timestamp: bool,
47    },
48}
49
50impl Command {
51    pub const MAX_ENCODED_LEN: usize = 1 + 8 + 1 + 16 + 1; // Tiiiiiiiildddddddddddddddd\r
52
53    /// Decodes a command from an input string. The input must contain the terminating `CR`
54    /// character (ASCII 13).
55    pub fn decode(input: &[u8]) -> Result<Self, Error> {
56        let mut reader = Reader { input };
57
58        let op = reader.read_byte()?;
59        let cmd = match op {
60            b'S' => {
61                let bitrate = match reader.read_byte()? {
62                    b'0' => Bitrate::_10kbit,
63                    b'1' => Bitrate::_20kbit,
64                    b'2' => Bitrate::_50kbit,
65                    b'3' => Bitrate::_100kbit,
66                    b'4' => Bitrate::_125kbit,
67                    b'5' => Bitrate::_250kbit,
68                    b'6' => Bitrate::_500kbit,
69                    b'7' => Bitrate::_800kbit,
70                    b'8' => Bitrate::_1mbit,
71                    _ => return Err(Error::decode()),
72                };
73
74                Command::SetupWithBitrate { bitrate }
75            }
76            b'O' => Command::Open,
77            b'C' => Command::Close,
78            b't' => {
79                let identifier = reader.read_hex_identifier()?;
80                let len = reader.read_hex_u4()?;
81                if len > 8 {
82                    return Err(Error::decode());
83                }
84                let frame = reader.read_frame(len)?;
85
86                Command::TxStandard { identifier, frame }
87            }
88            b'T' => {
89                let identifier = reader.read_hex_ext_identifier()?;
90                let len = reader.read_hex_u4()?;
91                if len > 8 {
92                    return Err(Error::decode());
93                }
94                let frame = reader.read_frame(len)?;
95
96                Command::TxExt { identifier, frame }
97            }
98            b'r' => {
99                let identifier = reader.read_hex_identifier()?;
100                let len = reader.read_hex_u4()?;
101                if len > 8 {
102                    return Err(Error::decode());
103                }
104
105                Command::TxStandardRtr { identifier, len }
106            }
107            b'R' => {
108                let identifier = reader.read_hex_ext_identifier()?;
109                let len = reader.read_hex_u4()?;
110                if len > 8 {
111                    return Err(Error::decode());
112                }
113
114                Command::TxExtRtr { identifier, len }
115            }
116            b'F' => Command::ReadStatus,
117            b'V' => Command::ReadVersion,
118            b'N' => Command::ReadSerial,
119            b'Z' => {
120                let timestamp = match reader.read_byte()? {
121                    b'0' => false,
122                    b'1' => true,
123                    _ => return Err(Error::decode()),
124                };
125
126                Command::SetRxTimestamp { timestamp }
127            }
128            _ => return Err(Error::decode()),
129        };
130
131        if reader.read_byte()? != b'\r' {
132            return Err(Error::decode());
133        }
134
135        // Reject trailing undecoded data.
136        if !reader.input.is_empty() {
137            return Err(Error::decode());
138        }
139
140        Ok(cmd)
141    }
142}
143
144/// A byte buffer that yields decoded `Command`s.
145///
146/// This is meant to be used by apps that receive bytewise data and want to decode `Command`s from
147/// that.
148#[derive(Default, Debug)]
149pub struct CommandBuf {
150    /// Invariant: `bytes[..used]` Never contains `\r`.
151    bytes: [u8; Command::MAX_ENCODED_LEN],
152    used: u8,
153}
154
155impl CommandBuf {
156    /// Creates a new, empty `CommandBuf`.
157    pub const fn new() -> Self {
158        Self {
159            bytes: [0; Command::MAX_ENCODED_LEN],
160            used: 0,
161        }
162    }
163
164    /// Returns the currently unused part of the buffer.
165    ///
166    /// The caller can copy new input bytes into the returned slice, and call `advance_by` to mark
167    /// them as part of the `CommandBuf`.
168    pub fn tail_mut(&mut self) -> &mut [u8] {
169        &mut self.bytes[usize::from(self.used)..]
170    }
171
172    fn is_full(&self) -> bool {
173        usize::from(self.used) == Command::MAX_ENCODED_LEN
174    }
175
176    fn find_cr(&self, start: usize) -> Option<usize> {
177        self.bytes[start..usize::from(self.used)]
178            .iter()
179            .position(|b| *b == b'\r')
180            .map(|pos| pos + start)
181    }
182
183    /// Marks `len` more bytes from the buffer's tail as consumed, and returns an iterator over all
184    /// `Command`s in the buffer.
185    ///
186    /// When dropped, the returned iterator will remove the decoded bytes from the `CommandBuf`.
187    pub fn advance_by(&mut self, amount: u8) -> impl Iterator<Item = Result<Command, Error>> + '_ {
188        self.used += amount;
189        assert!(usize::from(self.used) <= Command::MAX_ENCODED_LEN);
190
191        CommandIter { buf: self, pos: 0 }
192    }
193}
194
195struct CommandIter<'a> {
196    buf: &'a mut CommandBuf,
197    pos: u8,
198}
199
200impl Iterator for CommandIter<'_> {
201    type Item = Result<Command, Error>;
202
203    fn next(&mut self) -> Option<Self::Item> {
204        let pos = usize::from(self.pos);
205        let end = match self.buf.find_cr(pos) {
206            Some(pos) => pos,
207            None if pos == 0 && self.buf.is_full() => {
208                // There is no `\r` in the entire buffer to terminate the received command. That
209                // means that the input is invalid, since the buffer can hold the longest command,
210                // including the trailing `\r`.
211                // Yield an error, and mark the whole buffer as consumed to make space for new data.
212                self.pos = Command::MAX_ENCODED_LEN as u8;
213                return Some(Err(Error::decode()));
214            }
215            None => return None,
216        };
217
218        let cmd = &self.buf.bytes[pos..end + 1];
219        self.pos += cmd.len() as u8;
220
221        Some(Command::decode(cmd))
222    }
223}
224
225impl Drop for CommandIter<'_> {
226    fn drop(&mut self) {
227        let decoded_end = usize::from(self.pos);
228        self.buf.bytes.copy_within(decoded_end.., 0);
229        self.buf.used -= decoded_end as u8;
230    }
231}
232
233#[derive(Eq, PartialEq)]
234struct Reader<'a> {
235    input: &'a [u8],
236}
237
238impl<'a> Reader<'a> {
239    fn read_byte(&mut self) -> Result<u8, Error> {
240        match self.input {
241            [] => Err(Error::eof()),
242            [b, rest @ ..] => {
243                self.input = rest;
244                Ok(*b)
245            }
246        }
247    }
248
249    fn read_hex_digits(&mut self, digits: u8) -> Result<u32, Error> {
250        let mut val = 0;
251
252        for _ in 0..digits {
253            val <<= 4;
254            val |= unhex(self.read_byte()?)? as u32;
255        }
256
257        Ok(val)
258    }
259
260    fn read_hex_u4(&mut self) -> Result<u8, Error> {
261        Ok(self.read_hex_digits(1)? as u8)
262    }
263
264    fn read_hex_u8(&mut self) -> Result<u8, Error> {
265        Ok(self.read_hex_digits(2)? as u8)
266    }
267
268    fn read_hex_identifier(&mut self) -> Result<Identifier, Error> {
269        let raw = self.read_hex_digits(3)? as u16;
270        Identifier::from_raw(raw).ok_or(Error::decode())
271    }
272
273    fn read_hex_ext_identifier(&mut self) -> Result<ExtIdentifier, Error> {
274        let raw = self.read_hex_digits(8)?;
275        ExtIdentifier::from_raw(raw).ok_or(Error::decode())
276    }
277
278    fn read_frame(&mut self, len: u8) -> Result<CanFrame, Error> {
279        assert!(len <= 8);
280
281        let mut frame = CanFrame::new();
282
283        for _ in 0..len {
284            let byte = self.read_hex_u8()?;
285
286            // Can never fail, because we limit `len` to 8 or less.
287            frame.push(byte).unwrap();
288        }
289
290        Ok(frame)
291    }
292}
293
294fn unhex(digit: u8) -> Result<u8, Error> {
295    match digit {
296        b'0'..=b'9' => Ok(digit - b'0'),
297        b'A'..=b'F' => Ok(digit - b'A' + 10),
298        _ => Err(Error::decode()),
299    }
300}