use std::time::Duration;
use crate::error::{Error, Result};
pub const MAX_STANDARD_ID: u16 = 0x07FF;
pub const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF;
pub const MAX_CAN_DATA_LEN: usize = 8;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CanId {
Standard(u16),
Extended(u32),
}
impl CanId {
pub fn standard(id: u16) -> Result<Self> {
if id > MAX_STANDARD_ID {
return Err(Error::InvalidCanId(id.into()));
}
Ok(Self::Standard(id))
}
pub fn extended(id: u32) -> Result<Self> {
if id > MAX_EXTENDED_ID {
return Err(Error::InvalidCanId(id));
}
Ok(Self::Extended(id))
}
pub const fn raw(self) -> u32 {
match self {
Self::Standard(id) => id as u32,
Self::Extended(id) => id,
}
}
pub const fn is_extended(self) -> bool {
matches!(self, Self::Extended(_))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CanFrame {
id: CanId,
data: [u8; MAX_CAN_DATA_LEN],
len: u8,
}
impl CanFrame {
pub fn new(id: CanId, data: &[u8]) -> Result<Self> {
if data.len() > MAX_CAN_DATA_LEN {
return Err(Error::PayloadTooLong { len: data.len() });
}
let mut padded = [0_u8; MAX_CAN_DATA_LEN];
padded[..data.len()].copy_from_slice(data);
Ok(Self {
id,
data: padded,
len: data.len() as u8,
})
}
pub fn new_padded(id: CanId, data: &[u8]) -> Result<Self> {
let mut frame = Self::new(id, data)?;
frame.len = MAX_CAN_DATA_LEN as u8;
Ok(frame)
}
pub const fn id(&self) -> CanId {
self.id
}
pub fn data(&self) -> &[u8] {
&self.data[..self.len as usize]
}
pub const fn padded_data(&self) -> [u8; MAX_CAN_DATA_LEN] {
self.data
}
pub const fn len(&self) -> usize {
self.len as usize
}
pub const fn is_empty(&self) -> bool {
self.len == 0
}
}
pub trait CanBus {
fn send(&mut self, frame: &CanFrame) -> Result<()>;
fn receive(&mut self, timeout: Duration) -> Result<Option<CanFrame>>;
}