Skip to main content

simple_someip/protocol/
message_id.rs

1use super::sd;
2
3/// Newtype for a message ID.
4/// The Message ID is a 32-bit identifier that is unique for each message.
5/// It encodes both the service ID and the method ID.
6/// Message IDs are assumed to be unique for an entire vehicle network.
7#[derive(Clone, Copy, Eq, PartialEq)]
8pub struct MessageId(u32);
9
10impl From<u32> for MessageId {
11    fn from(message_id: u32) -> Self {
12        MessageId(message_id)
13    }
14}
15
16impl MessageId {
17    /// Message ID for Service Discovery
18    pub const SD: Self = Self::new(sd::MESSAGE_ID_VALUE);
19
20    /// Create a new `MessageId` directly.
21    #[must_use]
22    pub const fn new(message_id: u32) -> Self {
23        MessageId(message_id)
24    }
25
26    /// Create a new `MessageId` from service and method IDs.
27    #[must_use]
28    pub const fn new_from_service_and_method(service_id: u16, method_id: u16) -> Self {
29        MessageId(((service_id as u32) << 16) | method_id as u32)
30    }
31
32    /// Get the message ID
33    #[inline]
34    #[must_use]
35    pub const fn message_id(&self) -> u32 {
36        self.0
37    }
38
39    /// Set the message ID
40    #[inline]
41    pub const fn set_message_id(&mut self, message_id: u32) {
42        self.0 = message_id;
43    }
44
45    /// Get the service ID
46    #[inline]
47    #[must_use]
48    pub const fn service_id(&self) -> u16 {
49        (self.0 >> 16) as u16
50    }
51
52    /// Set the service ID
53    #[inline]
54    pub const fn set_service_id(&mut self, service_id: u16) {
55        self.0 = (self.0 & 0xFFFF) | ((service_id as u32) << 16);
56    }
57
58    /// Get the method ID
59    #[inline]
60    #[must_use]
61    pub const fn method_id(&self) -> u16 {
62        (self.0 & 0xFFFF) as u16
63    }
64
65    /// Set the method ID
66    #[inline]
67    pub const fn set_method_id(&mut self, method_id: u16) {
68        self.0 = (self.0 & 0xFFFF_0000) | method_id as u32;
69    }
70
71    /// Message is Event/Notification
72    #[inline]
73    #[must_use]
74    pub const fn is_event(&self) -> bool {
75        self.method_id() & 0x8000 != 0
76    }
77
78    /// Message is SOME/IP Service Discovery
79    #[inline]
80    #[must_use]
81    pub const fn is_sd(&self) -> bool {
82        self.0 == sd::MESSAGE_ID_VALUE
83    }
84}
85
86impl core::fmt::Debug for MessageId {
87    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
88        write!(
89            f,
90            "Message Id: {{ service_id: {:#06X}, method_id: {:#06X} }}",
91            self.service_id(),
92            self.method_id(),
93        )
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    // --- constructors ---
102
103    #[test]
104    fn from_u32() {
105        let mid = MessageId::from(0x1234_5678);
106        assert_eq!(mid.message_id(), 0x1234_5678);
107    }
108
109    #[test]
110    fn new() {
111        let mid = MessageId::new(0xABCD_EF01);
112        assert_eq!(mid.message_id(), 0xABCD_EF01);
113    }
114
115    #[test]
116    fn new_from_service_and_method() {
117        let mid = MessageId::new_from_service_and_method(0x1234, 0x5678);
118        assert_eq!(mid.message_id(), 0x1234_5678);
119        assert_eq!(mid.service_id(), 0x1234);
120        assert_eq!(mid.method_id(), 0x5678);
121    }
122
123    // --- getters / setters ---
124
125    #[test]
126    fn set_message_id() {
127        let mut mid = MessageId::new(0);
128        mid.set_message_id(0xDEAD_BEEF);
129        assert_eq!(mid.message_id(), 0xDEAD_BEEF);
130    }
131
132    #[test]
133    fn set_service_id_preserves_method() {
134        let mut mid = MessageId::new_from_service_and_method(0x0001, 0x00FF);
135        mid.set_service_id(0xAAAA);
136        assert_eq!(mid.service_id(), 0xAAAA);
137        assert_eq!(mid.method_id(), 0x00FF);
138    }
139
140    #[test]
141    fn set_method_id_preserves_service() {
142        let mut mid = MessageId::new_from_service_and_method(0x00FF, 0x0001);
143        mid.set_method_id(0xBBBB);
144        assert_eq!(mid.service_id(), 0x00FF);
145        assert_eq!(mid.method_id(), 0xBBBB);
146    }
147
148    // --- is_event ---
149
150    #[test]
151    fn is_event_true_when_method_high_bit_set() {
152        let mid = MessageId::new_from_service_and_method(0x0001, 0x8001);
153        assert!(mid.is_event());
154    }
155
156    #[test]
157    fn is_event_false_when_method_high_bit_clear() {
158        let mid = MessageId::new_from_service_and_method(0x0001, 0x0001);
159        assert!(!mid.is_event());
160    }
161
162    // --- is_sd ---
163
164    #[test]
165    fn is_sd_true_for_sd_constant() {
166        assert!(MessageId::SD.is_sd());
167    }
168
169    #[test]
170    fn is_sd_false_for_other() {
171        let mid = MessageId::new(0x0001_0001);
172        assert!(!mid.is_sd());
173    }
174
175    // --- SD constant ---
176
177    #[test]
178    fn sd_constant_value() {
179        assert_eq!(MessageId::SD.message_id(), 0xFFFF_8100);
180    }
181
182    // --- Debug ---
183
184    #[test]
185    fn debug_format() {
186        use core::fmt::Write;
187        let mid = MessageId::new_from_service_and_method(0x1234, 0x0001);
188        let mut buf = heapless::String::<128>::new();
189        write!(buf, "{mid:?}").unwrap();
190        assert!(buf.contains("service_id"));
191        assert!(buf.contains("method_id"));
192    }
193}