1#![doc(html_root_url = "https://docs.rs/mini-slcan/0.1.1")]
4#![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 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 ERROR_PASSIVE = 1 << 5;
59 const ARBITRATION_LOST = 1 << 6;
60 const BUS_ERROR = 1 << 7;
61 }
62}
63
64#[derive(Copy, Clone, Eq, PartialEq, Debug, Format)]
66pub struct SerialNumber([u8; 4]);
67
68impl SerialNumber {
69 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 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);