serial_can/
lib.rs

1//! A Rust Serial Line CAN (slcan) library. Useful for embedded systems.
2
3#![cfg_attr(not(test), no_std)]
4
5mod frame;
6
7use embedded_can::{ExtendedId, Frame as _, Id, StandardId};
8pub use frame::Frame;
9use nom::{
10    branch::alt,
11    bytes::complete::{tag, take},
12    character::complete::{digit1, one_of},
13    combinator::map,
14    error::{Error, ErrorKind},
15    sequence::tuple,
16    Err, IResult,
17};
18
19/// Bitrate options.
20#[derive(Debug, PartialEq, Eq, Copy, Clone)]
21#[repr(u8)]
22pub enum Bitrate {
23    Rate10kbit = 0,
24    Rate20kbit = 1,
25    Rate50kbit = 2,
26    Rate100kbit = 3,
27    Rate125kbit = 4,
28    Rate250kbit = 5,
29    Rate500kbit = 6,
30    Rate800kbit = 7,
31    Rate1000kbit = 8,
32}
33
34/// Setup port command.
35#[derive(Debug, PartialEq, Eq, Copy, Clone)]
36pub struct Setup {
37    pub bitrate: Bitrate,
38}
39
40impl Setup {
41    pub fn new(bitrate: Bitrate) -> Self {
42        Self { bitrate }
43    }
44
45    /// Try parsing a [`Setup`] command from a string.
46    pub fn try_parse(input: &str) -> IResult<&str, Self> {
47        let (input, (_, bitrate, _)) = tuple((tag("S"), digit1, tag("\r")))(input)?;
48
49        let bitrate = match bitrate {
50            "0" => Bitrate::Rate10kbit,
51            "1" => Bitrate::Rate20kbit,
52            "2" => Bitrate::Rate50kbit,
53            "3" => Bitrate::Rate100kbit,
54            "4" => Bitrate::Rate125kbit,
55            "5" => Bitrate::Rate250kbit,
56            "6" => Bitrate::Rate500kbit,
57            "7" => Bitrate::Rate800kbit,
58            "8" => Bitrate::Rate1000kbit,
59            _ => return Err(Err::Failure(Error::new(input, ErrorKind::Digit))),
60        };
61
62        Ok((input, Self { bitrate }))
63    }
64}
65
66impl core::fmt::Display for Setup {
67    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68        write!(f, "S{:}\r", self.bitrate as u8)
69    }
70}
71
72/// Open port command.
73#[derive(Debug, PartialEq, Eq, Copy, Clone)]
74pub struct Open {}
75
76impl Open {
77    pub fn new() -> Self {
78        Self {}
79    }
80
81    /// Try parsing an [`Open`] command from a string.
82    pub fn try_parse(input: &str) -> IResult<&str, Self> {
83        let (input, _) = tag("O\r")(input)?;
84
85        Ok((input, Self::new()))
86    }
87}
88
89impl core::fmt::Display for Open {
90    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
91        write!(f, "O\r")
92    }
93}
94
95/// Close port command.
96#[derive(Debug, PartialEq, Eq, Copy, Clone)]
97pub struct Close {}
98
99impl Close {
100    pub fn new() -> Self {
101        Self {}
102    }
103
104    /// Try parsing a [`Close`] command from a string.
105    pub fn try_parse(input: &str) -> IResult<&str, Self> {
106        let (input, _) = tag("C\r")(input)?;
107
108        Ok((input, Self::new()))
109    }
110}
111
112impl core::fmt::Display for Close {
113    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
114        write!(f, "C\r")
115    }
116}
117
118/// Transmit frame command.
119#[derive(Debug, PartialEq, Eq, Copy, Clone)]
120pub struct Transmit {
121    frame: Frame,
122}
123
124impl Transmit {
125    pub fn new(frame: &impl embedded_can::Frame) -> Self {
126        // Convert foreign frame to library frame.
127        let frame = if frame.is_remote_frame() {
128            Frame::new_remote(frame.id(), frame.dlc()).unwrap()
129        } else {
130            Frame::new(frame.id(), frame.data()).unwrap()
131        };
132
133        Self { frame }
134    }
135
136    /// Try parsing a [`Transmit`] command from a string.
137    pub fn try_parse(input: &str) -> IResult<&str, Self> {
138        let (input, kind) = one_of("tTrR")(input)?;
139        let (input, id) = match kind {
140            't' | 'r' => {
141                let (input, id_hex) = take(3_usize)(input)?;
142                let id = u16::from_str_radix(id_hex, 16)
143                    .map_err(|_| Err::Failure(Error::new(input, ErrorKind::HexDigit)))?;
144                (input, Id::Standard(StandardId::new(id).unwrap()))
145            }
146            'T' | 'R' => {
147                let (input, id_hex) = take(8_usize)(input)?;
148                let id = u32::from_str_radix(id_hex, 16)
149                    .map_err(|_| Err::Failure(Error::new(input, ErrorKind::HexDigit)))?;
150                (input, Id::Extended(ExtendedId::new(id).unwrap()))
151            }
152            _ => unreachable!(), // other cases are impossible due to `one_of`
153        };
154
155        let (input, dlc) = take(1_usize)(input)?;
156        let dlc = usize::from_str_radix(dlc, 16)
157            .map_err(|_| Err::Failure(Error::new(input, ErrorKind::HexDigit)))?;
158
159        let (input, data) = if dlc > 0 {
160            take(dlc * 2_usize)(input)?
161        } else {
162            (input, "")
163        };
164
165        let data = if data.is_empty() {
166            [0; 8]
167        } else {
168            let mut array = [0; 8];
169            for i in 0..dlc {
170                array[i] = u8::from_str_radix(&data[i * 2..i * 2 + 2], 16)
171                    .map_err(|_| Err::Failure(Error::new(input, ErrorKind::HexDigit)))?;
172            }
173            array
174        };
175
176        let frame = if kind == 't' || kind == 'T' {
177            Frame::new(id, &data[..dlc]).unwrap()
178        } else {
179            Frame::new_remote(id, dlc).unwrap()
180        };
181
182        let (input, _) = tag("\r")(input)?;
183
184        Ok((input, Self::new(&frame)))
185    }
186}
187
188impl core::fmt::Display for Transmit {
189    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
190        let cmd = match (self.frame.is_extended(), self.frame.is_remote_frame()) {
191            (false, false) => 't',
192            (true, false) => 'T',
193            (true, true) => 'R',
194            (false, true) => 'r',
195        };
196
197        match self.frame.id() {
198            Id::Standard(id) => write!(f, "{}{:03X}", cmd, id.as_raw())?,
199            Id::Extended(id) => write!(f, "{}{:08X}", cmd, id.as_raw())?,
200        }
201
202        write!(f, "{}", self.frame.dlc())?;
203
204        if self.frame.is_data_frame() {
205            for byte in self.frame.data() {
206                write!(f, "{:02X}", *byte)?;
207            }
208        }
209
210        write!(f, "\r")?;
211
212        Ok(())
213    }
214}
215
216/// Command variants.
217#[derive(Debug, PartialEq, Eq, Copy, Clone)]
218pub enum Command {
219    Setup(Setup),
220    Open(Open),
221    Close(Close),
222    Transmit(Transmit),
223}
224
225impl Command {
226    /// Try parsing a [`Command`] from a string.
227    pub fn try_parse(input: &str) -> IResult<&str, Self> {
228        alt((
229            map(Setup::try_parse, Command::Setup),
230            map(Open::try_parse, Command::Open),
231            map(Close::try_parse, Command::Close),
232            map(Transmit::try_parse, Command::Transmit),
233        ))(input)
234    }
235}
236
237impl core::fmt::Display for Command {
238    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239        match self {
240            Command::Setup(setup) => setup.fmt(f),
241            Command::Open(open) => open.fmt(f),
242            Command::Close(close) => close.fmt(f),
243            Command::Transmit(transmit) => transmit.fmt(f),
244        }
245    }
246}
247
248#[cfg(test)]
249mod tests {
250    use super::*;
251    use embedded_can::{ExtendedId, StandardId};
252
253    #[test]
254    fn format_setup() {
255        let setup = Setup::new(Bitrate::Rate10kbit);
256        assert_eq!(format!("{}", setup), "S0\r");
257    }
258
259    #[test]
260    fn parse_setup() {
261        assert_eq!(
262            Setup::try_parse("S0\r"),
263            Ok((
264                "",
265                Setup {
266                    bitrate: Bitrate::Rate10kbit
267                }
268            ))
269        );
270
271        assert!(Setup::try_parse("S9\r").is_err());
272        assert!(Setup::try_parse("SF\r").is_err());
273        assert!(Setup::try_parse("S \r").is_err());
274    }
275
276    #[test]
277    fn format_open() {
278        let open = Open::new();
279        assert_eq!(format!("{}", open), "O\r");
280    }
281
282    #[test]
283    fn parse_open() {
284        assert_eq!(Open::try_parse("O\r"), Ok(("", Open {})));
285
286        assert!(Close::try_parse("o\r").is_err());
287    }
288
289    #[test]
290    fn format_close() {
291        let close = Close::new();
292        assert_eq!(format!("{}", close), "C\r");
293    }
294
295    #[test]
296    fn parse_close() {
297        assert_eq!(Close::try_parse("C\r"), Ok(("", Close {})));
298
299        assert!(Close::try_parse("c\r").is_err());
300    }
301
302    #[test]
303    fn format_transmit() {
304        let frame = Frame::new(Id::Standard(StandardId::new(0x123).unwrap()), &[]).unwrap();
305        let transmit = Transmit::new(&frame);
306        assert_eq!(format!("{}", transmit), "t1230\r");
307
308        let frame = Frame::new(
309            Id::Standard(StandardId::new(0x456).unwrap()),
310            &[0x11, 0x22, 0x33],
311        )
312        .unwrap();
313        let transmit = Transmit::new(&frame);
314        assert_eq!(format!("{}", transmit), "t4563112233\r");
315
316        let frame = Frame::new(
317            Id::Extended(ExtendedId::new(0x12ABCDEF).unwrap()),
318            &[0xAA, 0x55],
319        )
320        .unwrap();
321        let transmit = Transmit::new(&frame);
322        assert_eq!(format!("{}", transmit), "T12ABCDEF2AA55\r");
323
324        let frame = Frame::new_remote(Id::Standard(StandardId::new(0x123).unwrap()), 0).unwrap();
325        let transmit = Transmit::new(&frame);
326        assert_eq!(format!("{}", transmit), "r1230\r");
327    }
328
329    #[test]
330    fn parse_transmit() {
331        assert_eq!(
332            Transmit::try_parse("t1230\r"),
333            Ok((
334                "",
335                Transmit::new(
336                    &Frame::new(Id::Standard(StandardId::new(0x123).unwrap()), &[]).unwrap()
337                )
338            ))
339        );
340
341        assert_eq!(
342            Transmit::try_parse("t4563112233\r"),
343            Ok((
344                "",
345                Transmit::new(
346                    &Frame::new(
347                        Id::Standard(StandardId::new(0x456).unwrap()),
348                        &[0x11, 0x22, 0x33]
349                    )
350                    .unwrap()
351                )
352            ))
353        );
354
355        assert_eq!(
356            Transmit::try_parse("T12ABCDEF2AA55\r"),
357            Ok((
358                "",
359                Transmit::new(
360                    &Frame::new(
361                        Id::Extended(ExtendedId::new(0x12ABCDEF).unwrap()),
362                        &[0xAA, 0x55]
363                    )
364                    .unwrap()
365                )
366            ))
367        );
368
369        assert_eq!(
370            Transmit::try_parse("r1230\r"),
371            Ok((
372                "",
373                Transmit::new(
374                    &Frame::new_remote(Id::Standard(StandardId::new(0x123).unwrap()), 0).unwrap()
375                )
376            ))
377        );
378    }
379
380    #[test]
381    fn format_command() {
382        let cmd = Command::Open(Open::new());
383        assert_eq!(format!("{}", cmd), "O\r");
384
385        let cmd = Command::Setup(Setup::new(Bitrate::Rate100kbit));
386        assert_eq!(format!("{}", cmd), "S3\r");
387    }
388
389    #[test]
390    fn parse_command() {
391        let cmd = Command::try_parse("O\r");
392        assert_eq!(cmd, Ok(("", Command::Open(Open::new()))));
393    }
394}