1use crate::{E2EError, E2EProfile, E2EResult, E2EStatus};
13use crc::{Crc, CRC_32_AUTOSAR};
14
15const BITS_PER_BYTE: u16 = 8;
17const COUNTER_MAX: u16 = 0xFFFF;
18const COUNTER_MODULO: u32 = 0x10000;
19
20#[derive(Debug, Clone)]
22pub struct Profile4Config {
23 pub data_id: u32,
25 pub offset: u16,
27 pub min_data_length: u16,
29 pub max_data_length: u16,
31 pub max_delta_counter: u16,
33}
34
35#[derive(Debug, Clone)]
37pub struct Profile4Check {
38 rx_data_length: u16,
39 rx_counter: u16,
40 rx_data_id: u32,
41 rx_crc: u32,
42 calculated_crc: u32,
43 data_len: u16,
44}
45
46impl Default for Profile4Config {
47 fn default() -> Self {
48 Self {
49 data_id: 0x0a0b0c0d,
50 offset: 0x0000,
51 min_data_length: 96, max_data_length: 32768, max_delta_counter: 1,
54 }
55 }
56}
57
58#[derive(Clone)]
62pub struct Profile4 {
63 config: Profile4Config,
64 counter: u16,
65 initialized: bool,
66}
67
68impl Profile4 {
69 fn validate_config(config: &Profile4Config) -> E2EResult<()> {
71 if config.min_data_length < 12 * BITS_PER_BYTE
72 || 4096 * BITS_PER_BYTE < config.min_data_length
73 {
74 return Err(E2EError::InvalidConfiguration(
75 "Minimum Data length shall be between 12B and 4096B".into(),
76 ));
77 }
78 if config.max_data_length < config.min_data_length || 4096 * 8 < config.max_data_length {
79 return Err(E2EError::InvalidConfiguration(
80 "Maximum Data length shall be between MinDataLength and 4096B".into(),
81 ));
82 }
83 if config.max_delta_counter == 0 || config.max_delta_counter == COUNTER_MAX {
84 return Err(E2EError::InvalidConfiguration(format!(
85 "Max delta counter must be between 1 and {}",
86 COUNTER_MAX
87 )));
88 }
89 Ok(())
90 }
91 fn validate_length(&self, len: u16) -> E2EResult<()> {
93 let min_bytes = self.config.min_data_length / BITS_PER_BYTE;
94 let max_bytes = self.config.max_data_length / BITS_PER_BYTE;
95 if len < min_bytes || max_bytes < len {
96 return Err(E2EError::InvalidDataFormat(format!(
97 "Expected {} - {} bytes, got {} bytes",
98 min_bytes, max_bytes, len
99 )));
100 }
101 Ok(())
102 }
103 fn increment_counter(&mut self) {
104 self.counter = (self.counter as u32 + 1) as u16 & COUNTER_MAX;
105 }
106 fn write_data_length(&self, data: &mut [u8]) {
107 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
108 let len16 = data.len() as u16;
109 data[offset..=offset + 1].copy_from_slice(&len16.to_be_bytes());
110 }
111 fn write_counter(&self, data: &mut [u8]) {
112 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
113 data[offset + 2..=offset + 3].copy_from_slice(&self.counter.to_be_bytes());
114 }
115 fn write_data_id(&self, data: &mut [u8]) {
116 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
117 data[offset + 4..=offset + 7].copy_from_slice(&self.config.data_id.to_be_bytes());
118 }
119 fn compute_crc(&self, data: &[u8]) -> u32 {
120 let crc: Crc<u32> = Crc::<u32>::new(&CRC_32_AUTOSAR);
121 let mut digest = crc.digest();
122 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
123 digest.update(&data[0..offset + 8]); digest.update(&data[(offset + 12)..]); digest.finalize()
126 }
127 fn write_crc(&self, calculated_crc: u32, data: &mut [u8]) {
128 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
129 data[offset + 8..=offset + 11].copy_from_slice(&calculated_crc.to_be_bytes());
130 }
131 fn read_data_length(&self, data: &[u8]) -> u16 {
132 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
133 u16::from_be_bytes([data[offset], data[offset + 1]])
134 }
135 fn read_counter(&self, data: &[u8]) -> u16 {
136 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
137 u16::from_be_bytes([data[offset + 2], data[offset + 3]])
138 }
139 fn read_data_id(&self, data: &[u8]) -> u32 {
140 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
141 u32::from_be_bytes([
142 data[offset + 4],
143 data[offset + 5],
144 data[offset + 6],
145 data[offset + 7],
146 ])
147 }
148 fn read_crc(&self, data: &[u8]) -> u32 {
149 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
150 u32::from_be_bytes([
151 data[offset + 8],
152 data[offset + 9],
153 data[offset + 10],
154 data[offset + 11],
155 ])
156 }
157
158 fn do_checks(&mut self, check_items: Profile4Check) -> E2EStatus {
159 if check_items.calculated_crc != check_items.rx_crc {
160 return E2EStatus::CrcError;
161 }
162 if check_items.rx_data_id != self.config.data_id {
163 return E2EStatus::DataIdError;
164 }
165 if check_items.rx_data_length != check_items.data_len {
166 return E2EStatus::DataLengthError;
167 }
168 let status = self.validate_counter(check_items.rx_counter);
169 self.counter = check_items.rx_counter;
170 status
171 }
172 fn check_counter_delta(&self, received_counter: u16) -> u16 {
174 if received_counter >= self.counter {
175 received_counter - self.counter
176 } else {
177 ((COUNTER_MODULO + received_counter as u32 - self.counter as u32) % COUNTER_MODULO)
179 as u16
180 }
181 }
182 fn validate_counter(&self, rx_counter: u16) -> E2EStatus {
183 let delta = self.check_counter_delta(rx_counter);
184
185 if delta == 0 {
186 if self.initialized {
187 E2EStatus::Repeated
188 } else {
189 E2EStatus::Ok
190 }
191 } else if delta == 1 {
192 E2EStatus::Ok
193 } else if delta >= 2 && delta <= self.config.max_delta_counter {
194 E2EStatus::OkSomeLost
195 } else {
196 E2EStatus::WrongSequence
197 }
198 }
199}
200
201impl E2EProfile for Profile4 {
202 type Config = Profile4Config;
203
204 fn new(config: Self::Config) -> E2EResult<Self> {
205 Self::validate_config(&config)?;
207 Ok(Self {
208 config,
209 counter: 0,
210 initialized: false,
211 })
212 }
213
214 fn protect(&mut self, data: &mut [u8]) -> E2EResult<()> {
215 self.validate_length(data.len() as u16)?;
216 self.write_data_length(data);
217 self.write_counter(data);
218 self.write_data_id(data);
219 let calculated_crc = self.compute_crc(data);
220 self.write_crc(calculated_crc, data);
221 self.increment_counter();
222 Ok(())
223 }
224
225 fn check(&mut self, data: &[u8]) -> E2EResult<E2EStatus> {
226 self.validate_length(data.len() as u16)?;
228 let check_items = Profile4Check {
229 rx_data_length: self.read_data_length(data),
230 rx_counter: self.read_counter(data),
231 rx_crc: self.read_crc(data),
232 rx_data_id: self.read_data_id(data),
233 calculated_crc: self.compute_crc(data),
234 data_len: data.len() as u16,
235 };
236 let status = self.do_checks(check_items);
237 if !self.initialized && matches!(status, E2EStatus::Ok | E2EStatus::OkSomeLost) {
238 self.initialized = true;
239 }
240 Ok(status)
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247 #[test]
248 fn test_profile4_basic_example() {
249 let mut profile_tx = Profile4::new(Profile4Config::default()).unwrap();
250 let mut profile_rx = Profile4::new(Profile4Config::default()).unwrap();
251
252 let mut data = vec![
253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
254 0x00, 0x00,
255 ];
256 profile_tx.protect(&mut data).unwrap();
257 assert_eq!(data[0], 0x00);
259 assert_eq!(data[1], 0x10);
260 assert_eq!(data[2], 0x00);
262 assert_eq!(data[3], 0x00);
263 assert_eq!(data[4], 0x0a);
265 assert_eq!(data[5], 0x0b);
266 assert_eq!(data[6], 0x0c);
267 assert_eq!(data[7], 0x0d);
268 assert_eq!(data[8], 0x86);
270 assert_eq!(data[9], 0x2b);
271 assert_eq!(data[10], 0x05);
272 assert_eq!(data[11], 0x56);
273 assert_eq!(data[12], 0x00);
275 assert_eq!(data[13], 0x00);
276 assert_eq!(data[14], 0x00);
277 assert_eq!(data[15], 0x00);
278 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
279 }
280
281 #[test]
282 fn test_profile4_offset_example() {
283 let config = Profile4Config {
284 offset: 64,
285 ..Default::default()
286 };
287
288 let mut profile_tx = Profile4::new(config.clone()).unwrap();
289 let mut profile_rx = Profile4::new(config).unwrap();
290
291 let mut data = vec![
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 ];
295 profile_tx.protect(&mut data).unwrap();
296 assert_eq!(data[8], 0x00);
298 assert_eq!(data[9], 0x18);
299 assert_eq!(data[10], 0x00);
301 assert_eq!(data[11], 0x00);
302 assert_eq!(data[12], 0x0a);
304 assert_eq!(data[13], 0x0b);
305 assert_eq!(data[14], 0x0c);
306 assert_eq!(data[15], 0x0d);
307 assert_eq!(data[16], 0x69);
309 assert_eq!(data[17], 0xd7);
310 assert_eq!(data[18], 0x50);
311 assert_eq!(data[19], 0x2e);
312 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
313 }
314 #[test]
315 fn test_profile4_counter_wraparound() {
316 let config = Profile4Config {
317 offset: 64,
318 ..Default::default()
319 };
320
321 let mut profile_tx = Profile4::new(config.clone()).unwrap();
322 let mut profile_rx = Profile4::new(config).unwrap();
323
324 let mut data = vec![
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 ];
328 profile_tx.protect(&mut data).unwrap();
329 assert_eq!(data[10], 0x00);
331 assert_eq!(data[11], 0x00);
332 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
333 for i in 1u16..=0xFFFF {
334 profile_tx.protect(&mut data).unwrap();
335 assert_eq!(data[10], i.to_be_bytes()[0]);
337 assert_eq!(data[11], i.to_be_bytes()[1]);
338 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
339 }
340 profile_tx.protect(&mut data).unwrap();
341 assert_eq!(data[10], 0x00);
343 assert_eq!(data[11], 0x00);
344 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
345 }
346}