use crate::{Error, Result};
use bitflags::bitflags;
use embedded_can::{ExtendedId, Id, StandardId};
use libc::canid_t;
use std::{io, ops};
pub use libc::{
CANFD_BRS, CANFD_ESI, CANFD_MAX_DLEN, CAN_EFF_FLAG, CAN_EFF_MASK, CAN_ERR_FLAG, CAN_ERR_MASK,
CAN_MAX_DLEN, CAN_RTR_FLAG, CAN_SFF_MASK,
};
pub const CANFD_FDF: libc::c_int = 0x04;
pub const ERR_MASK_ALL: u32 = CAN_ERR_MASK;
pub const ERR_MASK_NONE: u32 = 0;
bitflags! {
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct IdFlags: canid_t {
const EFF = CAN_EFF_FLAG;
const RTR = CAN_RTR_FLAG;
const ERR = CAN_ERR_FLAG;
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct FdFlags: u8 {
const BRS = CANFD_BRS as u8;
const ESI = CANFD_ESI as u8;
const FDF = CANFD_FDF as u8;
}
}
pub fn id_to_canid_t(id: impl Into<Id>) -> canid_t {
use Id::*;
match id.into() {
Standard(id) => id.as_raw() as canid_t,
Extended(id) => id.as_raw() | CAN_EFF_FLAG,
}
}
#[inline]
pub fn id_is_standard(id: &Id) -> bool {
matches!(id, Id::Standard(_))
}
#[inline]
pub fn id_is_extended(id: &Id) -> bool {
matches!(id, Id::Extended(_))
}
pub fn id_from_raw(id: u32) -> Option<Id> {
let id = match id {
n if n <= CAN_SFF_MASK => StandardId::new(n as u16)?.into(),
n => ExtendedId::new(n)?.into(),
};
Some(id)
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum CanId {
Standard(StandardId),
Extended(ExtendedId),
}
impl CanId {
pub fn standard(id: u16) -> Option<Self> {
let id = StandardId::new(id)?;
Some(Self::Standard(id))
}
pub fn extended(id: u32) -> Option<Self> {
let id = ExtendedId::new(id)?;
Some(Self::Extended(id))
}
pub fn as_id(&self) -> Id {
use CanId::*;
match self {
Standard(id) => Id::Standard(*id),
Extended(id) => Id::Extended(*id),
}
}
pub fn as_raw(&self) -> u32 {
use CanId::*;
match self {
Standard(id) => id.as_raw() as u32,
Extended(id) => id.as_raw(),
}
}
#[inline]
pub fn is_standard(&self) -> bool {
matches!(self, CanId::Standard(_))
}
#[inline]
pub fn is_extended(&self) -> bool {
matches!(self, CanId::Extended(_))
}
}
impl Ord for CanId {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.as_id().cmp(&other.as_id())
}
}
impl PartialOrd for CanId {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl From<StandardId> for CanId {
#[inline]
fn from(id: StandardId) -> Self {
Self::Standard(id)
}
}
impl From<ExtendedId> for CanId {
#[inline]
fn from(id: ExtendedId) -> Self {
Self::Extended(id)
}
}
impl From<Id> for CanId {
fn from(id: Id) -> Self {
use Id::*;
match id {
Standard(id) => Self::Standard(id),
Extended(id) => Self::Extended(id),
}
}
}
impl From<CanId> for Id {
#[inline]
fn from(id: CanId) -> Self {
id.as_id()
}
}
impl TryFrom<u32> for CanId {
type Error = Error;
fn try_from(id: u32) -> Result<Self> {
let id = match id {
n if n <= CAN_SFF_MASK => {
Self::standard(n as u16).ok_or(io::Error::from(io::ErrorKind::InvalidInput))?
}
n => Self::extended(n).ok_or(io::Error::from(io::ErrorKind::InvalidInput))?,
};
Ok(id)
}
}
impl ops::Add<u32> for CanId {
type Output = Self;
fn add(self, val: u32) -> Self::Output {
use CanId::*;
match self {
Standard(id) => {
Self::standard((id.as_raw() + val as u16) & CAN_SFF_MASK as u16).unwrap()
}
Extended(id) => Self::extended((id.as_raw() + val) & CAN_EFF_MASK).unwrap(),
}
}
}
impl ops::AddAssign<u32> for CanId {
fn add_assign(&mut self, other: u32) {
*self = *self + other;
}
}
#[cfg(test)]
mod tests {
use super::*;
const ID: u32 = 0x100;
#[test]
fn test_id_conv() {
let sid = StandardId::MAX;
let id = CanId::from(sid);
assert!(id.is_standard());
assert!(matches!(id, CanId::Standard(_)));
assert_eq!(id.as_raw(), sid.as_raw() as u32);
let eid = ExtendedId::MAX;
let id = CanId::from(eid);
assert!(id.is_extended());
assert!(matches!(id, CanId::Extended(_)));
assert_eq!(id.as_raw(), eid.as_raw());
let sid = Id::from(StandardId::MAX);
let id = CanId::from(sid);
assert!(id.is_standard());
assert!(matches!(id, CanId::Standard(_)));
match sid {
Id::Standard(sid) => assert_eq!(id.as_raw(), sid.as_raw() as u32),
_ => assert!(false),
};
let eid = Id::from(ExtendedId::MAX);
let id = CanId::from(eid);
assert!(id.is_extended());
assert!(matches!(id, CanId::Extended(_)));
match eid {
Id::Extended(eid) => assert_eq!(id.as_raw(), eid.as_raw()),
_ => assert!(false),
}
}
#[test]
fn test_id_raw() {
let id = CanId::try_from(ID).unwrap();
assert!(matches!(id, CanId::Standard(_)));
assert_eq!(id.as_raw(), ID);
}
#[test]
fn test_id_add() {
let id = CanId::try_from(ID).unwrap();
let id = id + 1;
assert!(matches!(id, CanId::Standard(_)));
assert_eq!(id.as_raw(), ID + 1);
let mut id = CanId::try_from(ID).unwrap();
id += 1;
assert!(matches!(id, CanId::Standard(_)));
assert_eq!(id.as_raw(), ID + 1);
}
}