mini_slcan_ng/
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
50defmt::bitflags! {
51    /// Status flags reported by an SLCAN device.
52    pub struct Status: u8 {
53        const RX_FIFO_FULL = 1 << 0;
54        const TX_FIFO_FULL = 1 << 1;
55        const ERROR_WARNING = 1 << 2;
56        const DATA_OVERRUN = 1 << 3;
57        //const UNUSED = 1 << 4;
58        const ERROR_PASSIVE = 1 << 5;
59        const ARBITRATION_LOST = 1 << 6;
60        const BUS_ERROR = 1 << 7;
61    }
62}
63
64/// 4-byte serial number of an SLCAN device.
65#[derive(Copy, Clone, Eq, PartialEq, Debug, Format)]
66pub struct SerialNumber([u8; 4]);
67
68impl SerialNumber {
69    /// Creates a new `SerialNumber` from 4 raw bytes.
70    ///
71    /// The bytes must be alphanumeric ASCII characters, or this will return `None`.
72    pub fn new(raw: [u8; 4]) -> Option<Self> {
73        if raw.iter().all(|b| b.is_ascii_alphanumeric()) {
74            Some(Self(raw))
75        } else {
76            None
77        }
78    }
79
80    pub const fn new_const(raw: [u8; 4]) -> Self {
81        let valid = raw[0].is_ascii_alphanumeric()
82            && raw[1].is_ascii_alphanumeric()
83            && raw[2].is_ascii_alphanumeric()
84            && raw[3].is_ascii_alphanumeric();
85
86        if !valid {
87            let serial_number_contain_non_alphanumeric_characters = ();
88
89            #[allow(unconditional_panic)]
90            #[allow(clippy::out_of_bounds_indexing)]
91            #[allow(clippy::no_effect)]
92            [serial_number_contain_non_alphanumeric_characters][1];
93        }
94
95        Self(raw)
96    }
97}
98
99#[derive(Eq, PartialEq, Copy, Clone, Debug, Default)]
100pub struct CanFrame {
101    data: [u8; Self::MAX_LENGTH],
102    len: u8,
103}
104
105impl CanFrame {
106    pub const MAX_LENGTH: usize = 8;
107
108    #[inline]
109    pub const fn new() -> Self {
110        Self {
111            data: [0; Self::MAX_LENGTH],
112            len: 0,
113        }
114    }
115
116    #[inline]
117    pub fn len(&self) -> usize {
118        self.len.into()
119    }
120
121    #[inline]
122    pub fn is_empty(&self) -> bool {
123        self.len() == 0
124    }
125
126    #[inline]
127    pub fn data(&self) -> &[u8] {
128        &self.data[..usize::from(self.len)]
129    }
130
131    #[inline]
132    pub fn data_mut(&mut self) -> &mut [u8] {
133        &mut self.data[..usize::from(self.len)]
134    }
135
136    /// Appends a byte to this CAN frame.
137    ///
138    /// Returns an error when the frame is already full.
139    pub fn push(&mut self, byte: u8) -> Result<(), Error> {
140        if self.len() == Self::MAX_LENGTH {
141            Err(Error::eof())
142        } else {
143            self.data[self.len()] = byte;
144            self.len += 1;
145            Ok(())
146        }
147    }
148}
149
150impl Deref for CanFrame {
151    type Target = [u8];
152
153    fn deref(&self) -> &[u8] {
154        self.data()
155    }
156}
157
158impl DerefMut for CanFrame {
159    fn deref_mut(&mut self) -> &mut [u8] {
160        self.data_mut()
161    }
162}
163
164impl Format for CanFrame {
165    fn format(&self, fmt: defmt::Formatter<'_>) {
166        self.data().format(fmt)
167    }
168}
169
170macro_rules! impl_from {
171    ( $($len:literal),+ ) => {
172        $(
173            impl From<[u8; $len]> for CanFrame {
174                fn from(arr: [u8; $len]) -> Self {
175                    let mut data = [0; Self::MAX_LENGTH];
176                    data[..$len].copy_from_slice(&arr);
177                    Self {
178                        data,
179                        len: $len,
180                    }
181                }
182            }
183        )+
184    };
185}
186
187impl_from!(0, 1, 2, 3, 4, 5, 6, 7, 8);