1use super::*;
2
3#[derive(Debug, PartialEq, Eq, Clone, Default)]
5pub struct DltHeader {
6 pub is_big_endian: bool,
8 pub message_counter: u8,
9 pub length: u16,
10 pub ecu_id: Option<[u8; 4]>,
11 pub session_id: Option<u32>,
12 pub timestamp: Option<u32>,
13 pub extended_header: Option<DltExtendedHeader>,
14}
15
16impl DltHeader {
17 pub const SUPPORTED_DECODABLE_VERSIONS: [u8; 2] = [0, 1];
20
21 pub const MAX_SERIALIZED_SIZE: usize = 4 + 4 + 4 + 4 + 10;
31
32 pub const VERSION: u8 = 1;
34
35 pub fn from_slice(slice: &[u8]) -> Result<DltHeader, error::PacketSliceError> {
36 use error::{PacketSliceError::*, *};
37
38 if slice.len() < 4 {
39 return Err(UnexpectedEndOfSlice(UnexpectedEndOfSliceError {
40 layer: error::Layer::DltHeader,
41 minimum_size: 4,
42 actual_size: slice.len(),
43 }));
44 }
45
46 let header_type = unsafe { *slice.get_unchecked(0) };
50
51 let version = (header_type >> 5) & MAX_VERSION;
53 if 0 != version && 1 != version {
54 return Err(UnsupportedDltVersion(UnsupportedDltVersionError {
55 unsupported_version: version,
56 }));
57 }
58
59 let header_len = if 0 != header_type & ECU_ID_FLAG {
62 4 + 4
63 } else {
64 4
65 };
66
67 let header_len = if 0 != header_type & SESSION_ID_FLAG {
68 header_len + 4
69 } else {
70 header_len
71 };
72
73 let header_len = if 0 != header_type & TIMESTAMP_FLAG {
74 header_len + 4
75 } else {
76 header_len
77 };
78
79 let header_len = if 0 != header_type & EXTDENDED_HEADER_FLAG {
80 header_len + 10
81 } else {
82 header_len
83 };
84
85 if slice.len() < header_len {
87 return Err(UnexpectedEndOfSlice(UnexpectedEndOfSliceError {
88 layer: error::Layer::DltHeader,
89 minimum_size: header_len,
90 actual_size: slice.len(),
91 }));
92 }
93
94 let mut next_option_ptr = unsafe { slice.as_ptr().add(4) };
97
98 let ecu_id = if 0 != header_type & ECU_ID_FLAG {
99 unsafe {
103 let ecu_id_ptr = next_option_ptr;
104 next_option_ptr = next_option_ptr.add(4);
105 Some([
106 *ecu_id_ptr,
107 *ecu_id_ptr.add(1),
108 *ecu_id_ptr.add(2),
109 *ecu_id_ptr.add(3),
110 ])
111 }
112 } else {
113 None
114 };
115
116 let session_id = if 0 != header_type & SESSION_ID_FLAG {
117 unsafe {
121 let session_id_ptr = next_option_ptr;
122 next_option_ptr = next_option_ptr.add(4);
123 Some(u32::from_be_bytes([
124 *session_id_ptr,
125 *session_id_ptr.add(1),
126 *session_id_ptr.add(2),
127 *session_id_ptr.add(3),
128 ]))
129 }
130 } else {
131 None
132 };
133
134 let timestamp = if 0 != header_type & TIMESTAMP_FLAG {
135 unsafe {
139 let timestamp_id_ptr = next_option_ptr;
140 next_option_ptr = next_option_ptr.add(4);
141 Some(u32::from_be_bytes([
142 *timestamp_id_ptr,
143 *timestamp_id_ptr.add(1),
144 *timestamp_id_ptr.add(2),
145 *timestamp_id_ptr.add(3),
146 ]))
147 }
148 } else {
149 None
150 };
151
152 let extended_header = if 0 != header_type & EXTDENDED_HEADER_FLAG {
153 Some(DltExtendedHeader {
154 message_info: DltMessageInfo(unsafe { *next_option_ptr }),
158 number_of_arguments: unsafe { *next_option_ptr.add(1) },
159 application_id: unsafe {
160 [
161 *next_option_ptr.add(2),
162 *next_option_ptr.add(3),
163 *next_option_ptr.add(4),
164 *next_option_ptr.add(5),
165 ]
166 },
167 context_id: unsafe {
168 [
169 *next_option_ptr.add(6),
170 *next_option_ptr.add(7),
171 *next_option_ptr.add(8),
172 *next_option_ptr.add(9),
173 ]
174 },
175 })
176 } else {
177 None
178 };
179
180 Ok(DltHeader {
181 is_big_endian: 0 != header_type & BIG_ENDIAN_FLAG,
183 message_counter: unsafe { *slice.get_unchecked(1) },
187 length: u16::from_be_bytes(
188 unsafe { [*slice.get_unchecked(2), *slice.get_unchecked(3)] },
192 ),
193 ecu_id,
194 session_id,
195 timestamp,
196 extended_header,
197 })
198 }
199
200 pub fn to_bytes(&self) -> ArrayVec<u8, { DltHeader::MAX_SERIALIZED_SIZE }> {
202 let length_be = self.length.to_be_bytes();
204 let mut bytes: [u8; 26] = [
205 {
207 let mut result = 0;
208 if self.extended_header.is_some() {
209 result |= EXTDENDED_HEADER_FLAG;
210 }
211 if self.is_big_endian {
212 result |= BIG_ENDIAN_FLAG;
213 }
214 if self.ecu_id.is_some() {
215 result |= ECU_ID_FLAG;
216 }
217 if self.session_id.is_some() {
218 result |= SESSION_ID_FLAG;
219 }
220 if self.timestamp.is_some() {
221 result |= TIMESTAMP_FLAG;
222 }
223 result |= (DltHeader::VERSION << 5) & 0b1110_0000;
224 result
225 },
226 self.message_counter,
227 length_be[0],
228 length_be[1],
229 0,
231 0,
232 0,
233 0,
234 0,
236 0,
237 0,
238 0,
239 0,
241 0,
242 0,
243 0,
244 0,
246 0,
247 0,
248 0,
249 0,
250 0,
251 0,
252 0,
253 0,
254 0,
255 ];
256
257 let mut offset = 4;
258 let mut add_4bytes = |data: [u8; 4]| {
259 unsafe {
262 let ptr = bytes.as_mut_slice().as_mut_ptr().add(offset);
263 *ptr = data[0];
264 *ptr.add(1) = data[1];
265 *ptr.add(2) = data[2];
266 *ptr.add(3) = data[3];
267 }
268 offset += 4;
269 };
270
271 if let Some(value) = self.ecu_id {
273 add_4bytes(value);
274 }
275
276 if let Some(value) = self.session_id {
277 add_4bytes(value.to_be_bytes());
278 }
279
280 if let Some(value) = self.timestamp {
281 add_4bytes(value.to_be_bytes());
282 }
283
284 if let Some(value) = &self.extended_header {
285 unsafe {
287 let ptr = bytes.as_mut_slice().as_mut_ptr().add(offset);
288 *ptr = value.message_info.0;
289 *ptr.add(1) = value.number_of_arguments;
290 *ptr.add(2) = value.application_id[0];
291 *ptr.add(3) = value.application_id[1];
292 *ptr.add(4) = value.application_id[2];
293 *ptr.add(5) = value.application_id[3];
294 *ptr.add(6) = value.context_id[0];
295 *ptr.add(7) = value.context_id[1];
296 *ptr.add(8) = value.context_id[2];
297 *ptr.add(9) = value.context_id[3];
298 }
299 offset += 10;
300 }
301 let mut result = ArrayVec::from(bytes);
302 unsafe {
303 result.set_len(offset);
304 }
305 result
306 }
307
308 #[cfg(feature = "std")]
310 pub fn read<T: io::Read + Sized>(reader: &mut T) -> Result<DltHeader, error::ReadError> {
311 use crate::error::UnsupportedDltVersionError;
312
313 let standard_header_start = {
315 let mut standard_header_start: [u8; 4] = [0; 4];
316 reader.read_exact(&mut standard_header_start)?;
317 standard_header_start
318 };
319
320 let header_type = standard_header_start[0];
322
323 let version = (header_type >> 5) & MAX_VERSION;
325 if 0 != version && 1 != version {
326 return Err(error::ReadError::UnsupportedDltVersion(
327 UnsupportedDltVersionError {
328 unsupported_version: version,
329 },
330 ));
331 }
332
333 Ok(DltHeader {
335 is_big_endian: 0 != header_type & BIG_ENDIAN_FLAG,
336 message_counter: standard_header_start[1],
337 length: u16::from_be_bytes([standard_header_start[2], standard_header_start[3]]),
338 ecu_id: if 0 != header_type & ECU_ID_FLAG {
339 Some({
340 let mut buffer: [u8; 4] = [0; 4];
341 reader.read_exact(&mut buffer)?;
342 buffer
343 })
344 } else {
345 None
346 },
347 session_id: if 0 != header_type & SESSION_ID_FLAG {
348 Some({
349 let mut buffer: [u8; 4] = [0; 4];
350 reader.read_exact(&mut buffer)?;
351 u32::from_be_bytes(buffer)
352 })
353 } else {
354 None
355 },
356 timestamp: if 0 != header_type & TIMESTAMP_FLAG {
357 Some({
358 let mut buffer: [u8; 4] = [0; 4];
359 reader.read_exact(&mut buffer)?;
360 u32::from_be_bytes(buffer)
361 })
362 } else {
363 None
364 },
365 extended_header: if 0 != header_type & EXTDENDED_HEADER_FLAG {
366 Some({
367 let mut buffer: [u8; 10] = [0; 10];
368 reader.read_exact(&mut buffer)?;
369
370 DltExtendedHeader {
371 message_info: DltMessageInfo(buffer[0]),
372 number_of_arguments: buffer[1],
373 application_id: [buffer[2], buffer[3], buffer[4], buffer[5]],
374 context_id: [buffer[6], buffer[7], buffer[8], buffer[9]],
375 }
376 })
377 } else {
378 None
379 },
380 })
381 }
382
383 #[cfg(feature = "std")]
385 pub fn write<T: io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
386 {
387 let length_be = self.length.to_be_bytes();
388 let standard_header_start: [u8; 4] = [
389 {
391 let mut result = 0;
392 if self.extended_header.is_some() {
393 result |= EXTDENDED_HEADER_FLAG;
394 }
395 if self.is_big_endian {
396 result |= BIG_ENDIAN_FLAG;
397 }
398 if self.ecu_id.is_some() {
399 result |= ECU_ID_FLAG;
400 }
401 if self.session_id.is_some() {
402 result |= SESSION_ID_FLAG;
403 }
404 if self.timestamp.is_some() {
405 result |= TIMESTAMP_FLAG;
406 }
407 result |= (DltHeader::VERSION << 5) & 0b1110_0000;
408 result
409 },
410 self.message_counter,
411 length_be[0],
412 length_be[1],
413 ];
414
415 writer.write_all(&standard_header_start)?;
416 }
417
418 if let Some(value) = self.ecu_id {
419 writer.write_all(&value)?;
420 }
421
422 if let Some(value) = self.session_id {
423 writer.write_all(&value.to_be_bytes())?;
424 }
425
426 if let Some(value) = self.timestamp {
427 writer.write_all(&value.to_be_bytes())?;
428 }
429
430 if let Some(value) = &self.extended_header {
432 let bytes: [u8; 10] = [
433 value.message_info.0,
434 value.number_of_arguments,
435 value.application_id[0],
436 value.application_id[1],
437 value.application_id[2],
438 value.application_id[3],
439 value.context_id[0],
440 value.context_id[1],
441 value.context_id[2],
442 value.context_id[3],
443 ];
444 writer.write_all(&bytes)?;
445 }
446 Ok(())
447 }
448
449 #[inline]
451 pub fn is_verbose(&self) -> bool {
452 match &self.extended_header {
453 None => false, Some(ext) => ext.is_verbose(),
455 }
456 }
457
458 #[inline]
460 pub fn header_len(&self) -> u16 {
461 4 + match self.ecu_id {
462 Some(_) => 4,
463 None => 0,
464 } + match self.session_id {
465 Some(_) => 4,
466 None => 0,
467 } + match self.timestamp {
468 Some(_) => 4,
469 None => 0,
470 } + match self.extended_header {
471 Some(_) => 10,
472 None => 0,
473 }
474 }
475}
476
477#[cfg(test)]
478mod dlt_header_tests {
479
480 use super::*;
481 use crate::proptest_generators::*;
482 use proptest::prelude::*;
483
484 proptest! {
485 #[test]
486 fn to_bytes_from_slice(
487 version in 0..=1u8,
488 ref dlt_header in dlt_header_any(),
489 unsupported_version in (0u8..0b111u8).prop_filter(
490 "version must be unknown",
491 |v| !DltHeader::SUPPORTED_DECODABLE_VERSIONS.iter().any(|&x| v == &x)
492 )
493 ) {
494 use error::PacketSliceError::*;
495 {
497 let bytes = {
498 let mut bytes = dlt_header.to_bytes();
499 bytes[0] = (bytes[0] & 0b0001_1111) | ((version << 5) & 0b1110_0000);
501 bytes
502 };
503 assert_eq!(
504 dlt_header.clone(),
505 DltHeader::from_slice(&bytes[..]).unwrap()
506 );
507 }
508 {
510 for l in 0..dlt_header.header_len() as usize {
511 let bytes = dlt_header.to_bytes();
512 assert_eq!(
513 UnexpectedEndOfSlice(
514 error::UnexpectedEndOfSliceError{
515 minimum_size: if l < 4 {
516 4
517 } else {
518 dlt_header.header_len() as usize
519 },
520 actual_size: l,
521 layer: error::Layer::DltHeader,
522 }
523 ),
524 DltHeader::from_slice(&bytes[..l]).unwrap_err()
525 );
526 }
527 }
528 {
530 let mut bytes = dlt_header.to_bytes();
531 bytes[0] = (bytes[0] & 0b0001_1111) | ((unsupported_version << 5) & 0b1110_0000);
534 assert_eq!(
535 UnsupportedDltVersion(
536 error::UnsupportedDltVersionError{
537 unsupported_version,
538 }
539 ),
540 DltHeader::from_slice(&bytes[..]).unwrap_err()
541 );
542 }
543 }
544 }
545
546 proptest! {
547 #[test]
548 #[cfg(feature = "std")]
549 fn write_read(ref dlt_header in dlt_header_any()) {
550 use std::io::Cursor;
551
552 let mut buffer = Vec::new();
553 dlt_header.write(&mut buffer).unwrap();
554 let mut reader = Cursor::new(&buffer[..]);
555 let result = DltHeader::read(&mut reader).unwrap();
556 assert_eq!(dlt_header, &result);
557 }
558 }
559
560 proptest! {
561 #[test]
562 #[cfg(feature = "std")]
563 fn read_length_error(ref dlt_header in dlt_header_any()) {
564 use std::io::Cursor;
565
566 let mut buffer = Vec::new();
567 dlt_header.write(&mut buffer).unwrap();
568 let reduced_len = buffer.len() - 1;
569 let mut reader = Cursor::new(&buffer[..reduced_len]);
570 assert_matches!(DltHeader::read(&mut reader), Err(error::ReadError::IoError(_)));
571 }
572 }
573
574 proptest! {
575 #[test]
576 #[cfg(feature = "std")]
577 fn write_io_error(ref header in dlt_header_any()) {
578 use std::io::Cursor;
579
580 let mut buffer: Vec<u8> = Vec::with_capacity(
581 header.header_len().into()
582 );
583 for len in 0..header.header_len() {
584 buffer.resize(len.into(), 0);
585 let mut writer = Cursor::new(&mut buffer[..]);
586 assert_matches!(header.write(&mut writer), Err(_));
587 }
588 }
589 }
590
591 #[test]
592 fn is_verbose() {
593 let mut header: DltHeader = Default::default();
594 assert_eq!(false, header.is_verbose());
595 header.extended_header = Some(Default::default());
597 assert_eq!(false, header.is_verbose());
598 header
600 .extended_header
601 .as_mut()
602 .unwrap()
603 .set_is_verbose(true);
604 assert_eq!(true, header.is_verbose());
605 }
606
607 #[test]
608 fn header_len() {
609 struct Test {
610 expected: u16,
611 ecu_id: Option<[u8; 4]>,
612 session_id: Option<u32>,
613 timestamp: Option<u32>,
614 extended_header: Option<DltExtendedHeader>,
615 }
616
617 let tests = [
618 Test {
619 expected: 4,
620 ecu_id: None,
621 session_id: None,
622 timestamp: None,
623 extended_header: None,
624 },
625 Test {
626 expected: 4 + 4 + 4 + 4 + 10,
627 ecu_id: Some([0; 4]),
628 session_id: Some(0),
629 timestamp: Some(0),
630 extended_header: Some(Default::default()),
631 },
632 Test {
633 expected: 4 + 4,
634 ecu_id: Some([0; 4]),
635 session_id: None,
636 timestamp: None,
637 extended_header: None,
638 },
639 Test {
640 expected: 4 + 4,
641 ecu_id: None,
642 session_id: Some(0),
643 timestamp: None,
644 extended_header: None,
645 },
646 Test {
647 expected: 4 + 4,
648 ecu_id: None,
649 session_id: None,
650 timestamp: Some(0),
651 extended_header: None,
652 },
653 Test {
654 expected: 4 + 10,
655 ecu_id: None,
656 session_id: None,
657 timestamp: None,
658 extended_header: Some(Default::default()),
659 },
660 ];
661
662 for test in tests {
663 assert_eq!(
664 test.expected,
665 DltHeader {
666 is_big_endian: false,
667 message_counter: 123,
668 length: 123,
669 ecu_id: test.ecu_id,
670 session_id: test.session_id,
671 timestamp: test.timestamp,
672 extended_header: test.extended_header,
673 }
674 .header_len()
675 );
676 }
677 }
678
679 #[test]
680 fn debug() {
681 let header: DltHeader = Default::default();
682 assert_eq!(
683 format!(
684 "DltHeader {{ is_big_endian: {}, message_counter: {}, length: {}, ecu_id: {:?}, session_id: {:?}, timestamp: {:?}, extended_header: {:?} }}",
685 header.is_big_endian,
686 header.message_counter,
687 header.length,
688 header.ecu_id,
689 header.session_id,
690 header.timestamp,
691 header.extended_header,
692 ),
693 format!("{:?}", header)
694 );
695 }
696
697 proptest! {
698 #[test]
699 fn clone_eq(ref header in dlt_header_any()) {
700 assert_eq!(*header, header.clone());
701 }
702 }
703
704 #[test]
705 fn default() {
706 let header: DltHeader = Default::default();
707 assert_eq!(header.is_big_endian, false);
708 assert_eq!(header.message_counter, 0);
709 assert_eq!(header.length, 0);
710 assert_eq!(header.ecu_id, None);
711 assert_eq!(header.session_id, None);
712 assert_eq!(header.timestamp, None);
713 assert_eq!(header.extended_header, None);
714 }
715}