use embedded_can::{Frame, Id, StandardId};
pub fn frame_from<F: Frame>(cob_id: u16, data: &[u8]) -> Option<F> {
F::new(StandardId::new(cob_id)?, data)
}
pub fn cob_id<F: Frame>(frame: &F) -> Option<u16> {
match frame.id() {
Id::Standard(id) => Some(id.as_raw()),
Id::Extended(_) => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use heapless::Vec;
#[derive(Debug)]
struct MockFrame {
id: Id,
data: Vec<u8, 8>,
}
impl Frame for MockFrame {
fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
let mut buf = Vec::new();
buf.extend_from_slice(data).ok()?;
Some(Self {
id: id.into(),
data: buf,
})
}
fn new_remote(_id: impl Into<Id>, _dlc: usize) -> Option<Self> {
None
}
fn is_extended(&self) -> bool {
matches!(self.id, Id::Extended(_))
}
fn is_remote_frame(&self) -> bool {
false
}
fn id(&self) -> Id {
self.id
}
fn dlc(&self) -> usize {
self.data.len()
}
fn data(&self) -> &[u8] {
&self.data
}
}
#[test]
fn round_trips_cob_id_and_data() {
let frame: MockFrame = frame_from(0x581, &[0x43, 0x00, 0x10, 0x00]).unwrap();
assert_eq!(cob_id(&frame), Some(0x581));
assert_eq!(frame.data(), &[0x43, 0x00, 0x10, 0x00]);
}
#[test]
fn rejects_out_of_range_cob_id() {
assert!(frame_from::<MockFrame>(0x800, &[]).is_none());
}
#[test]
fn extended_id_has_no_cob_id() {
use embedded_can::ExtendedId;
let frame = MockFrame {
id: Id::Extended(ExtendedId::new(0x1234).unwrap()),
data: Vec::new(),
};
assert_eq!(cob_id(&frame), None);
}
}