kcan 0.1.6

CAN controller primitives for actuator and motor control.
Documentation
use std::{fmt, 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(_))
    }

    pub const fn kind_name(self) -> &'static str {
        match self {
            Self::Standard(_) => "standard",
            Self::Extended(_) => "extended",
        }
    }
}

impl fmt::Display for CanId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} 0x{:X}", self.kind_name(), self.raw())
    }
}

#[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
    }
}

impl fmt::Display for CanFrame {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} len={} data=", self.id, self.len())?;
        for (index, byte) in self.data().iter().enumerate() {
            if index > 0 {
                f.write_str(" ")?;
            }
            write!(f, "{byte:02X}")?;
        }
        Ok(())
    }
}

pub trait CanBus {
    fn send(&mut self, frame: &CanFrame) -> Result<()>;
    fn receive(&mut self, timeout: Duration) -> Result<Option<CanFrame>>;
}