someip_wire/
types.rs

1use core::fmt::{self, Display};
2
3/// Struct representation of MessageID
4#[derive(Debug, PartialEq, Eq, Clone, Copy)]
5pub struct MessageId {
6    pub service_id: u16,
7    pub method_id: u16,
8}
9
10impl MessageId {
11    /// Parses a MessageId from a u32 value
12    ///
13    /// # Arguments
14    ///
15    /// * `value` - A u32 value representing the MessageId
16    /// # Returns
17    ///
18    /// * `MessageId` - The parsed MessageId struct
19    pub fn from_u32(value: u32) -> MessageId {
20        MessageId {
21            service_id: (value >> 16) as u16,
22            method_id: (value & 0xFFFF) as u16,
23        }
24    }
25
26    /// Converts the MessageId struct into a u32 value
27    ///
28    /// # Returns
29    ///
30    /// * `u32` - The u32 representation of the MessageId
31    pub fn to_u32(&self) -> u32 {
32        ((self.service_id as u32) << 16) | (self.method_id as u32)
33    }
34}
35
36impl Display for MessageId {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(f, "{:04X}.{:04X}", self.service_id, self.method_id)
39    }
40}
41
42/// Struct representation of ClientID
43#[derive(Debug, PartialEq, Eq, Clone, Copy)]
44pub struct ClientId {
45    pub client_id_prefix: u8,
46    pub client_id: u8,
47}
48
49#[allow(dead_code)]
50impl ClientId {
51    /// Parses a ClientId from a u16 value
52    ///
53    /// # Arguments
54    ///
55    /// * `value` - A u16 value representing the ClientId
56    /// # Returns
57    ///
58    /// * `ClientId` - The parsed ClientId struct
59    pub fn from_u16(value: u16) -> ClientId {
60        ClientId {
61            client_id_prefix: ((value >> 8) & 0xFF) as u8,
62            client_id: (value & 0xFF) as u8,
63        }
64    }
65
66    /// Converts the ClientId struct into a u16 value
67    ///
68    /// # Returns
69    ///
70    /// * `u16` - The u16 representation of the ClientId
71    pub fn to_u16(&self) -> u16 {
72        ((self.client_id_prefix as u16) << 8) | (self.client_id as u16)
73    }
74}
75
76impl Display for ClientId {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        write!(f, "{:02X}.{:02X}", self.client_id_prefix, self.client_id)
79    }
80}
81
82/// Struct representation of RequestID
83#[derive(Debug, PartialEq, Eq, Clone, Copy)]
84pub struct RequestId {
85    pub client_id: ClientId,
86    pub session_id: u16,
87}
88
89#[allow(dead_code)]
90impl RequestId {
91    /// Parses a RequestId from a u32 value
92    ///
93    /// # Arguments
94    ///
95    /// * `value` - A u32 value representing the RequestId
96    /// # Returns
97    ///
98    /// * `RequestId` - The parsed RequestId struct
99    pub fn from_u32(value: u32) -> RequestId {
100        RequestId {
101            client_id: ClientId::from_u16((value >> 16) as u16),
102            session_id: (value & 0xFFFF) as u16,
103        }
104    }
105
106    /// Converts the RequestId struct into a u32 value
107    ///
108    /// # Returns
109    ///
110    /// * `u32` - The u32 representation of the RequestId
111    pub fn to_u32(&self) -> u32 {
112        ((self.client_id.to_u16() as u32) << 16) | (self.session_id as u32)
113    }
114}
115
116impl Display for RequestId {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        write!(f, "{}.{:04X}", self.client_id, self.session_id)
119    }
120}
121
122/// Public representation of SOME/IP return codes
123///
124/// This enum provides a clean, ergonomic API for working with SOME/IP return codes.
125/// Named variants represent well-known error codes, while data-carrying variants
126/// handle reserved ranges.
127#[derive(PartialEq, Eq, Clone, Copy, Debug)]
128#[allow(non_camel_case_types)]
129pub enum ReturnCode {
130    /// No error occurred
131    E_OK,
132    /// An unspecified error occurred
133    E_NOT_OK,
134    /// The requested service is unknown
135    E_UNKNOWN_SERVICE,
136    /// The requested method is unknown
137    E_UNKNOWN_METHOD,
138    /// Service not ready
139    E_NOT_READY,
140    /// Service not reachable
141    E_NOT_REACHABLE,
142    /// Timeout occurred
143    E_TIMEOUT,
144    /// Wrong protocol version
145    E_WRONG_PROTOCOL_VERSION,
146    /// Wrong interface version
147    E_WRONG_INTERFACE_VERSION,
148    /// Malformed message
149    E_MALFORMED_MESSAGE,
150    /// Wrong message type
151    E_WRONG_MESSAGE_TYPE,
152    /// E2E repeated
153    E_E2E_REPEATED,
154    /// E2E wrong sequence
155    E_E2E_WRONG_SEQUENCE,
156    /// E2E error
157    E_E2E,
158    /// E2E not available
159    E_E2E_NOT_AVAILABLE,
160    /// E2E no new data
161    E_E2E_NO_NEW_DATA,
162    /// Reserved for generic SOME/IP errors (range 0x10-0x1F)
163    ReservedSomeIP(u8),
164    /// Reserved for service/method specific errors (range 0x20-0x5E)
165    ReservedServiceMethod(u8),
166}
167
168impl ReturnCode {
169    /// Create a ReturnCode from a raw u8 value
170    ///
171    /// Returns None if the value is outside valid SOME/IP ranges (> 0x5E).
172    pub fn from_u8(value: u8) -> Option<Self> {
173        if value > 0x5E {
174            return None;
175        }
176
177        Some(match value {
178            0x00 => ReturnCode::E_OK,
179            0x01 => ReturnCode::E_NOT_OK,
180            0x02 => ReturnCode::E_UNKNOWN_SERVICE,
181            0x03 => ReturnCode::E_UNKNOWN_METHOD,
182            0x04 => ReturnCode::E_NOT_READY,
183            0x05 => ReturnCode::E_NOT_REACHABLE,
184            0x06 => ReturnCode::E_TIMEOUT,
185            0x07 => ReturnCode::E_WRONG_PROTOCOL_VERSION,
186            0x08 => ReturnCode::E_WRONG_INTERFACE_VERSION,
187            0x09 => ReturnCode::E_MALFORMED_MESSAGE,
188            0x0A => ReturnCode::E_WRONG_MESSAGE_TYPE,
189            0x0B => ReturnCode::E_E2E_REPEATED,
190            0x0C => ReturnCode::E_E2E_WRONG_SEQUENCE,
191            0x0D => ReturnCode::E_E2E,
192            0x0E => ReturnCode::E_E2E_NOT_AVAILABLE,
193            0x0F => ReturnCode::E_E2E_NO_NEW_DATA,
194            0x10..=0x1F => ReturnCode::ReservedSomeIP(value),
195            0x20..=0x5E => ReturnCode::ReservedServiceMethod(value),
196            _ => unreachable!("value validated to be <= 0x5E"),
197        })
198    }
199
200    /// Get the raw u8 value
201    pub fn as_u8(&self) -> u8 {
202        match self {
203            ReturnCode::E_OK => 0x00,
204            ReturnCode::E_NOT_OK => 0x01,
205            ReturnCode::E_UNKNOWN_SERVICE => 0x02,
206            ReturnCode::E_UNKNOWN_METHOD => 0x03,
207            ReturnCode::E_NOT_READY => 0x04,
208            ReturnCode::E_NOT_REACHABLE => 0x05,
209            ReturnCode::E_TIMEOUT => 0x06,
210            ReturnCode::E_WRONG_PROTOCOL_VERSION => 0x07,
211            ReturnCode::E_WRONG_INTERFACE_VERSION => 0x08,
212            ReturnCode::E_MALFORMED_MESSAGE => 0x09,
213            ReturnCode::E_WRONG_MESSAGE_TYPE => 0x0A,
214            ReturnCode::E_E2E_REPEATED => 0x0B,
215            ReturnCode::E_E2E_WRONG_SEQUENCE => 0x0C,
216            ReturnCode::E_E2E => 0x0D,
217            ReturnCode::E_E2E_NOT_AVAILABLE => 0x0E,
218            ReturnCode::E_E2E_NO_NEW_DATA => 0x0F,
219            ReturnCode::ReservedSomeIP(v) => *v,
220            ReturnCode::ReservedServiceMethod(v) => *v,
221        }
222    }
223
224    /// Check if this is an OK status
225    pub const fn is_ok(&self) -> bool {
226        matches!(self, ReturnCode::E_OK)
227    }
228
229    /// Check if this is a reserved SOME/IP error (0x10-0x1F)
230    pub const fn is_reserved_someip(&self) -> bool {
231        matches!(self, ReturnCode::ReservedSomeIP(_))
232    }
233
234    /// Check if this is a service/method specific error (0x20-0x5E)
235    pub const fn is_reserved_service_method(&self) -> bool {
236        matches!(self, ReturnCode::ReservedServiceMethod(_))
237    }
238}
239
240// Convenience: convert to u8
241impl From<ReturnCode> for u8 {
242    fn from(code: ReturnCode) -> Self {
243        code.as_u8()
244    }
245}
246
247impl Display for ReturnCode {
248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249        match self {
250            ReturnCode::E_OK => write!(f, "E_OK"),
251            ReturnCode::E_NOT_OK => write!(f, "E_NOT_OK"),
252            ReturnCode::E_UNKNOWN_SERVICE => write!(f, "E_UNKNOWN_SERVICE"),
253            ReturnCode::E_UNKNOWN_METHOD => write!(f, "E_UNKNOWN_METHOD"),
254            ReturnCode::E_NOT_READY => write!(f, "E_NOT_READY"),
255            ReturnCode::E_NOT_REACHABLE => write!(f, "E_NOT_REACHABLE"),
256            ReturnCode::E_TIMEOUT => write!(f, "E_TIMEOUT"),
257            ReturnCode::E_WRONG_PROTOCOL_VERSION => write!(f, "E_WRONG_PROTOCOL_VERSION"),
258            ReturnCode::E_WRONG_INTERFACE_VERSION => write!(f, "E_WRONG_INTERFACE_VERSION"),
259            ReturnCode::E_MALFORMED_MESSAGE => write!(f, "E_MALFORMED_MESSAGE"),
260            ReturnCode::E_WRONG_MESSAGE_TYPE => write!(f, "E_WRONG_MESSAGE_TYPE"),
261            ReturnCode::E_E2E_REPEATED => write!(f, "E_E2E_REPEATED"),
262            ReturnCode::E_E2E_WRONG_SEQUENCE => write!(f, "E_E2E_WRONG_SEQUENCE"),
263            ReturnCode::E_E2E => write!(f, "E_E2E"),
264            ReturnCode::E_E2E_NOT_AVAILABLE => write!(f, "E_E2E_NOT_AVAILABLE"),
265            ReturnCode::E_E2E_NO_NEW_DATA => write!(f, "E_E2E_NO_NEW_DATA"),
266            ReturnCode::ReservedSomeIP(v) => write!(f, "Reserved SOME/IP Error (0x{:02X})", v),
267            ReturnCode::ReservedServiceMethod(v) => {
268                write!(f, "Reserved Service/Method Error (0x{:02X})", v)
269            }
270        }
271    }
272}
273
274/// Message Type for SOME/IP protocol
275///
276/// This enum represents the different types of messages in SOME/IP.
277/// It's a clean representation type with named variants for known message types.
278#[derive(Debug, PartialEq, Eq, Clone, Copy)]
279pub enum MessageType {
280    /// A request expecting a response (even void)
281    Request,
282    /// A Fire&Forget request   
283    RequestNoReturn,
284    /// A request of a notification/event callback expecting no response     
285    Notification,
286    /// The response message
287    Response,
288    /// The response containing an error
289    Error,
290    /// A TP request expecting a response (even void)           
291    TPRequest,
292    /// A TP Fire&Forget request
293    TPRequestNoReturn,
294    /// A TP notification/event callback expecting no response
295    TPNotification,
296    /// The TP response message
297    TPResponse,
298    /// The TP response containing an error
299    TPError,
300}
301
302impl MessageType {
303    /// Convert from wire format (u8) to MessageType
304    ///
305    /// Returns None if the value doesn't correspond to a known message type
306    pub fn from_u8(value: u8) -> Option<Self> {
307        match value {
308            0x00 => Some(MessageType::Request),
309            0x01 => Some(MessageType::RequestNoReturn),
310            0x02 => Some(MessageType::Notification),
311            0x03 => Some(MessageType::Response),
312            0x04 => Some(MessageType::Error),
313            0x20 => Some(MessageType::TPRequest),
314            0x21 => Some(MessageType::TPRequestNoReturn),
315            0x22 => Some(MessageType::TPNotification),
316            0xA0 => Some(MessageType::TPResponse),
317            0xA1 => Some(MessageType::TPError),
318            _ => None,
319        }
320    }
321
322    /// Convert to wire format (u8)
323    pub fn as_u8(&self) -> u8 {
324        match self {
325            MessageType::Request => 0x00,
326            MessageType::RequestNoReturn => 0x01,
327            MessageType::Notification => 0x02,
328            MessageType::Response => 0x03,
329            MessageType::Error => 0x04,
330            MessageType::TPRequest => 0x20,
331            MessageType::TPRequestNoReturn => 0x21,
332            MessageType::TPNotification => 0x22,
333            MessageType::TPResponse => 0xA0,
334            MessageType::TPError => 0xA1,
335        }
336    }
337
338    /// Check if this is a request type (expects a response)
339    pub const fn is_request(&self) -> bool {
340        matches!(self, MessageType::Request | MessageType::TPRequest)
341    }
342
343    /// Check if this is a fire-and-forget request
344    pub const fn is_request_no_return(&self) -> bool {
345        matches!(
346            self,
347            MessageType::RequestNoReturn | MessageType::TPRequestNoReturn
348        )
349    }
350
351    /// Check if this is a notification
352    pub const fn is_notification(&self) -> bool {
353        matches!(
354            self,
355            MessageType::Notification | MessageType::TPNotification
356        )
357    }
358
359    /// Check if this is a response
360    pub const fn is_response(&self) -> bool {
361        matches!(self, MessageType::Response | MessageType::TPResponse)
362    }
363
364    /// Check if this is an error response
365    pub const fn is_error(&self) -> bool {
366        matches!(self, MessageType::Error | MessageType::TPError)
367    }
368
369    /// Check if this is a TP (TCP) message
370    pub const fn is_tp(&self) -> bool {
371        matches!(
372            self,
373            MessageType::TPRequest
374                | MessageType::TPRequestNoReturn
375                | MessageType::TPNotification
376                | MessageType::TPResponse
377                | MessageType::TPError
378        )
379    }
380}
381
382// Convenience: convert to u8
383impl From<MessageType> for u8 {
384    fn from(mt: MessageType) -> Self {
385        mt.as_u8()
386    }
387}
388
389impl Display for MessageType {
390    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391        match self {
392            MessageType::Request => write!(f, "Request"),
393            MessageType::RequestNoReturn => write!(f, "Request No Return"),
394            MessageType::Notification => write!(f, "Notification"),
395            MessageType::Response => write!(f, "Response"),
396            MessageType::Error => write!(f, "Error"),
397            MessageType::TPRequest => write!(f, "TP Request"),
398            MessageType::TPRequestNoReturn => write!(f, "TP Request No Return"),
399            MessageType::TPNotification => write!(f, "TP Notification"),
400            MessageType::TPResponse => write!(f, "TP Response"),
401            MessageType::TPError => write!(f, "TP Error"),
402        }
403    }
404}