use crc::{Crc, CRC_8_AUTOSAR};
use crate::e2e::{CheckInfo, E2eError, E2eProfile};
const CRC8P2: Crc<u8> = Crc::<u8>::new(&CRC_8_AUTOSAR);
#[derive(Clone, Debug)]
pub struct P22 {
pub data_id_list: [u8; 16],
}
impl E2eProfile for P22 {
fn protect(&self, payload: &[u8], counter: u32) -> Result<Vec<u8>, E2eError> {
let c4 = (counter & 0x0F) as u8;
let mut out = Vec::with_capacity(payload.len() + 2);
out.extend_from_slice(payload);
out.resize(payload.len() + 2, 0u8);
let hdr = c4 & 0x0F;
let mut crc_in = Vec::with_capacity(payload.len() + 2);
crc_in.extend_from_slice(payload);
crc_in.push(self.data_id_list[c4 as usize]);
crc_in.push(hdr);
out[payload.len()] = CRC8P2.checksum(&crc_in);
out[payload.len() + 1] = hdr;
Ok(out)
}
fn check(&self, frame: &[u8]) -> Result<CheckInfo, E2eError> {
if frame.len() < 2 { return Err(E2eError::Length); }
let (crc_rx, hdr) = (frame[frame.len()-2], frame[frame.len()-1]);
let counter = hdr & 0x0F;
let payload = &frame[..frame.len()-2];
let mut crc_in = Vec::with_capacity(payload.len() + 2);
crc_in.extend_from_slice(payload);
crc_in.push(self.data_id_list[counter as usize]);
crc_in.push(hdr);
let want = CRC8P2.checksum(&crc_in);
if want != crc_rx { return Err(E2eError::Crc); }
Ok(CheckInfo { counter: counter as u32, ok: true })
}
fn payload_len(&self, frame: &[u8]) -> Option<usize> {
frame.len().checked_sub(2)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{E2eProfile, E2eSession, CounterPolicy, E2eError};
#[test]
fn p22_roundtrip() {
let mut tx = E2eSession::new(
P22 { data_id_list: [0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1A,0x1B, 0x1C,0x1D,0x1E,0x1F] },
CounterPolicy::Rollover { bits: 4, step: 1 },
);
let f = tx.wrap(&[0xAA]).unwrap();
let mut rx = E2eSession::new(
P22 { data_id_list: [0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1A,0x1B, 0x1C,0x1D,0x1E,0x1F] },
CounterPolicy::Rollover { bits: 4, step: 1 },
);
let pl = rx.unwrap(&f).unwrap();
assert_eq!(pl, &[0xAA]);
}
#[test]
fn p22_crc_detects_payload_bitflip() {
let p = P22 { data_id_list: [0;16] };
let mut f = p.protect(&[1,2,3], 3).unwrap();
f[1] ^= 0x80; assert!(matches!(p.check(&f), Err(E2eError::Crc)));
}
#[test]
fn p22_counter_policy() {
let mut tx = E2eSession::new(
P22 { data_id_list: [0;16] },
CounterPolicy::Rollover { bits: 4, step: 1 },
);
let f0 = tx.wrap(&[]).unwrap();
let f1 = tx.wrap(&[]).unwrap();
let f3 = P22 { data_id_list: [0;16] }.protect(&[], 3).unwrap();
let mut rx = E2eSession::new(
P22 { data_id_list: [0;16] },
CounterPolicy::Rollover { bits: 4, step: 1 },
);
rx.unwrap(&f0).unwrap();
rx.unwrap(&f1).unwrap();
assert!(matches!(rx.unwrap(&f3), Err(E2eError::Counter)));
}
}