mini_slcan/
lib.rs

1//! A lightweight, `#![no_std]` implementation of the Serial Line CAN protocol.
2
3#![doc(html_root_url = "https://docs.rs/mini-slcan/0.1.1")]
4// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default
5#![doc(test(attr(deny(unused_imports, unused_must_use))))]
6#![warn(missing_debug_implementations, rust_2018_idioms)]
7#![cfg_attr(not(test), no_std)]
8
9mod error;
10mod identifier;
11pub mod read;
12mod readme;
13pub mod write;
14
15pub use self::error::{Error, ErrorKind};
16pub use self::identifier::{ExtIdentifier, Identifier};
17
18use core::ops::{Deref, DerefMut};
19use defmt::Format;
20
21#[derive(Copy, Clone, Eq, PartialEq, Debug, Format)]
22pub enum Bitrate {
23    _10kbit,
24    _20kbit,
25    _50kbit,
26    _100kbit,
27    _125kbit,
28    _250kbit,
29    _500kbit,
30    _800kbit,
31    _1mbit,
32}
33
34impl Bitrate {
35    pub fn kbps(&self) -> u16 {
36        match self {
37            Bitrate::_10kbit => 10,
38            Bitrate::_20kbit => 20,
39            Bitrate::_50kbit => 50,
40            Bitrate::_100kbit => 100,
41            Bitrate::_125kbit => 125,
42            Bitrate::_250kbit => 250,
43            Bitrate::_500kbit => 500,
44            Bitrate::_800kbit => 800,
45            Bitrate::_1mbit => 1_000,
46        }
47    }
48}
49
50bitflags::bitflags! {
51    /// Status flags reported by an SLCAN device.
52    #[derive(Format)]
53    pub struct Status: u8 {
54        const RX_FIFO_FULL = 1 << 0;
55        const TX_FIFO_FULL = 1 << 1;
56        const ERROR_WARNING = 1 << 2;
57        const DATA_OVERRUN = 1 << 3;
58        //const UNUSED = 1 << 4;
59        const ERROR_PASSIVE = 1 << 5;
60        const ARBITRATION_LOST = 1 << 6;
61        const BUS_ERROR = 1 << 7;
62    }
63}
64
65/// 4-byte serial number of an SLCAN device.
66#[derive(Copy, Clone, Eq, PartialEq, Debug, Format)]
67pub struct SerialNumber([u8; 4]);
68
69impl SerialNumber {
70    /// Creates a new `SerialNumber` from 4 raw bytes.
71    ///
72    /// The bytes must be alphanumeric ASCII characters, or this will return `None`.
73    pub fn new(raw: [u8; 4]) -> Option<Self> {
74        if raw.iter().all(|b| b.is_ascii_alphanumeric()) {
75            Some(Self(raw))
76        } else {
77            None
78        }
79    }
80
81    pub const fn new_const(raw: [u8; 4]) -> Self {
82        let valid = raw[0].is_ascii_alphanumeric()
83            && raw[1].is_ascii_alphanumeric()
84            && raw[2].is_ascii_alphanumeric()
85            && raw[3].is_ascii_alphanumeric();
86
87        if !valid {
88            let serial_number_contain_non_alphanumeric_characters = ();
89
90            #[allow(unconditional_panic)]
91            [serial_number_contain_non_alphanumeric_characters][1];
92        }
93
94        Self(raw)
95    }
96}
97
98#[derive(Eq, PartialEq, Copy, Clone, Debug, Default)]
99pub struct CanFrame {
100    data: [u8; Self::MAX_LENGTH],
101    len: u8,
102}
103
104impl CanFrame {
105    pub const MAX_LENGTH: usize = 8;
106
107    #[inline]
108    pub const fn new() -> Self {
109        Self {
110            data: [0; Self::MAX_LENGTH],
111            len: 0,
112        }
113    }
114
115    #[inline]
116    pub fn len(&self) -> usize {
117        self.len.into()
118    }
119
120    #[inline]
121    pub fn data(&self) -> &[u8] {
122        &self.data[..usize::from(self.len)]
123    }
124
125    #[inline]
126    pub fn data_mut(&mut self) -> &mut [u8] {
127        &mut self.data[..usize::from(self.len)]
128    }
129
130    /// Appends a byte to this CAN frame.
131    ///
132    /// Returns an error when the frame is already full.
133    pub fn push(&mut self, byte: u8) -> Result<(), Error> {
134        if self.len() == Self::MAX_LENGTH {
135            Err(Error::eof())
136        } else {
137            self.data[self.len()] = byte;
138            self.len += 1;
139            Ok(())
140        }
141    }
142}
143
144impl Deref for CanFrame {
145    type Target = [u8];
146
147    fn deref(&self) -> &[u8] {
148        self.data()
149    }
150}
151
152impl DerefMut for CanFrame {
153    fn deref_mut(&mut self) -> &mut [u8] {
154        self.data_mut()
155    }
156}
157
158impl Format for CanFrame {
159    fn format(&self, fmt: &mut defmt::Formatter) {
160        self.data().format(fmt)
161    }
162}
163
164macro_rules! impl_from {
165    ( $($len:literal),+ ) => {
166        $(
167            impl From<[u8; $len]> for CanFrame {
168                fn from(arr: [u8; $len]) -> Self {
169                    let mut data = [0; Self::MAX_LENGTH];
170                    data[..$len].copy_from_slice(&arr);
171                    Self {
172                        data,
173                        len: $len,
174                    }
175                }
176            }
177        )+
178    };
179}
180
181impl_from!(0, 1, 2, 3, 4, 5, 6, 7, 8);