use std::collections::HashMap;
use smallvec::SmallVec;
use crate::engine::format::{iso11783_compose, iso11783_decompose};
use crate::engine::reassembly::{Reassembled, Reassembler};
use crate::engine::{BusProtocol, FramePacketType, RawFrame, fastpacket, format_iso_ms};
use super::{Event, Refused, SYNTHETIC_PGN_START};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CanFrame {
pub id: u32,
pub extended: bool,
pub data: SmallVec<[u8; 8]>,
}
impl CanFrame {
pub fn extended(id: u32, data: &[u8]) -> Option<Self> {
(id <= 0x1fff_ffff && data.len() <= 8).then(|| Self {
id,
extended: true,
data: SmallVec::from_slice(data),
})
}
pub fn standard(id: u32, data: &[u8]) -> Option<Self> {
(id <= 0x7ff && data.len() <= 8).then(|| Self {
id,
extended: false,
data: SmallVec::from_slice(data),
})
}
pub fn is_valid(&self) -> bool {
let max = if self.extended { 0x1fff_ffff } else { 0x7ff };
self.id <= max && self.data.len() <= 8
}
}
pub(crate) fn receive(
protocol: BusProtocol,
reassembler: &mut Reassembler,
id: u32,
extended: bool,
data: &[u8],
now_ms: Option<u64>,
events: &mut Vec<Event>,
) {
if let Some(now_ms) = now_ms {
reassembler.tick(now_ms);
}
if extended == protocol.standard_frames() {
return;
}
if !extended {
let mut frame = RawFrame::new(None, 0, id, 0, 255, data.iter().copied());
frame.timestamp = now_ms.map(format_iso_ms);
events.push(Event::Frame(frame));
return;
}
let (prio, pgn, src, dst) = iso11783_decompose(id);
let mut frame = RawFrame::new(None, prio, pgn, src, dst, data.iter().copied());
frame.timestamp = now_ms.map(format_iso_ms);
let pt = protocol.packet_type(frame.pgn);
match reassembler.push(frame, pt) {
Reassembled::PassThrough(f) | Reassembled::Complete(f) => events.push(Event::Frame(f)),
Reassembled::Partial => {}
Reassembled::Error(e) => events.push(Event::Error(e.to_string())),
}
}
#[derive(Debug, Default)]
pub(crate) struct FastPacketSeq(HashMap<(u32, u8), u8>);
impl FastPacketSeq {
fn next(&mut self, pgn: u32, src: u8) -> u8 {
let e = self.0.entry((pgn, src)).or_insert(0);
let s = *e;
*e = (*e + 1) & 0x07;
s
}
}
pub(crate) fn split(
protocol: BusProtocol,
seq: &mut FastPacketSeq,
frame: &RawFrame,
) -> Result<Vec<CanFrame>, Refused> {
if frame.pgn >= SYNTHETIC_PGN_START {
return Err(Refused::Synthetic);
}
if protocol.standard_frames() {
if frame.pgn > 0x7ff || frame.data.len() > 8 {
return Err(Refused::TooLarge);
}
return Ok(vec![CanFrame {
id: frame.pgn,
extended: false,
data: frame.data.iter().copied().collect(),
}]);
}
let id = iso11783_compose(frame.prio & 7, frame.pgn, frame.src, frame.dst);
let extended = |data: &[u8]| CanFrame {
id,
extended: true,
data: SmallVec::from_slice(data),
};
if protocol.packet_type(frame.pgn) == FramePacketType::Fast {
let chunks = fastpacket::fragment(seq.next(frame.pgn, frame.src), &frame.data)
.ok_or(Refused::TooLarge)?;
Ok(chunks.iter().map(|c| extended(c)).collect())
} else if frame.data.len() <= 8 {
Ok(vec![extended(&frame.data)])
} else {
Err(Refused::TooLarge)
}
}