1use crate::{E2EError, E2EProfile, E2EResult, E2EStatus};
14use crc::{Crc, CRC_8_AUTOSAR};
15
16const COUNTER_MASK: u8 = 0x0F;
18const COUNTER_MAX: u8 = 15;
19const COUNTER_MODULO: u8 = 16;
20const BITS_PER_BYTE: usize = 8;
21const DATA_ID_NUMBER: usize = 16;
22
23#[derive(Debug, Clone)]
25pub struct Profile22Config {
26 pub data_length: usize,
28 pub data_id_list: [u8; DATA_ID_NUMBER],
30 pub max_delta_counter: u8,
32 pub offset: usize,
34}
35
36impl Default for Profile22Config {
37 fn default() -> Self {
38 Self {
39 data_length: 64, data_id_list: [
41 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
42 0x0f, 0x10,
43 ],
44 max_delta_counter: 1,
45 offset: 0, }
47 }
48}
49
50#[derive(Debug, Clone)]
52pub struct Profile22Check {
53 rx_counter: u8,
54 rx_crc: u8,
55 calculated_crc: u8,
56}
57#[derive(Clone)]
61pub struct Profile22 {
62 config: Profile22Config,
63 counter: u8,
64}
65
66impl Profile22 {
67 fn validate_config(config: &Profile22Config) -> E2EResult<()> {
69 if !config.data_length.is_multiple_of(BITS_PER_BYTE) {
70 return Err(E2EError::InvalidConfiguration(
71 "Data length shall be a multiple of 8".into(),
72 ));
73 }
74
75 if config.max_delta_counter == 0 || config.max_delta_counter > COUNTER_MAX {
76 return Err(E2EError::InvalidConfiguration(format!(
77 "Max delta counter must be between 1 and {}",
78 COUNTER_MAX
79 )));
80 }
81
82 Ok(())
83 }
84 fn validate_length(&self, len: usize) -> E2EResult<()> {
86 let expected_bytes = self.config.data_length / BITS_PER_BYTE;
87 if len != expected_bytes {
88 return Err(E2EError::InvalidDataFormat(format!(
89 "Expected {} bytes, got {} bytes",
90 expected_bytes, len
91 )));
92 }
93 Ok(())
94 }
95 fn increment_counter(&mut self) {
96 self.counter = (self.counter + 1) % COUNTER_MODULO;
97 }
98 fn write_counter(&self, data: &mut [u8]) {
99 let byte_idx = self.config.offset >> 3;
100
101 data[byte_idx + 1] = (data[byte_idx + 1] & 0xF0) | self.counter;
102 }
103 fn read_counter(&self, data: &[u8]) -> u8 {
104 let byte_idx = self.config.offset >> 3;
105
106 data[byte_idx + 1] & COUNTER_MASK
107 }
108 fn write_crc(&self, calculated_crc: u8, data: &mut [u8]) {
109 let byte_position = self.config.offset / BITS_PER_BYTE;
110 data[byte_position] = calculated_crc;
111 }
112 fn read_crc(&self, data: &[u8]) -> u8 {
113 let byte_position = self.config.offset / BITS_PER_BYTE;
114 data[byte_position]
115 }
116 fn compute_crc(&self, data: &[u8]) -> u8 {
117 let crc: Crc<u8> = Crc::<u8>::new(&CRC_8_AUTOSAR);
118 let mut digest = crc.digest();
119 let offset_byte = self.config.offset / BITS_PER_BYTE;
120 digest.update(&data[0..offset_byte]); digest.update(&data[(offset_byte + 1)..]); digest.update(&[self.config.data_id_list[self.read_counter(data) as usize]]); digest.finalize()
124 }
125 fn do_checks(&mut self, check_items: Profile22Check) -> E2EStatus {
126 if check_items.calculated_crc != check_items.rx_crc {
127 return E2EStatus::CrcError;
128 }
129 let status = self.validate_counter(check_items.rx_counter);
130 self.counter = check_items.rx_counter;
131 status
132 }
133 fn check_counter_delta(&self, received_counter: u8) -> u8 {
135 if received_counter >= self.counter {
136 received_counter - self.counter
137 } else {
138 (COUNTER_MODULO + received_counter - self.counter) % COUNTER_MODULO
140 }
141 }
142 fn validate_counter(&self, rx_counter: u8) -> E2EStatus {
143 let delta = self.check_counter_delta(rx_counter);
144
145 if delta == 0 {
146 E2EStatus::Repeated
147 } else if delta == 1 {
148 E2EStatus::Ok
149 } else if delta >= 2 && delta <= self.config.max_delta_counter {
150 E2EStatus::OkSomeLost
151 } else {
152 E2EStatus::WrongSequence
153 }
154 }
155}
156
157impl E2EProfile for Profile22 {
158 type Config = Profile22Config;
159
160 fn new(config: Self::Config) -> E2EResult<Self> {
161 Self::validate_config(&config)?;
163 Ok(Self { config, counter: 0 })
164 }
165
166 fn protect(&mut self, data: &mut [u8]) -> E2EResult<()> {
167 self.validate_length(data.len())?;
168 self.increment_counter();
169 self.write_counter(data);
170 let calculated_crc = self.compute_crc(data);
171 self.write_crc(calculated_crc, data);
172 Ok(())
173 }
174
175 fn check(&mut self, data: &[u8]) -> E2EResult<E2EStatus> {
176 self.validate_length(data.len())?;
178 let check_items = Profile22Check {
179 rx_counter: self.read_counter(data),
180 rx_crc: self.read_crc(data),
181 calculated_crc: self.compute_crc(data),
182 };
183 let status = self.do_checks(check_items);
184 Ok(status)
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 #[test]
192 fn test_profile22_basic_example() {
193 let mut profile_tx = Profile22::new(Profile22Config::default()).unwrap();
194 let mut profile_rx = Profile22::new(Profile22Config::default()).unwrap();
195
196 let mut data = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
197 profile_tx.protect(&mut data).unwrap();
198 assert_eq!(data[0], 0x1b);
199 assert_eq!(data[1], 0x01);
200 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
201 profile_tx.protect(&mut data).unwrap();
202 assert_eq!(data[0], 0x98);
203 assert_eq!(data[1], 0x02);
204 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
205 profile_tx.protect(&mut data).unwrap();
206 assert_eq!(data[0], 0x31);
207 assert_eq!(data[1], 0x03);
208 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
209 profile_tx.protect(&mut data).unwrap();
210 assert_eq!(data[0], 0x0d);
211 assert_eq!(data[1], 0x04);
212 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
213 profile_tx.protect(&mut data).unwrap();
214 assert_eq!(data[0], 0x18);
215 assert_eq!(data[1], 0x05);
216 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
217 profile_tx.protect(&mut data).unwrap();
218 assert_eq!(data[0], 0x9b);
219 assert_eq!(data[1], 0x06);
220 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
221 profile_tx.protect(&mut data).unwrap();
222 assert_eq!(data[0], 0x65);
223 assert_eq!(data[1], 0x07);
224 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
225 profile_tx.protect(&mut data).unwrap();
226 assert_eq!(data[0], 0x08);
227 assert_eq!(data[1], 0x08);
228 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
229 profile_tx.protect(&mut data).unwrap();
230 assert_eq!(data[0], 0x1d);
231 assert_eq!(data[1], 0x09);
232 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
233 profile_tx.protect(&mut data).unwrap();
234 assert_eq!(data[0], 0x9e);
235 assert_eq!(data[1], 0x0a);
236 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
237 profile_tx.protect(&mut data).unwrap();
238 assert_eq!(data[0], 0x37);
239 assert_eq!(data[1], 0x0b);
240 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
241 profile_tx.protect(&mut data).unwrap();
242 assert_eq!(data[0], 0x0b);
243 assert_eq!(data[1], 0x0c);
244 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
245 profile_tx.protect(&mut data).unwrap();
246 assert_eq!(data[0], 0x1e);
247 assert_eq!(data[1], 0x0d);
248 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
249 profile_tx.protect(&mut data).unwrap();
250 assert_eq!(data[0], 0x9d);
251 assert_eq!(data[1], 0x0e);
252 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
253 profile_tx.protect(&mut data).unwrap();
254 assert_eq!(data[0], 0xcd);
255 assert_eq!(data[1], 0x0f);
256 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
257 profile_tx.protect(&mut data).unwrap();
258 assert_eq!(data[0], 0x0e);
259 assert_eq!(data[1], 0x00);
260 assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
261 }
262
263 #[test]
264 fn test_profile22_offset_example() {
265 let config = Profile22Config {
266 offset: 64,
267 data_length: 128,
268 ..Default::default()
269 };
270
271 let mut profile_tx = Profile22::new(config.clone()).unwrap();
272 let mut profile_rx = Profile22::new(config).unwrap();
273
274 let mut data1 = vec![
275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00,
277 ];
278 profile_tx.protect(&mut data1).unwrap();
279 assert_eq!(data1[8], 0x14);
280 assert_eq!(data1[9], 0x01);
281 assert_eq!(profile_rx.check(&data1).unwrap(), E2EStatus::Ok);
282 }
283}