1use crate::ldf::NodeAttributes;
4use bitfield::BitRange;
5use byteorder::{ByteOrder, LittleEndian};
6use core::mem::size_of;
7use num_traits::{PrimInt, Unsigned};
8
9#[derive(Copy, Clone, Debug, PartialEq, Eq)]
11#[repr(transparent)]
12pub struct PID(u8);
13
14impl PID {
15 pub const fn new(pid: u8) -> PID {
17 let correct_pid = PID::from_id(pid & 0b0011_1111);
19 assert!(correct_pid.0 == pid, "Invalid PID");
20 correct_pid
21 }
22
23 pub const fn from_id(id: u8) -> PID {
27 assert!(id < 64, "ID must be less than 64");
28 let p0 = (id & 0b1_0111).count_ones() as u8 & 0b1;
30 let p1 = ((id & 0b11_1010).count_ones() as u8 + 1) & 0b1;
31 PID(id | (p0 << 6u8) | (p1 << 7u8))
32 }
33
34 pub const fn get(self) -> u8 {
36 self.0
37 }
38
39 pub const fn get_id(self) -> u8 {
41 self.0 & 0b0011_1111
42 }
43
44 pub const fn uses_classic_checksum(self) -> bool {
47 self.get_id() >= 60
48 }
49}
50
51pub fn checksum(pid: PID, data: &[u8]) -> u8 {
55 let sum = data.iter().fold(u16::from(pid.0), |sum, v| {
56 let sum = sum + u16::from(*v);
57 if sum >= 256 {
58 sum - 255
59 } else {
60 sum
61 }
62 });
63 !(sum as u8)
64}
65
66pub fn classic_checksum(data: &[u8]) -> u8 {
69 checksum(PID(0u8), data)
70}
71
72#[derive(Debug, Eq, PartialEq)]
73pub struct Frame {
74 pub(crate) pid: PID,
75 pub(crate) buffer: [u8; 9],
76 pub(crate) data_length: usize,
77}
78
79impl Frame {
80 pub fn from_data(pid: PID, data: &[u8]) -> Frame {
82 assert!(data.len() <= 8, "Maximum data is 8 bytes");
83 let mut buffer = [0u8; 9];
84 buffer[0..data.len()].clone_from_slice(data);
85 buffer[data.len()] = {
86 if pid.uses_classic_checksum() {
87 classic_checksum(&buffer[0..data.len()])
88 } else {
89 checksum(pid, &buffer[0..data.len()])
90 }
91 };
92 Frame {
93 pid,
94 buffer,
95 data_length: data.len(),
96 }
97 }
98
99 pub fn get_data(&self) -> &[u8] {
101 &self.buffer[0..self.data_length]
102 }
103
104 pub fn decode<T>(&self, offset: usize, length: usize) -> T
106 where
107 T: PrimInt + Unsigned,
108 u64: BitRange<T>,
109 {
110 assert!(
111 (offset + length) <= self.data_length * 8,
112 "Not enough data available"
113 );
114 assert!(length <= size_of::<T>() * 8, "Output type not big enough");
115
116 let num = LittleEndian::read_u64(&self.buffer[0..8]);
117 num.bit_range(offset + length - 1, offset)
118 }
119
120 pub fn get_checksum(&self) -> u8 {
122 self.buffer[self.data_length]
123 }
124
125 pub fn get_pid(&self) -> PID {
127 self.pid
128 }
129
130 pub fn get_data_with_checksum(&self) -> &[u8] {
132 &self.buffer[0..=self.data_length]
133 }
134}
135
136pub mod transport {
139 use super::{Frame, PID};
140
141 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
144 #[repr(transparent)]
145 pub struct NAD(pub u8);
146
147 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
150 #[repr(transparent)]
151 pub struct PCI(u8);
152
153 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
155 pub enum PCIType {
156 SF = 0,
158 FF = 1,
160 CF = 2,
162 Invalid,
164 }
165
166 impl PCI {
167 pub const fn new_sf(length: u8) -> PCI {
169 assert!(length <= 6, "Maximum length for single frame is 6");
170 PCI(length)
171 }
172
173 pub const fn get_type(self) -> PCIType {
175 match self.0 >> 4 {
176 0 => PCIType::SF,
177 1 => PCIType::FF,
178 2 => PCIType::CF,
179 _ => PCIType::Invalid,
180 }
181 }
182
183 pub const fn get_length(self) -> u8 {
185 self.0 & 0x0F
186 }
187 }
188
189 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
192 #[repr(transparent)]
193 pub struct SID(pub u8);
194
195 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
197 #[repr(transparent)]
198 pub struct RSID(pub u8);
199
200 pub fn create_single_frame(pid: PID, nad: NAD, sid: SID, data: &[u8]) -> Frame {
202 assert!(
203 !data.is_empty() && data.len() <= 5,
204 "A single frame must contain between 0 and 5 bytes"
205 );
206 let mut frame_data = [0xFFu8; 8];
208 frame_data[0] = nad.0;
209 frame_data[1] = PCI::new_sf(data.len() as u8 + 1).0;
210 frame_data[2] = sid.0;
211 frame_data[3..data.len() + 3].clone_from_slice(data);
212 Frame::from_data(pid, &frame_data)
213 }
214}
215
216pub mod diagnostic {
218 use super::transport::{create_single_frame, NAD, SID};
219 use super::{ByteOrder, Frame, LittleEndian, PID};
220
221 pub const MASTER_REQUEST_FRAME_ID: u8 = 0x3C;
222 pub const SLAVE_RESPONSE_FRAME_ID: u8 = 0x3D;
223
224 pub const MASTER_REQUEST_FRAME_PID: PID = PID::from_id(0x3C);
225 pub const SLAVE_RESPONSE_FRAME_PID: PID = PID::from_id(0x3D);
226
227 pub const READ_BY_IDENTIFIER_SID: SID = SID(0xB2);
228
229 #[repr(u8)]
230 pub enum Identifier {
232 LINProductIdentification,
234 SerialNumber,
236 UserDefined(u8),
238 Reserved(u8),
240 }
241
242 impl From<u8> for Identifier {
243 fn from(byte: u8) -> Identifier {
244 match byte {
245 0 => Identifier::LINProductIdentification,
246 1 => Identifier::SerialNumber,
247 b @ 32..=63 => Identifier::UserDefined(b),
248 b => Identifier::Reserved(b),
249 }
250 }
251 }
252
253 impl From<Identifier> for u8 {
254 fn from(identifier: Identifier) -> u8 {
255 match identifier {
256 Identifier::LINProductIdentification => 0,
257 Identifier::SerialNumber => 1,
258 Identifier::UserDefined(b) => b,
259 Identifier::Reserved(b) => b,
260 }
261 }
262 }
263
264 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
266 pub struct ProductId {
267 pub supplier_id: u16,
268 pub function_id: u16,
269 pub variant: u8,
270 }
271
272 impl From<&[u8]> for ProductId {
273 fn from(data: &[u8]) -> ProductId {
274 assert!(data.len() >= 5, "We require at least 4 data bytes");
275 ProductId {
276 supplier_id: LittleEndian::read_u16(&data[0..2]),
277 function_id: LittleEndian::read_u16(&data[2..4]),
278 variant: data[4],
279 }
280 }
281 }
282
283 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
284 #[repr(transparent)]
285 pub struct SerialNumber(pub u32);
286
287 impl From<&[u8]> for SerialNumber {
288 fn from(data: &[u8]) -> SerialNumber {
289 assert!(data.len() >= 4, "We require at least 4 data bytes");
290 SerialNumber(LittleEndian::read_u32(data))
291 }
292 }
293
294 pub fn create_read_by_identifier_frame_from_node_attributes(
296 node_attributes: super::NodeAttributes,
297 identifier: Identifier,
298 ) -> Frame {
299 create_read_by_identifier_frame(
300 node_attributes.initial_nad,
301 identifier,
302 node_attributes.product_id.supplier_id,
303 node_attributes.product_id.function_id,
304 )
305 }
306
307 pub fn create_read_by_identifier_frame(
309 nad: NAD,
310 identifier: Identifier,
311 supplier_id: u16,
312 function_id: u16,
313 ) -> Frame {
314 create_single_frame(
315 MASTER_REQUEST_FRAME_PID,
316 nad,
317 READ_BY_IDENTIFIER_SID,
318 &[
319 identifier.into(),
320 (supplier_id & 0xFF) as u8,
321 (supplier_id >> 8) as u8,
322 (function_id & 0xFF) as u8,
323 (function_id >> 8) as u8,
324 ],
325 )
326 }
327
328 pub fn create_read_lin_product_identification_frame(
329 node_attributes: super::NodeAttributes,
330 ) -> Frame {
331 create_read_by_identifier_frame_from_node_attributes(
332 node_attributes,
333 Identifier::LINProductIdentification,
334 )
335 }
336
337 pub fn create_read_serial_number_frame(node_attributes: super::NodeAttributes) -> Frame {
338 create_read_by_identifier_frame_from_node_attributes(
339 node_attributes,
340 Identifier::SerialNumber,
341 )
342 }
343}
344
345#[cfg(test)]
346mod tests {
347 use super::diagnostic::*;
348 use super::transport::*;
349 use super::*;
350
351 struct CheckSumTestData<'a> {
352 pid: PID,
353 data: &'a [u8],
354 checksum: u8,
355 }
356
357 #[test]
358 fn test_enhanced_checksum() {
359 let test_data = [
360 CheckSumTestData {
361 pid: PID(0xDD),
362 data: &[0x01],
363 checksum: 0x21,
364 },
365 CheckSumTestData {
366 pid: PID(0x4A),
367 data: &[0x55, 0x93, 0xE5],
368 checksum: 0xE6,
369 },
370 CheckSumTestData {
371 pid: PID(0xBF),
372 data: &[0x40, 0xFF],
373 checksum: 0x00,
374 },
375 ];
376 for d in &test_data {
377 assert_eq!(d.checksum, checksum(d.pid, d.data));
378 }
379 }
380
381 #[test]
382 fn test_classic_checksum() {
383 let test_data = [
384 CheckSumTestData {
385 pid: PID::from_id(0x3C),
386 data: &[0x01],
387 checksum: 0xFE,
388 },
389 CheckSumTestData {
390 pid: PID::from_id(0x3D),
391 data: &[0x01],
392 checksum: 0xFE,
393 },
394 CheckSumTestData {
395 pid: PID::from_id(0x3d),
396 data: &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
397 checksum: 0xDB,
398 },
399 ];
400 for d in &test_data {
401 assert_eq!(d.checksum, classic_checksum(d.data));
402 }
403 }
404
405 #[test]
406 fn test_pid_new() {
407 let test_data = [
408 (0x64, PID::new(0x64)),
409 (0xCA, PID::new(0xCA)),
410 (0x80, PID::new(0x80)),
411 (0xC1, PID::new(0xC1)),
412 (0x47, PID::new(0x47)),
413 (0x61, PID::new(0x61)),
414 ];
415
416 for d in &test_data {
417 assert_eq!(d.0, d.1.get());
418 }
419 }
420
421 #[test]
422 #[should_panic]
423 fn test_invalid_pid_new() {
424 PID::new(0x07);
425 }
426
427 #[test]
428 fn test_pid_from_id() {
429 let test_data = [
430 (0, PID(0x80)),
431 (1, PID(0xC1)),
432 (2, PID(0x42)),
433 (25, PID(0x99)),
434 (27, PID(0x5B)),
435 (29, PID(0xDD)),
436 ];
437
438 for d in &test_data {
439 let pid = PID::from_id(d.0);
440 assert_eq!(pid, d.1);
441 assert_eq!(pid.get_id(), d.0);
442 }
443 }
444
445 #[test]
446 fn test_id_uses_classic_checksum() {
447 let test_ids: &[u8] = &[0, 1, 59, 60, 63];
448
449 for i in test_ids {
450 assert_eq!(PID::from_id(*i).uses_classic_checksum(), *i >= 60);
451 }
452 }
453
454 #[test]
455 #[should_panic]
456 fn test_pid_from_id_panic() {
457 PID::from_id(64);
458 }
459
460 #[test]
461 fn test_pci() {
462 let pci = PCI::new_sf(5);
463 assert_eq!(pci.get_type(), PCIType::SF);
464 assert_eq!(pci.get_length(), 5);
465 }
466
467 #[test]
468 fn test_transport_frame() {
469 struct TestData {
470 pid: PID,
471 nad: transport::NAD,
472 sid: transport::SID,
473 data: &'static [u8],
474 frame_data: [u8; 8],
475 }
476 let test_data = [
477 TestData {
478 pid: diagnostic::MASTER_REQUEST_FRAME_PID,
479 nad: transport::NAD(0x10),
480 sid: transport::SID(0xB2),
481 data: &[0x01, 0xB3, 0x00, 0x01, 0x10],
482 frame_data: [0x10, 0x06, 0xB2, 0x01, 0xB3, 0x00, 0x01, 0x10],
483 },
484 TestData {
485 pid: diagnostic::SLAVE_RESPONSE_FRAME_PID,
486 nad: transport::NAD(0x10),
487 sid: transport::SID(0xB2),
488 data: &[0x01],
489 frame_data: [0x10, 0x02, 0xB2, 0x01, 0xFF, 0xFF, 0xFF, 0xFF],
490 },
491 ];
492
493 for d in &test_data {
494 let frame = transport::create_single_frame(d.pid, d.nad, d.sid, d.data);
495 assert_eq!(frame.get_pid(), d.pid);
496 assert_eq!(frame.get_data(), d.frame_data);
497 assert_eq!(frame.data_length, 8);
498 }
499 }
500
501 #[test]
502 #[should_panic]
503 fn test_transport_frame_without_data() {
504 transport::create_single_frame(
505 PID::from_id(0x1),
506 transport::NAD(0x2),
507 transport::SID(0x03),
508 &[],
509 );
510 }
511
512 #[test]
513 #[should_panic]
514 fn test_transport_frame_with_too_much_data() {
515 transport::create_single_frame(
516 PID::from_id(0x1),
517 transport::NAD(0x2),
518 transport::SID(0x03),
519 &[1, 2, 3, 4, 5, 6],
520 );
521 }
522
523 #[test]
524 fn test_create_read_by_identifier_frame() {
525 const LIN_ID_SERIAL_REQ_PAYLOAD: &[u8] = &[0x10, 0x06, 0xB2, 0x01, 0xB3, 0x00, 0x01, 0x10];
526
527 let frame = diagnostic::create_read_by_identifier_frame(
528 transport::NAD(0x10),
529 diagnostic::Identifier::SerialNumber,
530 0x00B3,
531 0x1001,
532 );
533
534 assert_eq!(frame.get_pid(), diagnostic::MASTER_REQUEST_FRAME_PID);
535 assert_eq!(frame.get_data(), LIN_ID_SERIAL_REQ_PAYLOAD);
536 assert_eq!(frame.data_length, 8);
537 }
538
539 #[test]
540 fn test_create_read_by_identifier_frame_from_node_attributes() {
541 const LIN_ID_SERIAL_REQ_PAYLOAD: &[u8] = &[0x10, 0x06, 0xB2, 0x01, 0xB3, 0x00, 0x01, 0x10];
542 let node_attributes = NodeAttributes::with_default_timing(
543 transport::NAD(0x10),
544 transport::NAD(0x10),
545 diagnostic::ProductId {
546 supplier_id: 0x00B3,
547 function_id: 0x1001,
548 variant: 0x00,
549 },
550 );
551
552 let frame = diagnostic::create_read_by_identifier_frame_from_node_attributes(
553 node_attributes,
554 diagnostic::Identifier::SerialNumber,
555 );
556 assert_eq!(frame.get_pid(), diagnostic::MASTER_REQUEST_FRAME_PID);
557 assert_eq!(frame.get_data(), LIN_ID_SERIAL_REQ_PAYLOAD);
558 assert_eq!(frame.data_length, 8);
559 }
560
561 #[test]
562 fn test_decode_product_id() {
563 let product_id = ProductId {
564 supplier_id: 0x00B3,
565 function_id: 0x1001,
566 variant: 0x01,
567 };
568 let data = [0xB3, 0x00, 0x01, 0x10, 0x01];
569
570 assert_eq!(product_id, ProductId::from(&data[..]));
571 }
572
573 #[test]
574 fn test_decode_serial_number() {
575 let serial_number = SerialNumber(190200009);
576 let data = [0xC9, 0x38, 0x56, 0x0B];
577 assert_eq!(serial_number, SerialNumber::from(&data[..]));
578 }
579}