simple_someip/protocol/sd/
header.rs1use std::net::Ipv4Addr;
2
3use crate::protocol::byte_order::{ReadBytesExt, WriteBytesExt};
4
5use crate::{protocol::Error, traits::WireFormat};
6
7use super::{
8 Entry, EventGroupEntry, Flags, Options, ServiceEntry, TransportProtocol,
9 entry::{ENTRY_SIZE, OptionsCount},
10};
11
12pub const MAX_SD_ENTRIES: usize = 1;
14pub const MAX_SD_OPTIONS: usize = 1;
16
17pub type SdEntries<const N: usize = MAX_SD_ENTRIES> = heapless::Vec<Entry, N>;
18pub type SdOptions<const N: usize = MAX_SD_OPTIONS> = heapless::Vec<Options, N>;
19
20#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct Header<
22 const MAX_ENTRIES: usize = MAX_SD_ENTRIES,
23 const MAX_OPTIONS: usize = MAX_SD_OPTIONS,
24> {
25 pub flags: Flags,
26 pub entries: SdEntries<MAX_ENTRIES>,
27 pub options: SdOptions<MAX_OPTIONS>,
28}
29
30impl<const E: usize, const O: usize> Header<E, O> {
31 #[must_use]
32 pub fn new(flags: Flags, entries: SdEntries<E>, options: SdOptions<O>) -> Self {
33 Self {
34 flags,
35 entries,
36 options,
37 }
38 }
39
40 #[allow(clippy::too_many_arguments)]
41 #[must_use]
42 pub fn new_service_offer(
43 service_id: u16,
44 instance_id: u16,
45 major_version: u8,
46 minor_version: u32,
47 ttl: u32,
48 client_ip: Ipv4Addr,
49 protocol: TransportProtocol,
50 client_port: u16,
51 ) -> Self {
52 let entry = Entry::OfferService(ServiceEntry {
53 service_id,
54 instance_id,
55 major_version,
56 ttl,
57 index_first_options_run: 0,
58 index_second_options_run: 0,
59 options_count: OptionsCount::new(1, 0),
60 minor_version,
61 });
62 let endpoint = Options::IpV4Endpoint {
63 ip: client_ip,
64 protocol,
65 port: client_port,
66 };
67 let mut entries = SdEntries::new();
68 let mut options = SdOptions::new();
69 entries
70 .push(entry)
71 .expect("single SD entry exceeds capacity");
72 options
73 .push(endpoint)
74 .expect("single SD option exceeds capacity");
75 Self {
76 flags: Flags::new_sd(false),
77 entries,
78 options,
79 }
80 }
81
82 #[must_use]
85 pub fn new_find_services(reboot: bool, service_ids: &[u16]) -> Self {
86 let mut entries = SdEntries::new();
87 for service_id in service_ids {
88 entries
89 .push(Entry::FindService(ServiceEntry::find(*service_id)))
90 .expect("too many service IDs for SD header");
91 }
92 Self {
93 flags: Flags::new_sd(reboot),
94 entries,
95 options: SdOptions::new(),
96 }
97 }
98
99 #[allow(clippy::too_many_arguments)]
100 #[must_use]
101 pub fn new_subscription(
102 service_id: u16,
103 instance_id: u16,
104 major_version: u8,
105 ttl: u32,
106 event_group_id: u16,
107 client_ip: Ipv4Addr,
108 protocol: TransportProtocol,
109 client_port: u16,
110 ) -> Self {
111 let entry = Entry::SubscribeEventGroup(EventGroupEntry::new(
112 service_id,
113 instance_id,
114 major_version,
115 ttl,
116 event_group_id,
117 ));
118 let endpoint = Options::IpV4Endpoint {
119 ip: client_ip,
120 protocol,
121 port: client_port,
122 };
123 let mut entries = SdEntries::new();
124 let mut options = SdOptions::new();
125 entries
126 .push(entry)
127 .expect("single SD entry exceeds capacity");
128 options
129 .push(endpoint)
130 .expect("single SD option exceeds capacity");
131 Self {
132 flags: Flags::new_sd(false),
133 entries,
134 options,
135 }
136 }
137
138 #[must_use]
139 pub fn subscribe_ack(
140 service_id: u16,
141 instance_id: u16,
142 major_version: u8,
143 ttl: u32,
144 event_group_id: u16,
145 ) -> Self {
146 let entry = Entry::SubscribeAckEventGroup(EventGroupEntry::new(
147 service_id,
148 instance_id,
149 major_version,
150 ttl,
151 event_group_id,
152 ));
153 let mut entries = SdEntries::new();
154 entries
155 .push(entry)
156 .expect("single SD entry exceeds capacity");
157 Self {
158 flags: Flags::new_sd(true),
159 entries,
160 options: SdOptions::new(),
161 }
162 }
163}
164
165impl<const E: usize, const O: usize> WireFormat for Header<E, O> {
166 fn decode<T: embedded_io::Read>(reader: &mut T) -> Result<Self, crate::protocol::Error> {
167 const MIN_OPTION_SIZE: usize = 4;
168 let flags = Flags::from(reader.read_u8()?);
169 let mut reserved: [u8; 3] = [0; 3];
170 reader.read_bytes(&mut reserved)?;
171 let entries_size = reader.read_u32_be()?;
172 let entries_count = entries_size / u32::try_from(ENTRY_SIZE).expect("constant fits u32");
173 let mut entries = SdEntries::new();
174 for _i in 0..entries_count {
175 entries
176 .push(Entry::decode(reader)?)
177 .map_err(|_| Error::TooManyEntries)?;
178 }
179
180 let mut remaining_options_size = reader.read_u32_be()? as usize;
181 let mut options = SdOptions::new();
182 while remaining_options_size > 0 {
184 if remaining_options_size < MIN_OPTION_SIZE {
185 return Err(Error::IncorrectOptionsSize(remaining_options_size));
186 }
187 let option = Options::read(reader)?;
188 let option_size = option.size();
189 if option_size > remaining_options_size {
190 return Err(Error::IncorrectOptionsSize(remaining_options_size));
191 }
192 remaining_options_size -= option_size;
193 options.push(option).map_err(|_| Error::TooManyOptions)?;
194 }
195 Ok(Self {
196 flags,
197 entries,
198 options,
199 })
200 }
201
202 fn required_size(&self) -> usize {
203 let mut size = 12 + self.entries.len() * ENTRY_SIZE;
204 for option in &self.options {
205 size += option.size();
206 }
207 size
208 }
209
210 fn encode<T: embedded_io::Write>(
211 &self,
212 writer: &mut T,
213 ) -> Result<usize, crate::protocol::Error> {
214 writer.write_u8(u8::from(self.flags))?;
215 let reserved: [u8; 3] = [0; 3];
216 writer.write_bytes(&reserved)?;
217 let entries_size = u32::try_from(self.entries.len() * 16).expect("entries size fits u32");
218 writer.write_u32_be(entries_size)?;
219 for entry in &self.entries {
220 entry.encode(writer)?;
221 }
222 let mut options_size = 0;
223 for option in &self.options {
224 options_size += option.size();
225 }
226 writer.write_u32_be(u32::try_from(options_size).expect("options size fits u32"))?;
227 for option in &self.options {
228 option.write(writer)?;
229 }
230 Ok(12 + entries_size as usize + options_size)
231 }
232}