1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5#[cfg_attr(feature = "defmt-1", derive(defmt::Format))]
6pub enum PduFormat {
7 Pdu1(u8),
9 Pdu2(u8),
11}
12
13impl From<u8> for PduFormat {
14 fn from(value: u8) -> Self {
15 match value {
16 ..=239 => PduFormat::Pdu1(value),
17 240.. => PduFormat::Pdu2(value),
18 }
19 }
20}
21
22impl From<&Pgn> for PduFormat {
23 fn from(pgn: &Pgn) -> Self {
24 let byte = u32::from(pgn) >> 8 & 0xff;
25 Self::from(byte as u8)
26 }
27}
28
29impl From<Pgn> for PduFormat {
30 fn from(pgn: Pgn) -> Self {
31 Self::from(&pgn)
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37#[cfg_attr(feature = "defmt-1", derive(defmt::Format))]
38pub struct Id(u32);
39
40impl Id {
41 pub fn new(raw: u32) -> Self {
45 Self(raw & embedded_can::ExtendedId::MAX.as_raw())
46 }
47
48 pub fn builder() -> IdBuilder {
49 IdBuilder::new()
50 }
51
52 pub fn as_raw(&self) -> u32 {
54 self.0
55 }
56
57 pub fn priority(&self) -> u8 {
59 (self.0 >> 26) as u8
60 }
61
62 pub fn dp(&self) -> bool {
64 (self.0 >> 24 & 1) != 0
65 }
66
67 pub fn edp(&self) -> bool {
69 (self.0 >> 25 & 1) != 0
70 }
71
72 pub fn pgn(&self) -> Pgn {
74 let raw = self.0 >> 8;
75 let raw = match self.pf() {
76 PduFormat::Pdu1(_) => raw & 0xFF00,
77 PduFormat::Pdu2(_) => raw & 0xFFFF,
78 };
79 Pgn::from(raw)
80 }
81
82 pub fn pf(&self) -> PduFormat {
84 let format = ((self.0 >> 16) & 0xFF) as u8;
85 PduFormat::from(format)
86 }
87
88 pub fn ps(&self) -> u8 {
90 ((self.0 >> 8) & 0xff) as u8
91 }
92
93 pub fn da(&self) -> Option<u8> {
95 if self.ps() <= 239 {
96 Some(self.ps())
97 } else {
98 None
99 }
100 }
101
102 pub fn ge(&self) -> Option<u8> {
104 if self.ps() >= 240 {
105 Some(self.ps())
106 } else {
107 None
108 }
109 }
110
111 pub fn sa(&self) -> u8 {
113 (self.0 & 0xff) as u8
114 }
115}
116
117impl From<embedded_can::ExtendedId> for Id {
118 fn from(id: embedded_can::ExtendedId) -> Self {
119 Self(id.as_raw())
120 }
121}
122
123#[allow(clippy::unwrap_used)]
124impl From<Id> for embedded_can::ExtendedId {
125 fn from(id: Id) -> Self {
126 embedded_can::ExtendedId::new(id.0).unwrap()
127 }
128}
129
130impl From<Id> for embedded_can::Id {
131 fn from(id: Id) -> Self {
132 embedded_can::Id::Extended(id.into())
133 }
134}
135
136#[derive(Debug, Clone, Copy)]
137#[cfg_attr(feature = "defmt-1", derive(defmt::Format))]
138pub struct IdBuilder {
139 priority: Option<u8>,
140 pgn: Option<Pgn>,
141 sa: Option<u8>,
142 da: Option<u8>,
143}
144
145impl IdBuilder {
146 pub fn new() -> Self {
151 Self {
152 priority: None,
153 pgn: None,
154 sa: None,
155 da: None,
156 }
157 }
158
159 pub fn priority(mut self, p: u8) -> Self {
163 assert!(p <= 7);
164 self.priority = Some(p);
165 self
166 }
167
168 pub fn pgn(mut self, pgn: Pgn) -> Self {
172 self.pgn = Some(pgn);
173 self
174 }
175
176 pub fn sa(mut self, sa: u8) -> Self {
178 self.sa = Some(sa);
179 self
180 }
181
182 pub fn da(mut self, da: u8) -> Self {
186 self.da = Some(da);
187 self
188 }
189
190 pub fn build(self) -> Option<Id> {
191 let mut id = ((self.priority.unwrap_or(6) as u32) << 26)
192 | (u32::from(self.pgn?) << 8)
193 | (self.sa? as u32);
194
195 if let PduFormat::Pdu1(_) = Id::new(id).pf() {
196 id |= (self.da? as u32) << 8;
197 }
198
199 Some(Id(id))
200 }
201}
202
203impl Default for IdBuilder {
204 fn default() -> Self {
205 Self::new()
206 }
207}
208
209#[derive(Debug, Clone, Copy, PartialEq, Eq)]
211#[cfg_attr(feature = "defmt-1", derive(defmt::Format))]
212pub enum Pgn {
213 Request2,
215 Transfer,
217 BootLoadData,
219 BinaryDataTransfer,
221 MemoryAccessResponse,
223 MemoryAccessRequest,
225 Request,
227 Acknowledgement,
229 TransportProtocolDataTransfer,
231 TransportProtocolConnectionManagement,
233 ProprietaryA,
235 ProprietaryA2,
237 ProprietaryB(u8),
239 ProprietaryB2(u8),
241 Other(u32),
243}
244
245impl Pgn {
246 pub fn pf(&self) -> PduFormat {
247 PduFormat::from(*self)
248 }
249}
250
251impl From<u32> for Pgn {
252 fn from(value: u32) -> Self {
253 match value {
254 51456 => Self::Request2,
255 51712 => Self::Transfer,
256 54784 => Self::BootLoadData,
257 55040 => Self::BinaryDataTransfer,
258 55296 => Self::MemoryAccessResponse,
259 55552 => Self::MemoryAccessRequest,
260 59904 => Self::Request,
261 59392 => Self::Acknowledgement,
262 60160 => Self::TransportProtocolDataTransfer,
263 60416 => Self::TransportProtocolConnectionManagement,
264 61184 => Self::ProprietaryA,
265 126720 => Self::ProprietaryA2,
266 65280..=65535 => Self::ProprietaryB((value & 0xFF) as u8),
267 130816..=131071 => Self::ProprietaryB2((value & 0xFF) as u8),
268 _ => Self::Other(value),
269 }
270 }
271}
272
273impl From<&Pgn> for u32 {
274 fn from(value: &Pgn) -> Self {
275 match value {
276 Pgn::Request2 => 51456,
277 Pgn::Transfer => 51712,
278 Pgn::BootLoadData => 54784,
279 Pgn::BinaryDataTransfer => 55040,
280 Pgn::MemoryAccessResponse => 55296,
281 Pgn::MemoryAccessRequest => 55552,
282 Pgn::Request => 59904,
283 Pgn::Acknowledgement => 59392,
284 Pgn::TransportProtocolDataTransfer => 60160,
285 Pgn::TransportProtocolConnectionManagement => 60416,
286 Pgn::ProprietaryA => 61184,
287 Pgn::ProprietaryA2 => 126720,
288 Pgn::ProprietaryB(pgn) => (*pgn as u32) | 0xFF00,
289 Pgn::ProprietaryB2(pgn) => (*pgn as u32) | 0x1FF00,
290 Pgn::Other(pgn) => *pgn,
291 }
292 }
293}
294
295impl From<Pgn> for u32 {
296 fn from(value: Pgn) -> Self {
297 u32::from(&value)
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304
305 #[test]
306 fn proprietary_id() {
307 let id = Id::new(2565821696);
310
311 assert_eq!(id.sa(), 0x00);
312 assert_eq!(id.da(), Some(0x55));
313 assert_eq!(id.pgn(), Pgn::ProprietaryA);
314 assert_eq!(id.pf(), PduFormat::Pdu1(0xEF));
315 assert_eq!(id.dp(), false);
316 assert_eq!(id.edp(), false);
317 assert_eq!(id.priority(), 6);
318 }
319
320 #[test]
321 fn builder() {
322 let id = IdBuilder::new()
323 .sa(0x00)
324 .da(0x55)
325 .pgn(Pgn::ProprietaryA)
326 .priority(6)
327 .build()
328 .unwrap();
329
330 assert_eq!(id, Id::new(2565821696));
331 assert_eq!(id.pf(), PduFormat::Pdu1(0xEF));
332 }
333
334 #[test]
335 fn pgn_pf() {
336 assert_eq!(PduFormat::from(Pgn::ProprietaryA), PduFormat::Pdu1(239));
337 assert_eq!(PduFormat::from(Pgn::ProprietaryB(0)), PduFormat::Pdu2(255));
338 }
339}