use crc::{Crc, CRC_32_AUTOSAR};
use crate::e2e::{CheckInfo, E2eError, E2eProfile};
const CRC32P4: Crc<u32> = Crc::<u32>::new(&CRC_32_AUTOSAR);
#[derive(Clone, Debug)]
pub struct P8 {
pub data_id_list: [u8; 16], }
impl P8 {
fn crc32(bytes: &[u8]) -> u32 {
CRC32P4.checksum(bytes)
}
}
impl E2eProfile for P8 {
fn protect(&self, payload: &[u8], counter: u32) -> Result<Vec<u8>, E2eError> {
let c4 = (counter & 0x0F) as usize;
let mut out = Vec::with_capacity(payload.len() + 12);
out.extend_from_slice(payload);
out.extend_from_slice(&(payload.len() as u32).to_be_bytes());
out.extend_from_slice(&counter.to_be_bytes());
let mut crc_in = out.clone();
crc_in.push(self.data_id_list[c4]);
let crc = Self::crc32(&crc_in);
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 counter = u32::from_be_bytes(without_crc[without_crc.len() - 4..].try_into().unwrap());
let idx = (counter & 0x0F) as usize;
let mut crc_in = without_crc.to_vec();
crc_in.push(self.data_id_list[idx]);
let want = Self::crc32(&crc_in);
if want != crc_recv {
return Err(E2eError::Crc);
}
let len = u32::from_be_bytes(without_crc[without_crc.len() - 8..without_crc.len() - 4].try_into().unwrap()) as usize;
let payload_len = without_crc.len() - 8;
if len != payload_len {
return Err(E2eError::Length);
}
Ok(CheckInfo { counter, ok: true })
}
fn payload_len(&self, frame: &[u8]) -> Option<usize> {
frame.len().checked_sub(12)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{CounterPolicy, E2eProfile, E2eSession, E2eError};
#[test]
fn p8_roundtrip() {
let dil = [0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1A,0x1B, 0x1C,0x1D,0x1E,0x1F];
let mut tx = E2eSession::new(P8{data_id_list:dil}, CounterPolicy::Rollover{bits:32, step:1});
let f = tx.wrap(&[0x44,0x55]).unwrap();
let mut rx = E2eSession::new(P8{data_id_list:dil}, CounterPolicy::Rollover{bits:32, step:1});
let pl = rx.unwrap(&f).unwrap();
assert_eq!(pl, &[0x44,0x55]);
}
#[test]
fn p8_crc_detects_error() {
let p = P8{ data_id_list: [0;16] };
let mut f = p.protect(&[1,2,3,4], 7).unwrap();
f[1] ^= 0x80;
assert!(matches!(p.check(&f), Err(E2eError::Crc)));
}
}