Skip to main content

doip_definitions/doip_header/
mod.rs

1pub mod payload_type;
2pub mod version;
3
4use payload_type::PayloadType;
5use version::ProtocolVersion;
6
7use crate::error::{Error, Result};
8
9/// The definitive fields of a `DoIP` frame.
10///
11/// The definition of a `DoIP` frame is found in the `DoipHeader`, this contains each
12/// key field which a parser uses to identify the bytes which pertain to a `DoIP`
13/// frame.
14#[cfg_attr(feature = "python-bindings", pyo3::pyclass)]
15#[derive(Debug, PartialEq, Clone)]
16pub struct DoipHeader {
17    /// `protocol_version` acts a pair with the `inverse_protocol_version` to create
18    /// a validation check to ensure the packet is constructed correctly. There
19    /// are specific versions available within the `DoipVersion` enum.
20    pub protocol_version: ProtocolVersion,
21
22    /// Calculated using bitwise inversion, the `inverse_protocol_version` acts
23    /// as a validation technique for validating the packet.
24    pub inverse_protocol_version: u8,
25
26    /// The type of payload alongside the header, this defines what is contained
27    /// within the message, and directs the parser to accurately identify fields.
28    ///
29    /// A list of valid Payload Types are available in the `PayloadType` enum.
30    pub payload_type: PayloadType,
31
32    /// The `payload_length` is automatically calulated on the construction of a
33    /// `DoipHeader` and is taken from the payload the header was initiated with.
34    ///
35    /// This tells the parser how many bytes to expect after the header.
36    pub payload_length: u32,
37}
38
39impl TryFrom<[u8; 8]> for DoipHeader {
40    type Error = Error;
41
42    fn try_from(value: [u8; 8]) -> Result<Self> {
43        let protocol_version_slice = value.first().ok_or(Error::OutOfBounds {
44            source: "DoIP Header",
45            variable: "Protocol Version",
46        })?;
47        let protocol_version = ProtocolVersion::try_from(protocol_version_slice)?;
48
49        let inverse_protocol_version_slice = value.get(1).ok_or(Error::OutOfBounds {
50            source: "DoIP Header",
51            variable: "Inverse Protocol Version",
52        })?;
53        let inverse_protocol_version = *inverse_protocol_version_slice;
54
55        let payload_type_slice = value.get(2..4).ok_or(Error::OutOfBounds {
56            source: "DoIP Header",
57            variable: "Payload Type",
58        })?;
59        let payload_type = PayloadType::try_from(payload_type_slice)?;
60
61        let payload_length_slice: [u8; 4] = value
62            .get(4..8)
63            .ok_or(Error::OutOfBounds {
64                source: "DoIP Header",
65                variable: "Payload Length",
66            })?
67            .try_into()?;
68        let payload_length = u32::from_be_bytes(payload_length_slice);
69
70        Ok(DoipHeader {
71            protocol_version,
72            inverse_protocol_version,
73            payload_type,
74            payload_length,
75        })
76    }
77}
78
79impl From<DoipHeader> for [u8; 8] {
80    fn from(value: DoipHeader) -> Self {
81        let protocol_version: u8 = u8::from(value.protocol_version);
82        let inverse_protocol_version: u8 = value.inverse_protocol_version;
83        let payload_type: [u8; 2] = <[u8; 2]>::from(value.payload_type);
84        let payload_length: [u8; 4] = value.payload_length.to_be_bytes();
85
86        [
87            protocol_version,
88            inverse_protocol_version,
89            payload_type[0],
90            payload_type[1],
91            payload_length[0],
92            payload_length[1],
93            payload_length[2],
94            payload_length[3],
95        ]
96    }
97}