1#![no_std]
2
3use bitfield_struct::bitfield;
4use cangen_macro::generate_all_messages;
5use embedded_can::{ExtendedId, Frame, Id, StandardId};
6
7mod sealed {
8 pub trait Sealed {}
9 impl Sealed for u8 {}
10 impl Sealed for u16 {}
11 impl Sealed for u32 {}
12 impl Sealed for u64 {}
13}
14
15pub trait CanRepr: sealed::Sealed + Copy {
16 type Bytes: AsRef<[u8]>;
17 fn to_le_bytes(self) -> Self::Bytes;
18}
19
20impl CanRepr for u8 {
21 type Bytes = [u8; 1];
22 fn to_le_bytes(self) -> Self::Bytes {
23 u8::to_le_bytes(self)
24 }
25}
26impl CanRepr for u16 {
27 type Bytes = [u8; 2];
28 fn to_le_bytes(self) -> Self::Bytes {
29 u16::to_le_bytes(self)
30 }
31}
32impl CanRepr for u32 {
33 type Bytes = [u8; 4];
34 fn to_le_bytes(self) -> Self::Bytes {
35 u32::to_le_bytes(self)
36 }
37}
38impl CanRepr for u64 {
39 type Bytes = [u8; 8];
40 fn to_le_bytes(self) -> Self::Bytes {
41 u64::to_le_bytes(self)
42 }
43}
44
45pub trait ToCanFrame: Sized + Into<Self::Repr> {
48 type Repr: CanRepr;
49
50 const ID: Id;
51 const LEN: usize;
52
53 #[doc(hidden)]
54 const CHECK_BITS_FIT: () = assert!(
56 Self::LEN <= core::mem::size_of::<Self::Repr>(),
57 "BITS exceeds the backing integer's width"
58 );
59
60 #[doc(hidden)]
61 const CHECK_LEN: () = assert!(
63 Self::LEN <= 8 && core::mem::size_of::<Self::Repr>() <= 8,
64 "BITS exceeds the backing integer's width"
65 );
66
67 fn to_can_frame<F: Frame>(self) -> F {
68 let bytes = self.into().to_le_bytes();
69 unsafe { F::new(Self::ID, &bytes.as_ref()[..Self::LEN]).unwrap_unchecked() }
72 }
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub struct OutOfRange {
82 pub field: &'static str,
84}
85
86pub mod conv {
101 macro_rules! scaled {
102 ($u:ty, $i:ty, $w:literal,
103 $div_from:ident, $div_into:ident, $mul_from:ident, $mul_into:ident,
104 $sdiv_from:ident, $sdiv_into:ident, $smul_from:ident, $smul_into:ident) => {
105 pub const fn $div_from<const B: u32, const ARG: u32>(bits: $u) -> f32 {
107 bits as f32 / ARG as f32
108 }
109 pub const fn $div_into<const B: u32, const ARG: u32>(v: f32) -> $u {
113 let hi = (<$u>::MAX >> ($w - B)) as f32;
114 let raw = v * ARG as f32;
115 (if raw < 0.0 {
116 0.0
117 } else if raw > hi {
118 hi
119 } else {
120 raw
121 }) as $u
122 }
123 pub const fn $mul_from<const B: u32, const ARG: u32>(bits: $u) -> f32 {
125 bits as f32 * ARG as f32
126 }
127 pub const fn $mul_into<const B: u32, const ARG: u32>(v: f32) -> $u {
129 let hi = (<$u>::MAX >> ($w - B)) as f32;
130 let raw = v / ARG as f32;
131 (if raw < 0.0 {
132 0.0
133 } else if raw > hi {
134 hi
135 } else {
136 raw
137 }) as $u
138 }
139 pub const fn $sdiv_from<const B: u32, const ARG: u32>(bits: $u) -> f32 {
141 let sh = $w - B;
142 let s = ((bits << sh) as $i) >> sh;
143 s as f32 / ARG as f32
144 }
145 pub const fn $sdiv_into<const B: u32, const ARG: u32>(v: f32) -> $u {
148 let half = 1i128 << (B - 1);
149 let hi = (half - 1) as f32;
150 let lo = -(half as f32);
151 let raw = v * ARG as f32;
152 let raw = if raw < lo {
153 lo
154 } else if raw > hi {
155 hi
156 } else {
157 raw
158 };
159 let mask = <$u>::MAX >> ($w - B);
160 ((raw as $i) as $u) & mask
161 }
162 pub const fn $smul_from<const B: u32, const ARG: u32>(bits: $u) -> f32 {
164 let sh = $w - B;
165 let s = ((bits << sh) as $i) >> sh;
166 s as f32 * ARG as f32
167 }
168 pub const fn $smul_into<const B: u32, const ARG: u32>(v: f32) -> $u {
170 let half = 1i128 << (B - 1);
171 let hi = (half - 1) as f32;
172 let lo = -(half as f32);
173 let raw = v / ARG as f32;
174 let raw = if raw < lo {
175 lo
176 } else if raw > hi {
177 hi
178 } else {
179 raw
180 };
181 let mask = <$u>::MAX >> ($w - B);
182 ((raw as $i) as $u) & mask
183 }
184 };
185 }
186
187 scaled!(
188 u8,
189 i8,
190 8u32,
191 div_from_u8,
192 div_into_u8,
193 mul_from_u8,
194 mul_into_u8,
195 sdiv_from_u8,
196 sdiv_into_u8,
197 smul_from_u8,
198 smul_into_u8
199 );
200 scaled!(
201 u16,
202 i16,
203 16u32,
204 div_from_u16,
205 div_into_u16,
206 mul_from_u16,
207 mul_into_u16,
208 sdiv_from_u16,
209 sdiv_into_u16,
210 smul_from_u16,
211 smul_into_u16
212 );
213 scaled!(
214 u32,
215 i32,
216 32u32,
217 div_from_u32,
218 div_into_u32,
219 mul_from_u32,
220 mul_into_u32,
221 sdiv_from_u32,
222 sdiv_into_u32,
223 smul_from_u32,
224 smul_into_u32
225 );
226 scaled!(
227 u64,
228 i64,
229 64u32,
230 div_from_u64,
231 div_into_u64,
232 mul_from_u64,
233 mul_into_u64,
234 sdiv_from_u64,
235 sdiv_into_u64,
236 smul_from_u64,
237 smul_into_u64
238 );
239}
240
241impl ToCanFrame for ExampleDoNotUse {
242 type Repr = u64;
243 const ID: Id = Id::Standard(StandardId::new(0x00).unwrap());
244 const LEN: usize = 6;
245}
246
247#[bitfield(u64)]
250struct ExampleDoNotUse {
251 #[bits(4, from = conv::div_from_u8::<4, 1000>, into = conv::div_into_u8::<4, 1000>)]
253 pub a: f32,
254 pub b: u16,
255 pub c: u16,
256 #[bits(12)]
257 _1: u16,
258 _2: u16,
259}
260
261generate_all_messages!();