use crc::{Crc, CRC_32_AUTOSAR};
use crate::e2e::{CheckInfo, E2eError, E2eProfile};
const CRC32P4: Crc<u32> = Crc::<u32>::new(&CRC_32_AUTOSAR);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct P44 {
pub data_id: u32,
}
impl E2eProfile for P44 {
fn protect(&self, payload: &[u8], counter: u32) -> Result<Vec<u8>, E2eError> {
let mut out = Vec::with_capacity(payload.len() + 12);
out.extend_from_slice(payload);
out.extend_from_slice(&(payload.len() as u16).to_be_bytes());
out.extend_from_slice(&self.data_id.to_be_bytes());
out.extend_from_slice(&(counter as u16).to_be_bytes());
let crc = CRC32P4.checksum(&out);
out.extend_from_slice(&crc.to_be_bytes());
Ok(out)
}
fn check(&self, frame: &[u8]) -> Result<CheckInfo, E2eError> {
if frame.len() < 12 { return Err(E2eError::Length); }
let crc_recv = u32::from_be_bytes(frame[frame.len()-4..].try_into().unwrap());
let without_crc = &frame[..frame.len()-4];
let want = CRC32P4.checksum(without_crc);
if want != crc_recv { return Err(E2eError::Crc); }
let len = u16::from_be_bytes(without_crc[without_crc.len()-8..without_crc.len()-6].try_into().unwrap()) as usize;
let data_id = u32::from_be_bytes(without_crc[without_crc.len()-6..without_crc.len()-2].try_into().unwrap());
let counter = u16::from_be_bytes(without_crc[without_crc.len()-2..].try_into().unwrap());
if data_id != self.data_id { return Err(E2eError::DataId); }
if len != without_crc.len() - (2+4+2) { return Err(E2eError::Length); }
Ok(CheckInfo { counter: counter as u32, ok: true })
}
fn payload_len(&self, frame: &[u8]) -> Option<usize> {
frame.len().checked_sub(12)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{E2eProfile, E2eSession, CounterPolicy};
#[test]
fn p44_roundtrip() {
let mut tx = E2eSession::new(P44 { data_id: 0xDEAD_BEEF }, CounterPolicy::Rollover{bits:16, step:1});
let f = tx.wrap(&[1,2,3,4,5]).unwrap();
let mut rx = E2eSession::new(P44 { data_id: 0xDEAD_BEEF }, CounterPolicy::Rollover{bits:16, step:1});
let pl = rx.unwrap(&f).unwrap();
assert_eq!(pl, &[1,2,3,4,5]);
}
#[test]
fn p44_crc_detects_corruption() {
let p = P44 { data_id: 0x1 };
let mut f = p.protect(&[9,8,7], 123).unwrap();
f[0] ^= 0x01;
assert!(matches!(p.check(&f), Err(E2eError::Crc)));
}
}