Skip to main content

simple_someip/protocol/
header.rs

1use crate::{
2    protocol::{
3        Error, MessageId, MessageTypeField, ReturnCode,
4        byte_order::{ReadBytesExt, WriteBytesExt},
5    },
6    traits::WireFormat,
7};
8
9/// SOME/IP header
10#[derive(Clone, Debug, Eq, PartialEq)]
11pub struct Header {
12    /// Message ID, encoding service ID and method ID
13    pub message_id: MessageId,
14    /// Length of the message in bytes, starting at the request Id
15    /// Total length of the message is therefore length + 8
16    pub length: u32,
17    /// SOME/IP Request ID (4 bytes): Client ID [31:16] + Session ID [15:0].
18    pub request_id: u32,
19    pub protocol_version: u8,
20    pub interface_version: u8,
21    pub message_type: MessageTypeField,
22    pub return_code: ReturnCode,
23}
24
25impl Header {
26    /// Return the 8-byte "upper header" used by E2E UPPER-HEADER-BITS-TO-SHIFT.
27    ///
28    /// Layout (big-endian): `request_id(4)` + `protocol_version(1)` + `interface_version(1)`
29    ///                      + `message_type(1)` + `return_code(1)`
30    ///
31    /// Note: `request_id` is the full 4-byte SOME/IP Request ID field
32    /// (Client ID [31:16] + Session ID [15:0]), not just the 2-byte Session ID.
33    #[must_use]
34    pub fn upper_header_bytes(&self) -> [u8; 8] {
35        let rid = self.request_id.to_be_bytes();
36        [
37            rid[0],
38            rid[1],
39            rid[2],
40            rid[3],
41            self.protocol_version,
42            self.interface_version,
43            u8::from(self.message_type),
44            u8::from(self.return_code),
45        ]
46    }
47
48    #[must_use]
49    pub fn new_sd(request_id: u32, sd_header_size: usize) -> Self {
50        Self {
51            message_id: MessageId::SD,
52            length: 8 + u32::try_from(sd_header_size).expect("SD header too large"),
53            request_id,
54            protocol_version: 0x01,
55            interface_version: 0x01,
56            message_type: MessageTypeField::new_sd(),
57            return_code: ReturnCode::Ok,
58        }
59    }
60
61    #[must_use]
62    pub const fn is_sd(&self) -> bool {
63        self.message_id.is_sd()
64    }
65
66    #[must_use]
67    pub const fn payload_size(&self) -> usize {
68        self.length as usize - 8
69    }
70
71    pub fn set_request_id(&mut self, request_id: u32) {
72        self.request_id = request_id;
73    }
74}
75
76impl WireFormat for Header {
77    fn decode<T: embedded_io::Read>(reader: &mut T) -> Result<Self, Error> {
78        let message_id = MessageId::from(reader.read_u32_be()?);
79        let length = reader.read_u32_be()?;
80        let request_id = reader.read_u32_be()?;
81        let protocol_version = reader.read_u8()?;
82        if protocol_version != 0x01 {
83            return Err(Error::InvalidProtocolVersion(protocol_version));
84        }
85        let interface_version = reader.read_u8()?;
86        let message_type = MessageTypeField::try_from(reader.read_u8()?)?;
87        let return_code = ReturnCode::try_from(reader.read_u8()?)?;
88        Ok(Self {
89            message_id,
90            length,
91            request_id,
92            protocol_version,
93            interface_version,
94            message_type,
95            return_code,
96        })
97    }
98
99    fn required_size(&self) -> usize {
100        16
101    }
102
103    fn encode<T: embedded_io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
104        writer.write_u32_be(self.message_id.message_id())?;
105        writer.write_u32_be(self.length)?;
106        writer.write_u32_be(self.request_id)?;
107        writer.write_u8(self.protocol_version)?;
108        writer.write_u8(self.interface_version)?;
109        writer.write_u8(u8::from(self.message_type))?;
110        writer.write_u8(u8::from(self.return_code))?;
111        Ok(16)
112    }
113}