use bit_field::BitField;
use crate::can::enums::FrameCreateError;
#[cfg(feature = "time")]
pub type Timestamp = embassy_time::Instant;
#[cfg(not(feature = "time"))]
pub type Timestamp = u16;
#[derive(Debug, Copy, Clone)]
pub struct Header {
id: embedded_can::Id,
len: u8,
flags: u8,
}
#[cfg(feature = "defmt")]
impl defmt::Format for Header {
fn format(&self, fmt: defmt::Formatter<'_>) {
match self.id() {
embedded_can::Id::Standard(id) => {
defmt::write!(fmt, "Can Standard ID={:x} len={}", id.as_raw(), self.len,)
}
embedded_can::Id::Extended(id) => {
defmt::write!(fmt, "Can Extended ID={:x} len={}", id.as_raw(), self.len,)
}
}
}
}
impl Header {
const FLAG_RTR: usize = 0; const FLAG_FDCAN: usize = 1; const FLAG_BRS: usize = 2; pub fn new(id: embedded_can::Id, len: u8, rtr: bool) -> Header {
let mut flags = 0u8;
flags.set_bit(Self::FLAG_RTR, rtr);
Header { id, len, flags }
}
pub fn new_fd(id: embedded_can::Id, len: u8, rtr: bool, brs: bool) -> Header {
let mut flags = 0u8;
flags.set_bit(Self::FLAG_RTR, rtr);
flags.set_bit(Self::FLAG_FDCAN, true);
flags.set_bit(Self::FLAG_BRS, brs);
Header { id, len, flags }
}
pub fn id(&self) -> &embedded_can::Id {
&self.id
}
pub fn len(&self) -> u8 {
self.len
}
pub fn rtr(&self) -> bool {
self.flags.get_bit(Self::FLAG_RTR)
}
pub fn fdcan(&self) -> bool {
self.flags.get_bit(Self::FLAG_FDCAN)
}
pub fn bit_rate_switching(&self) -> bool {
self.flags.get_bit(Self::FLAG_BRS)
}
pub(crate) fn priority(&self) -> u32 {
match self.id() {
embedded_can::Id::Standard(id) => (id.as_raw() as u32) << 18,
embedded_can::Id::Extended(id) => id.as_raw(),
}
}
}
pub trait CanHeader: Sized {
fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError>;
fn header(&self) -> &Header;
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClassicData {
pub(crate) bytes: [u8; Self::MAX_DATA_LEN],
}
impl ClassicData {
pub(crate) const MAX_DATA_LEN: usize = 8;
pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
if data.len() > 8 {
return Err(FrameCreateError::InvalidDataLength);
}
let mut bytes = [0; 8];
bytes[..data.len()].copy_from_slice(data);
Ok(Self { bytes })
}
pub fn raw(&self) -> &[u8] {
&self.bytes
}
pub const fn is_valid_len(len: usize) -> bool {
match len {
0..=8 => true,
_ => false,
}
}
#[inline]
pub const fn empty() -> Self {
Self { bytes: [0; 8] }
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Frame {
can_header: Header,
data: ClassicData,
}
impl Frame {
pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
let data = ClassicData::new(raw_data)?;
Ok(Frame { can_header, data: data })
}
pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Result<Self, FrameCreateError> {
let eid: embedded_can::Id = id.into();
let header = Header::new(eid, data.len() as u8, false);
Self::new(header, data)
}
pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
} else {
Err(FrameCreateError::InvalidCanId)
}
}
pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
if let Some(id) = embedded_can::StandardId::new(raw_id) {
Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
} else {
Err(FrameCreateError::InvalidCanId)
}
}
pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
if len <= 8usize {
Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
} else {
Err(FrameCreateError::InvalidDataLength)
}
}
pub fn header(&self) -> &Header {
&self.can_header
}
pub fn id(&self) -> &embedded_can::Id {
&self.can_header.id
}
pub fn data(&self) -> &[u8] {
&self.data.raw()
}
pub fn priority(&self) -> u32 {
self.header().priority()
}
}
impl embedded_can::Frame for Frame {
fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
match frameopt {
Ok(frame) => Some(frame),
Err(_) => None,
}
}
fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 {
let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
match frameopt {
Ok(frame) => Some(frame),
Err(_) => None,
}
} else {
None
}
}
fn is_extended(&self) -> bool {
match self.can_header.id {
embedded_can::Id::Extended(_) => true,
embedded_can::Id::Standard(_) => false,
}
}
fn is_remote_frame(&self) -> bool {
self.can_header.rtr()
}
fn id(&self) -> embedded_can::Id {
self.can_header.id
}
fn dlc(&self) -> usize {
self.can_header.len as usize
}
fn data(&self) -> &[u8] {
&self.data.raw()
}
}
impl CanHeader for Frame {
fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
Self::new(header, data)
}
fn header(&self) -> &Header {
self.header()
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Envelope {
pub ts: Timestamp,
pub frame: Frame,
}
impl Envelope {
pub fn parts(self) -> (Frame, Timestamp) {
(self.frame, self.ts)
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdData {
pub(crate) bytes: [u8; 64],
}
impl FdData {
pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
if !FdData::is_valid_len(data.len()) {
return Err(FrameCreateError::InvalidDataLength);
}
let mut bytes = [0; 64];
bytes[..data.len()].copy_from_slice(data);
Ok(Self { bytes })
}
pub fn raw(&self) -> &[u8] {
&self.bytes
}
pub const fn is_valid_len(len: usize) -> bool {
match len {
0..=8 => true,
12 => true,
16 => true,
20 => true,
24 => true,
32 => true,
48 => true,
64 => true,
_ => false,
}
}
#[inline]
pub const fn empty() -> Self {
Self { bytes: [0; 64] }
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdFrame {
can_header: Header,
data: FdData,
}
impl FdFrame {
pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
let data = FdData::new(raw_data)?;
Ok(FdFrame { can_header, data })
}
pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
} else {
Err(FrameCreateError::InvalidCanId)
}
}
pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
if let Some(id) = embedded_can::StandardId::new(raw_id) {
Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
} else {
Err(FrameCreateError::InvalidCanId)
}
}
pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
if len <= 8 {
Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
} else {
Err(FrameCreateError::InvalidDataLength)
}
}
pub fn header(&self) -> &Header {
&self.can_header
}
pub fn id(&self) -> &embedded_can::Id {
&self.can_header.id
}
pub fn data(&self) -> &[u8] {
&self.data.raw()
}
}
impl embedded_can::Frame for FdFrame {
fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
match FdFrame::new(Header::new_fd(id.into(), raw_data.len() as u8, false, true), raw_data) {
Ok(frame) => Some(frame),
Err(_) => None,
}
}
fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 {
match FdFrame::new(Header::new_fd(id.into(), len as u8, true, true), &[0; 64]) {
Ok(frame) => Some(frame),
Err(_) => None,
}
} else {
None
}
}
fn is_extended(&self) -> bool {
match self.can_header.id {
embedded_can::Id::Extended(_) => true,
embedded_can::Id::Standard(_) => false,
}
}
fn is_remote_frame(&self) -> bool {
self.can_header.rtr()
}
fn id(&self) -> embedded_can::Id {
self.can_header.id
}
fn dlc(&self) -> usize {
self.can_header.len as usize
}
fn data(&self) -> &[u8] {
&self.data.raw()
}
}
impl CanHeader for FdFrame {
fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
Self::new(header, data)
}
fn header(&self) -> &Header {
self.header()
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdEnvelope {
pub ts: Timestamp,
pub frame: FdFrame,
}
impl FdEnvelope {
pub fn parts(self) -> (FdFrame, Timestamp) {
(self.frame, self.ts)
}
}