Skip to main content

simple_someip/protocol/sd/
entry.rs

1use crate::{
2    protocol::{
3        Error,
4        byte_order::{ReadBytesExt, WriteBytesExt},
5    },
6    traits::WireFormat,
7};
8
9pub const ENTRY_SIZE: usize = 16;
10
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12enum EntryType {
13    FindService,
14    OfferService,
15    StopOfferService,
16    Subscribe,
17    SubscribeAck,
18}
19
20impl TryFrom<u8> for EntryType {
21    type Error = Error;
22    fn try_from(value: u8) -> Result<Self, Error> {
23        match value {
24            0x00 => Ok(EntryType::FindService),
25            0x01 => Ok(EntryType::OfferService),
26            0x02 => Ok(EntryType::StopOfferService),
27            0x06 => Ok(EntryType::Subscribe),
28            0x07 => Ok(EntryType::SubscribeAck),
29            _ => Err(Error::InvalidSDEntryType(value)),
30        }
31    }
32}
33
34impl From<EntryType> for u8 {
35    fn from(service_entry_type: EntryType) -> u8 {
36        match service_entry_type {
37            EntryType::FindService => 0x00,
38            EntryType::OfferService => 0x01,
39            EntryType::StopOfferService => 0x02,
40            EntryType::Subscribe => 0x06,
41            EntryType::SubscribeAck => 0x07,
42        }
43    }
44}
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47pub struct OptionsCount {
48    pub first_options_count: u8,
49    pub second_options_count: u8,
50}
51
52impl From<u8> for OptionsCount {
53    fn from(value: u8) -> Self {
54        let first_options_count = (value & 0xf0) >> 4;
55        let second_options_count = value & 0x0f;
56
57        Self {
58            first_options_count,
59            second_options_count,
60        }
61    }
62}
63
64impl From<OptionsCount> for u8 {
65    fn from(options_count: OptionsCount) -> u8 {
66        ((options_count.first_options_count << 4) & 0xf0)
67            | (options_count.second_options_count & 0x0f)
68    }
69}
70
71impl OptionsCount {
72    #[must_use]
73    pub fn new(first_options_count: u8, second_options_count: u8) -> Self {
74        assert!(first_options_count < 16);
75        assert!(second_options_count < 16);
76        OptionsCount {
77            first_options_count,
78            second_options_count,
79        }
80    }
81}
82
83#[derive(Clone, Debug, Eq, PartialEq)]
84pub struct EventGroupEntry {
85    pub index_first_options_run: u8,
86    pub index_second_options_run: u8,
87    pub options_count: OptionsCount,
88    pub service_id: u16,
89    pub instance_id: u16,
90    pub major_version: u8,
91    /// ttl is a u24 value
92    pub ttl: u32,
93    pub counter: u16,
94    pub event_group_id: u16,
95}
96
97impl EventGroupEntry {
98    #[must_use]
99    pub fn new(
100        service_id: u16,
101        instance_id: u16,
102        major_version: u8,
103        ttl: u32,
104        event_group_id: u16,
105    ) -> Self {
106        Self {
107            index_first_options_run: 0,
108            index_second_options_run: 0,
109            options_count: OptionsCount::new(1, 0),
110            service_id,
111            instance_id,
112            major_version,
113            ttl,
114            counter: 0,
115            event_group_id,
116        }
117    }
118}
119
120impl WireFormat for EventGroupEntry {
121    fn decode<T: embedded_io::Read>(reader: &mut T) -> Result<Self, crate::protocol::Error> {
122        let index_first_options_run = reader.read_u8()?;
123        let index_second_options_run = reader.read_u8()?;
124        let options_count = OptionsCount::from(reader.read_u8()?);
125        let service_id = reader.read_u16_be()?;
126        let instance_id = reader.read_u16_be()?;
127        let major_version = reader.read_u8()?;
128        let ttl = reader.read_u24_be()?;
129        let counter = reader.read_u16_be()? & 0x000f;
130        let event_group_id = reader.read_u16_be()?;
131        Ok(Self {
132            index_first_options_run,
133            index_second_options_run,
134            options_count,
135            service_id,
136            instance_id,
137            major_version,
138            ttl,
139            counter,
140            event_group_id,
141        })
142    }
143
144    fn required_size(&self) -> usize {
145        16
146    }
147
148    fn encode<T: embedded_io::Write>(
149        &self,
150        writer: &mut T,
151    ) -> Result<usize, crate::protocol::Error> {
152        writer.write_u8(self.index_first_options_run)?;
153        writer.write_u8(self.index_second_options_run)?;
154        writer.write_u8(u8::from(self.options_count))?;
155        writer.write_u16_be(self.service_id)?;
156        writer.write_u16_be(self.instance_id)?;
157        writer.write_u8(self.major_version)?;
158        writer.write_u24_be(self.ttl)?;
159        writer.write_u16_be(self.counter)?;
160        writer.write_u16_be(self.event_group_id)?;
161        Ok(16)
162    }
163}
164
165#[derive(Clone, Debug, Eq, PartialEq)]
166pub struct ServiceEntry {
167    pub index_first_options_run: u8,
168    pub index_second_options_run: u8,
169    pub options_count: OptionsCount,
170    pub service_id: u16,
171    pub instance_id: u16,
172    pub major_version: u8,
173    /// ttl is a u24 value
174    pub ttl: u32,
175    pub minor_version: u32,
176}
177
178impl ServiceEntry {
179    #[must_use]
180    pub fn find(service_id: u16) -> Self {
181        Self {
182            index_first_options_run: 0,
183            index_second_options_run: 0,
184            options_count: OptionsCount::new(1, 0),
185            service_id,
186            instance_id: 0xFFFF,
187            major_version: 0xFF,
188            ttl: 0x00FF_FFFF,
189            minor_version: 0xFFFF_FFFF,
190        }
191    }
192}
193
194impl WireFormat for ServiceEntry {
195    fn decode<R: embedded_io::Read>(reader: &mut R) -> Result<Self, Error> {
196        let index_first_options_run = reader.read_u8()?;
197        let index_second_options_run = reader.read_u8()?;
198        let options_count = OptionsCount::from(reader.read_u8()?);
199        let service_id = reader.read_u16_be()?;
200        let instance_id = reader.read_u16_be()?;
201        let major_version = reader.read_u8()?;
202        let ttl = reader.read_u24_be()?;
203        let minor_version = reader.read_u32_be()?;
204        Ok(Self {
205            index_first_options_run,
206            index_second_options_run,
207            options_count,
208            service_id,
209            instance_id,
210            major_version,
211            ttl,
212            minor_version,
213        })
214    }
215
216    fn required_size(&self) -> usize {
217        16
218    }
219
220    fn encode<W: embedded_io::Write>(&self, writer: &mut W) -> Result<usize, Error> {
221        writer.write_u8(self.index_first_options_run)?;
222        writer.write_u8(self.index_second_options_run)?;
223        writer.write_u8(u8::from(self.options_count))?;
224        writer.write_u16_be(self.service_id)?;
225        writer.write_u16_be(self.instance_id)?;
226        writer.write_u8(self.major_version)?;
227        writer.write_u24_be(self.ttl)?;
228        writer.write_u32_be(self.minor_version)?;
229        Ok(16)
230    }
231}
232
233#[derive(Clone, Debug, Eq, PartialEq)]
234pub enum Entry {
235    FindService(ServiceEntry),
236    OfferService(ServiceEntry),
237    StopOfferService(ServiceEntry),
238    SubscribeEventGroup(EventGroupEntry),
239    SubscribeAckEventGroup(EventGroupEntry),
240}
241
242impl Entry {
243    #[must_use]
244    pub fn first_options_count(&self) -> u8 {
245        match self {
246            Entry::FindService(service_entry)
247            | Entry::OfferService(service_entry)
248            | Entry::StopOfferService(service_entry) => {
249                service_entry.options_count.first_options_count
250            }
251            Entry::SubscribeEventGroup(event_group_entry)
252            | Entry::SubscribeAckEventGroup(event_group_entry) => {
253                event_group_entry.options_count.first_options_count
254            }
255        }
256    }
257
258    #[must_use]
259    pub fn second_options_count(&self) -> u8 {
260        match self {
261            Entry::FindService(service_entry)
262            | Entry::OfferService(service_entry)
263            | Entry::StopOfferService(service_entry) => {
264                service_entry.options_count.second_options_count
265            }
266            Entry::SubscribeEventGroup(event_group_entry)
267            | Entry::SubscribeAckEventGroup(event_group_entry) => {
268                event_group_entry.options_count.second_options_count
269            }
270        }
271    }
272
273    #[must_use]
274    pub fn total_options_count(&self) -> u8 {
275        self.first_options_count() + self.second_options_count()
276    }
277}
278
279impl WireFormat for Entry {
280    fn decode<R: embedded_io::Read>(reader: &mut R) -> Result<Self, Error> {
281        let entry_type = EntryType::try_from(reader.read_u8()?)?;
282        match entry_type {
283            EntryType::FindService => {
284                let service_entry = ServiceEntry::decode(reader)?;
285                Ok(Entry::FindService(service_entry))
286            }
287            EntryType::OfferService => {
288                let service_entry = ServiceEntry::decode(reader)?;
289                Ok(Entry::OfferService(service_entry))
290            }
291            EntryType::StopOfferService => {
292                let service_entry = ServiceEntry::decode(reader)?;
293                Ok(Entry::StopOfferService(service_entry))
294            }
295            EntryType::Subscribe => {
296                let event_group_entry = EventGroupEntry::decode(reader)?;
297                Ok(Entry::SubscribeEventGroup(event_group_entry))
298            }
299            EntryType::SubscribeAck => {
300                let event_group_entry = EventGroupEntry::decode(reader)?;
301                Ok(Entry::SubscribeAckEventGroup(event_group_entry))
302            }
303        }
304    }
305
306    fn required_size(&self) -> usize {
307        1 + match self {
308            Entry::FindService(service_entry)
309            | Entry::OfferService(service_entry)
310            | Entry::StopOfferService(service_entry) => service_entry.required_size(),
311            Entry::SubscribeEventGroup(event_group_entry)
312            | Entry::SubscribeAckEventGroup(event_group_entry) => event_group_entry.required_size(),
313        }
314    }
315
316    fn encode<W: embedded_io::Write>(&self, writer: &mut W) -> Result<usize, Error> {
317        match self {
318            Entry::FindService(service_entry) => {
319                writer.write_u8(u8::from(EntryType::FindService))?;
320                service_entry.encode(writer)
321            }
322            Entry::OfferService(service_entry) => {
323                writer.write_u8(u8::from(EntryType::OfferService))?;
324                service_entry.encode(writer)
325            }
326            Entry::StopOfferService(service_entry) => {
327                writer.write_u8(u8::from(EntryType::StopOfferService))?;
328                service_entry.encode(writer)
329            }
330            Entry::SubscribeEventGroup(event_group_entry) => {
331                writer.write_u8(u8::from(EntryType::Subscribe))?;
332                event_group_entry.encode(writer)
333            }
334            Entry::SubscribeAckEventGroup(event_group_entry) => {
335                writer.write_u8(u8::from(EntryType::SubscribeAck))?;
336                event_group_entry.encode(writer)
337            }
338        }
339    }
340}