1use crate::{E2EError, E2EProfile, E2EResult, E2EStatus};
13use crc::{Crc, CRC_32_AUTOSAR};
14
15const BITS_PER_BYTE: u32 = 8;
17const COUNTER_MAX: u32 = 0xFFFFFFFF;
18const COUNTER_MODULO: u64 = 0x100000000;
19
20#[derive(Debug, Clone)]
22pub struct Profile8Config {
23 pub data_id: u32,
25 pub offset: u32,
27 pub min_data_length: u32,
29 pub max_data_length: u32,
31 pub max_delta_counter: u32,
33}
34
35#[derive(Debug, Clone)]
37pub struct Profile8Check {
38 rx_data_length: u32,
39 rx_counter: u32,
40 rx_data_id: u32,
41 rx_crc: u32,
42 calculated_crc: u32,
43 data_len: u32,
44}
45
46impl Default for Profile8Config {
47 fn default() -> Self {
48 Self {
49 data_id: 0x0a0b0c0d,
50 offset: 0x00000000,
51 min_data_length: 128, max_data_length: 4294967295, max_delta_counter: 1,
54 }
55 }
56}
57
58#[derive(Clone)]
62pub struct Profile8 {
63 config: Profile8Config,
64 counter: u32,
65 initialized: bool,
66}
67
68impl Profile8 {
69 fn validate_config(config: &Profile8Config) -> E2EResult<()> {
71 if config.min_data_length < 16 * BITS_PER_BYTE {
72 return Err(E2EError::InvalidConfiguration(
73 "Minimum Data length shall be larger than 16B".into(),
74 ));
75 }
76 if config.max_data_length < config.min_data_length {
77 return Err(E2EError::InvalidConfiguration(
78 "Maximum Data length shall be larger than MinDataLength".into(),
79 ));
80 }
81 if config.max_delta_counter == 0 || config.max_delta_counter == COUNTER_MAX {
82 return Err(E2EError::InvalidConfiguration(format!(
83 "Max delta counter must be between 1 and {}",
84 COUNTER_MAX
85 )));
86 }
87 Ok(())
88 }
89 fn validate_length(&self, len: u32) -> E2EResult<()> {
91 let min_bytes = self.config.min_data_length / BITS_PER_BYTE;
92 let max_bytes = self.config.max_data_length / BITS_PER_BYTE;
93 if len < min_bytes || max_bytes < len {
94 return Err(E2EError::InvalidDataFormat(format!(
95 "Expected {} - {} bytes, got {} bytes",
96 min_bytes, max_bytes, len
97 )));
98 }
99 Ok(())
100 }
101 fn write_data_length(&self, data: &mut [u8]) {
102 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
103 let len32 = data.len() as u32;
104 data[offset + 4..=offset + 7].copy_from_slice(&len32.to_be_bytes());
105 }
106 fn write_counter(&self, data: &mut [u8]) {
107 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
108 data[offset + 8..=offset + 11].copy_from_slice(&self.counter.to_be_bytes());
109 }
110 fn write_data_id(&self, data: &mut [u8]) {
111 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
112 data[offset + 12..=offset + 15].copy_from_slice(&self.config.data_id.to_be_bytes());
113 }
114 fn compute_crc(&self, data: &[u8]) -> u32 {
115 let crc: Crc<u32> = Crc::<u32>::new(&CRC_32_AUTOSAR);
116 let mut digest = crc.digest();
117 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
118 digest.update(&data[0..offset]); digest.update(&data[(offset + 4)..]); digest.finalize()
121 }
122 fn write_crc(&self, calculated_crc: u32, data: &mut [u8]) {
123 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
124 data[offset..=offset + 3].copy_from_slice(&calculated_crc.to_be_bytes());
125 }
126 fn increment_counter(&mut self) {
127 self.counter = if self.counter == COUNTER_MAX {
128 0x00000000
129 } else {
130 (self.counter + 1) & COUNTER_MAX
131 };
132 }
133
134 fn read_data_length(&self, data: &[u8]) -> u32 {
135 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
136 u32::from_be_bytes([
137 data[offset + 4],
138 data[offset + 5],
139 data[offset + 6],
140 data[offset + 7],
141 ])
142 }
143 fn read_counter(&self, data: &[u8]) -> u32 {
144 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
145 u32::from_be_bytes([
146 data[offset + 8],
147 data[offset + 9],
148 data[offset + 10],
149 data[offset + 11],
150 ])
151 }
152 fn read_data_id(&self, data: &[u8]) -> u32 {
153 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
154 u32::from_be_bytes([
155 data[offset + 12],
156 data[offset + 13],
157 data[offset + 14],
158 data[offset + 15],
159 ])
160 }
161 fn read_crc(&self, data: &[u8]) -> u32 {
162 let offset = (self.config.offset / BITS_PER_BYTE) as usize;
163 u32::from_be_bytes([
164 data[offset],
165 data[offset + 1],
166 data[offset + 2],
167 data[offset + 3],
168 ])
169 }
170
171 fn do_checks(&mut self, check_items: Profile8Check) -> E2EStatus {
172 if check_items.calculated_crc != check_items.rx_crc {
173 return E2EStatus::CrcError;
174 }
175 if check_items.rx_data_id != self.config.data_id {
176 return E2EStatus::DataIdError;
177 }
178 if check_items.rx_data_length != check_items.data_len {
179 return E2EStatus::DataLengthError;
180 }
181 let status = self.validate_counter(check_items.rx_counter);
182 self.counter = check_items.rx_counter;
183 status
184 }
185 fn check_counter_delta(&self, received_counter: u32) -> u32 {
187 if received_counter >= self.counter {
188 received_counter - self.counter
189 } else {
190 ((COUNTER_MODULO + received_counter as u64 - self.counter as u64) % COUNTER_MODULO)
192 as u32
193 }
194 }
195 fn validate_counter(&self, rx_counter: u32) -> E2EStatus {
196 let delta = self.check_counter_delta(rx_counter);
197
198 if delta == 0 {
199 if self.initialized {
200 E2EStatus::Repeated
201 } else {
202 E2EStatus::Ok
203 }
204 } else if delta == 1 {
205 E2EStatus::Ok
206 } else if delta >= 2 && delta <= self.config.max_delta_counter {
207 E2EStatus::OkSomeLost
208 } else {
209 E2EStatus::WrongSequence
210 }
211 }
212}
213
214impl E2EProfile for Profile8 {
215 type Config = Profile8Config;
216
217 fn new(config: Self::Config) -> E2EResult<Self> {
218 Self::validate_config(&config)?;
220 Ok(Self {
221 config,
222 counter: 0,
223 initialized: false,
224 })
225 }
226
227 fn protect(&mut self, data: &mut [u8]) -> E2EResult<()> {
228 self.validate_length(data.len() as u32)?;
229 self.write_data_length(data);
230 self.write_counter(data);
231 self.write_data_id(data);
232 let calculated_crc = self.compute_crc(data);
233 self.write_crc(calculated_crc, data);
234 self.increment_counter();
235 Ok(())
236 }
237
238 fn check(&mut self, data: &[u8]) -> E2EResult<E2EStatus> {
239 self.validate_length(data.len() as u32)?;
241 let check_items = Profile8Check {
242 rx_data_length: self.read_data_length(data),
243 rx_counter: self.read_counter(data),
244 rx_crc: self.read_crc(data),
245 rx_data_id: self.read_data_id(data),
246 calculated_crc: self.compute_crc(data),
247 data_len: data.len() as u32,
248 };
249 let status = self.do_checks(check_items);
250 if !self.initialized && matches!(status, E2EStatus::Ok | E2EStatus::OkSomeLost) {
251 self.initialized = true;
252 }
253 Ok(status)
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 #[test]
261 fn test_profile8_basic_example() {
262 let mut profile_tx = Profile8::new(Profile8Config::default()).unwrap();
263 let mut profile_rx = Profile8::new(Profile8Config::default()).unwrap();
264
265 let mut data = vec![
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 ];
269 profile_tx.protect(&mut data).unwrap();
270 assert_eq!(data[0], 0x41);
272 assert_eq!(data[1], 0x49);
273 assert_eq!(data[2], 0x4e);
274 assert_eq!(data[3], 0x52);
275 assert_eq!(data[4], 0x00);
277 assert_eq!(data[5], 0x00);
278 assert_eq!(data[6], 0x00);
279 assert_eq!(data[7], 0x14);
280 assert_eq!(data[8], 0x00);
282 assert_eq!(data[9], 0x00);
283 assert_eq!(data[10], 0x00);
284 assert_eq!(data[11], 0x00);
285 assert_eq!(data[12], 0x0a);
287 assert_eq!(data[13], 0x0b);
288 assert_eq!(data[14], 0x0c);
289 assert_eq!(data[15], 0x0d);
290 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
291 }
292
293 #[test]
294 fn test_profile8_offset_example() {
295 let config = Profile8Config {
296 offset: 64,
297 ..Default::default()
298 };
299
300 let mut profile_tx = Profile8::new(config.clone()).unwrap();
301 let mut profile_rx = Profile8::new(config).unwrap();
302
303 let mut data = vec![
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 ];
307 profile_tx.protect(&mut data).unwrap();
308 assert_eq!(data[8], 0xe8);
310 assert_eq!(data[9], 0x91);
311 assert_eq!(data[10], 0xe5);
312 assert_eq!(data[11], 0xa8);
313 assert_eq!(data[12], 0x00);
315 assert_eq!(data[13], 0x00);
316 assert_eq!(data[14], 0x00);
317 assert_eq!(data[15], 0x1c);
318 assert_eq!(data[16], 0x00);
320 assert_eq!(data[17], 0x00);
321 assert_eq!(data[18], 0x00);
322 assert_eq!(data[19], 0x00);
323 assert_eq!(data[20], 0x0a);
325 assert_eq!(data[21], 0x0b);
326 assert_eq!(data[22], 0x0c);
327 assert_eq!(data[23], 0x0d);
328 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
329 }
330 #[test]
331 fn test_profile8_counter_wraparound() {
332 let config = Profile8Config {
333 offset: 64,
334 ..Default::default()
335 };
336
337 let mut profile_tx = Profile8::new(config.clone()).unwrap();
338 let mut profile_rx = Profile8::new(config).unwrap();
339
340 let mut data = vec![
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 ];
344 profile_tx.protect(&mut data).unwrap();
345 assert_eq!(data[16], 0x00);
347 assert_eq!(data[17], 0x00);
348 assert_eq!(data[18], 0x00);
349 assert_eq!(data[19], 0x00);
350 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
351 profile_tx.protect(&mut data).unwrap();
352 assert_eq!(data[16], 0x00);
354 assert_eq!(data[17], 0x00);
355 assert_eq!(data[18], 0x00);
356 assert_eq!(data[19], 0x01);
357 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
358 profile_rx.counter = 0xFFFFFFFE;
359 profile_tx.counter = 0xFFFFFFFF;
360 profile_tx.protect(&mut data).unwrap();
361 assert_eq!(data[16], 0xFF);
363 assert_eq!(data[17], 0xFF);
364 assert_eq!(data[18], 0xFF);
365 assert_eq!(data[19], 0xFF);
366 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
367 profile_tx.protect(&mut data).unwrap();
368 assert_eq!(data[16], 0x00);
370 assert_eq!(data[17], 0x00);
371 assert_eq!(data[18], 0x00);
372 assert_eq!(data[19], 0x00);
373 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
374 }
375}