mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
Shared frame types.
Remove BXCAN speciffic id and frame modules Remove SizedClassicData
This commit is contained in:
parent
35f284ec22
commit
12a3af5043
@ -1,248 +0,0 @@
|
||||
#[cfg(test)]
|
||||
use core::cmp::Ordering;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::can::bx::{Id, IdReg};
|
||||
|
||||
/// A CAN data or remote frame.
|
||||
#[derive(Clone, Debug, Eq)]
|
||||
//#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct Frame {
|
||||
pub(crate) id: IdReg,
|
||||
pub(crate) data: Data,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
/// Creates a new data frame.
|
||||
pub fn new_data(id: impl Into<Id>, data: impl Into<Data>) -> Self {
|
||||
let id = match id.into() {
|
||||
Id::Standard(id) => IdReg::new_standard(id),
|
||||
Id::Extended(id) => IdReg::new_extended(id),
|
||||
};
|
||||
|
||||
Self { id, data: data.into() }
|
||||
}
|
||||
|
||||
/// Creates a new remote frame with configurable data length code (DLC).
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `dlc` is not inside the valid range `0..=8`.
|
||||
pub fn new_remote(id: impl Into<Id>, dlc: u8) -> Self {
|
||||
assert!(dlc <= 8);
|
||||
|
||||
let mut frame = Self::new_data(id, []);
|
||||
// Just extend the data length, even with no data present. The API does not hand out this
|
||||
// `Data` object.
|
||||
frame.data.len = dlc;
|
||||
frame.id = frame.id.with_rtr(true);
|
||||
frame
|
||||
}
|
||||
|
||||
/// Returns true if this frame is an extended frame.
|
||||
#[inline]
|
||||
pub fn is_extended(&self) -> bool {
|
||||
self.id.is_extended()
|
||||
}
|
||||
|
||||
/// Returns true if this frame is a standard frame.
|
||||
#[inline]
|
||||
pub fn is_standard(&self) -> bool {
|
||||
self.id.is_standard()
|
||||
}
|
||||
|
||||
/// Returns true if this frame is a remote frame.
|
||||
#[inline]
|
||||
pub fn is_remote_frame(&self) -> bool {
|
||||
self.id.rtr()
|
||||
}
|
||||
|
||||
/// Returns true if this frame is a data frame.
|
||||
#[inline]
|
||||
pub fn is_data_frame(&self) -> bool {
|
||||
!self.is_remote_frame()
|
||||
}
|
||||
|
||||
/// Returns the frame identifier.
|
||||
#[inline]
|
||||
pub fn id(&self) -> Id {
|
||||
self.id.to_id()
|
||||
}
|
||||
|
||||
/// Returns the priority of this frame.
|
||||
#[inline]
|
||||
pub fn priority(&self) -> FramePriority {
|
||||
FramePriority(self.id)
|
||||
}
|
||||
|
||||
/// Returns the data length code (DLC) which is in the range 0..8.
|
||||
///
|
||||
/// For data frames the DLC value always matches the length of the data.
|
||||
/// Remote frames do not carry any data, yet the DLC can be greater than 0.
|
||||
#[inline]
|
||||
pub fn dlc(&self) -> u8 {
|
||||
self.data.len() as u8
|
||||
}
|
||||
|
||||
/// Returns the frame data (0..8 bytes in length) if this is a data frame.
|
||||
///
|
||||
/// If this is a remote frame, returns `None`.
|
||||
pub fn data(&self) -> Option<&Data> {
|
||||
if self.is_data_frame() {
|
||||
Some(&self.data)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Frame {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.data(), other.data()) {
|
||||
(None, None) => self.id.eq(&other.id),
|
||||
(Some(a), Some(b)) => self.id.eq(&other.id) && a.eq(b),
|
||||
(None, Some(_)) | (Some(_), None) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Priority of a CAN frame.
|
||||
///
|
||||
/// Returned by [`Frame::priority`].
|
||||
///
|
||||
/// The priority of a frame is determined by the bits that are part of the *arbitration field*.
|
||||
/// These consist of the frame identifier bits (including the *IDE* bit, which is 0 for extended
|
||||
/// frames and 1 for standard frames), as well as the *RTR* bit, which determines whether a frame
|
||||
/// is a data or remote frame. Lower values of the *arbitration field* have higher priority.
|
||||
///
|
||||
/// This struct wraps the *arbitration field* and implements `PartialOrd` and `Ord` accordingly,
|
||||
/// ordering higher priorities greater than lower ones.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct FramePriority(IdReg);
|
||||
|
||||
/// Ordering is based on the Identifier and frame type (data vs. remote) and can be used to sort
|
||||
/// frames by priority.
|
||||
impl Ord for FramePriority {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
self.0.cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for FramePriority {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FramePriority {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.cmp(other) == core::cmp::Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for FramePriority {}
|
||||
|
||||
/// Payload of a CAN data frame.
|
||||
///
|
||||
/// Contains 0 to 8 Bytes of data.
|
||||
///
|
||||
/// `Data` implements `From<[u8; N]>` for all `N` up to 8, which provides a convenient lossless
|
||||
/// conversion from fixed-length arrays.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Data {
|
||||
pub(crate) len: u8,
|
||||
pub(crate) bytes: [u8; 8],
|
||||
}
|
||||
|
||||
impl Data {
|
||||
/// Creates a data payload from a raw byte slice.
|
||||
///
|
||||
/// Returns `None` if `data` contains more than 8 Bytes (which is the maximum).
|
||||
///
|
||||
/// `Data` can also be constructed from fixed-length arrays up to length 8 via `From`/`Into`.
|
||||
pub fn new(data: &[u8]) -> Option<Self> {
|
||||
if data.len() > 8 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut bytes = [0; 8];
|
||||
bytes[..data.len()].copy_from_slice(data);
|
||||
|
||||
Some(Self {
|
||||
len: data.len() as u8,
|
||||
bytes,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates an empty data payload containing 0 bytes.
|
||||
#[inline]
|
||||
pub const fn empty() -> Self {
|
||||
Self { len: 0, bytes: [0; 8] }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Data {
|
||||
type Target = [u8];
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.bytes[..usize::from(self.len)]
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Data {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes[..usize::from(self.len)]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Data {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Data {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
self.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Data {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_ref() == other.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Data {}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
impl defmt::Format for Data {
|
||||
fn format(&self, fmt: defmt::Formatter<'_>) {
|
||||
self.as_ref().format(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! data_from_array {
|
||||
( $($len:literal),+ ) => {
|
||||
$(
|
||||
impl From<[u8; $len]> for Data {
|
||||
#[inline]
|
||||
fn from(arr: [u8; $len]) -> Self {
|
||||
let mut bytes = [0; 8];
|
||||
bytes[..$len].copy_from_slice(&arr);
|
||||
Self {
|
||||
len: $len,
|
||||
bytes,
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
data_from_array!(0, 1, 2, 3, 4, 5, 6, 7, 8);
|
@ -1,113 +0,0 @@
|
||||
//! CAN Identifiers.
|
||||
|
||||
/// Standard 11-bit CAN Identifier (`0..=0x7FF`).
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct StandardId(u16);
|
||||
|
||||
impl StandardId {
|
||||
/// CAN ID `0`, the highest priority.
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
/// CAN ID `0x7FF`, the lowest priority.
|
||||
pub const MAX: Self = Self(0x7FF);
|
||||
|
||||
/// Tries to create a `StandardId` from a raw 16-bit integer.
|
||||
///
|
||||
/// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`).
|
||||
#[inline]
|
||||
pub const fn new(raw: u16) -> Option<Self> {
|
||||
if raw <= 0x7FF {
|
||||
Some(Self(raw))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `StandardId` without checking if it is inside the valid range.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that `raw` is in the valid range, otherwise the behavior is
|
||||
/// undefined.
|
||||
#[inline]
|
||||
pub const unsafe fn new_unchecked(raw: u16) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
/// Returns this CAN Identifier as a raw 16-bit integer.
|
||||
#[inline]
|
||||
pub fn as_raw(&self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`).
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ExtendedId(u32);
|
||||
|
||||
impl ExtendedId {
|
||||
/// CAN ID `0`, the highest priority.
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
/// CAN ID `0x1FFFFFFF`, the lowest priority.
|
||||
pub const MAX: Self = Self(0x1FFF_FFFF);
|
||||
|
||||
/// Tries to create a `ExtendedId` from a raw 32-bit integer.
|
||||
///
|
||||
/// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`).
|
||||
#[inline]
|
||||
pub const fn new(raw: u32) -> Option<Self> {
|
||||
if raw <= 0x1FFF_FFFF {
|
||||
Some(Self(raw))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `ExtendedId` without checking if it is inside the valid range.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that `raw` is in the valid range, otherwise the behavior is
|
||||
/// undefined.
|
||||
#[inline]
|
||||
pub const unsafe fn new_unchecked(raw: u32) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
/// Returns this CAN Identifier as a raw 32-bit integer.
|
||||
#[inline]
|
||||
pub fn as_raw(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Returns the Base ID part of this extended identifier.
|
||||
pub fn standard_id(&self) -> StandardId {
|
||||
// ID-28 to ID-18
|
||||
StandardId((self.0 >> 18) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
/// A CAN Identifier (standard or extended).
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Id {
|
||||
/// Standard 11-bit Identifier (`0..=0x7FF`).
|
||||
Standard(StandardId),
|
||||
|
||||
/// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`).
|
||||
Extended(ExtendedId),
|
||||
}
|
||||
|
||||
impl From<StandardId> for Id {
|
||||
#[inline]
|
||||
fn from(id: StandardId) -> Self {
|
||||
Id::Standard(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtendedId> for Id {
|
||||
#[inline]
|
||||
fn from(id: ExtendedId) -> Self {
|
||||
Id::Extended(id)
|
||||
}
|
||||
}
|
@ -25,19 +25,26 @@
|
||||
|
||||
//mod embedded_hal;
|
||||
pub mod filter;
|
||||
mod frame;
|
||||
mod id;
|
||||
|
||||
#[allow(clippy::all)] // generated code
|
||||
use core::cmp::{Ord, Ordering};
|
||||
use core::convert::{Infallible, TryInto};
|
||||
use core::convert::{Infallible, Into, TryInto};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
|
||||
pub use id::{ExtendedId, Id, StandardId};
|
||||
pub use embedded_can::{ExtendedId, Id, StandardId};
|
||||
|
||||
/// CAN Header: includes ID and length
|
||||
pub type Header = crate::can::frame::Header;
|
||||
|
||||
/// Data for a CAN Frame
|
||||
pub type Data = crate::can::frame::ClassicData;
|
||||
|
||||
/// CAN Frame
|
||||
pub type Frame = crate::can::frame::ClassicFrame;
|
||||
|
||||
use crate::can::bx::filter::MasterFilters;
|
||||
pub use crate::can::bx::frame::{Data, Frame, FramePriority};
|
||||
use crate::can::frame::ClassicData;
|
||||
|
||||
/// A bxCAN peripheral instance.
|
||||
///
|
||||
@ -148,13 +155,13 @@ impl IdReg {
|
||||
/// Sets the remote transmission (RTR) flag. This marks the identifier as
|
||||
/// being part of a remote frame.
|
||||
#[must_use = "returns a new IdReg without modifying `self`"]
|
||||
fn with_rtr(self, rtr: bool) -> IdReg {
|
||||
/*fn with_rtr(self, rtr: bool) -> IdReg {
|
||||
if rtr {
|
||||
Self(self.0 | Self::RTR_MASK)
|
||||
} else {
|
||||
Self(self.0 & !Self::RTR_MASK)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/// Returns the identifier.
|
||||
fn to_id(self) -> Id {
|
||||
@ -165,15 +172,28 @@ impl IdReg {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the identifier.
|
||||
fn id(self) -> embedded_can::Id {
|
||||
if self.is_extended() {
|
||||
embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT)
|
||||
.unwrap()
|
||||
.into()
|
||||
} else {
|
||||
embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16)
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the identifier is an extended identifier.
|
||||
fn is_extended(self) -> bool {
|
||||
self.0 & Self::IDE_MASK != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if the identifier is a standard identifier.
|
||||
fn is_standard(self) -> bool {
|
||||
/*fn is_standard(self) -> bool {
|
||||
!self.is_extended()
|
||||
}
|
||||
}*/
|
||||
|
||||
/// Returns `true` if the identifer is part of a remote frame (RTR bit set).
|
||||
fn rtr(self) -> bool {
|
||||
@ -181,6 +201,21 @@ impl IdReg {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&embedded_can::Id> for IdReg {
|
||||
fn from(eid: &embedded_can::Id) -> Self {
|
||||
match eid {
|
||||
embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()),
|
||||
embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IdReg> for embedded_can::Id {
|
||||
fn from(idr: IdReg) -> Self {
|
||||
idr.id()
|
||||
}
|
||||
}
|
||||
|
||||
/// `IdReg` is ordered by priority.
|
||||
impl Ord for IdReg {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
@ -682,9 +717,9 @@ where
|
||||
// The controller schedules pending frames of same priority based on the
|
||||
// mailbox index instead. As a workaround check all pending mailboxes
|
||||
// and only accept higher priority frames.
|
||||
self.check_priority(0, frame.id)?;
|
||||
self.check_priority(1, frame.id)?;
|
||||
self.check_priority(2, frame.id)?;
|
||||
self.check_priority(0, frame.id().into())?;
|
||||
self.check_priority(1, frame.id().into())?;
|
||||
self.check_priority(2, frame.id().into())?;
|
||||
|
||||
let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2);
|
||||
if all_frames_are_pending {
|
||||
@ -739,14 +774,15 @@ where
|
||||
debug_assert!(idx < 3);
|
||||
|
||||
let mb = self.canregs.tx(idx);
|
||||
mb.tdtr().write(|w| w.set_dlc(frame.dlc() as u8));
|
||||
mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8));
|
||||
|
||||
mb.tdlr()
|
||||
.write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[0..4].try_into().unwrap()));
|
||||
.write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap()));
|
||||
mb.tdhr()
|
||||
.write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[4..8].try_into().unwrap()));
|
||||
.write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap()));
|
||||
let id: IdReg = frame.id().into();
|
||||
mb.tir().write(|w| {
|
||||
w.0 = frame.id.0;
|
||||
w.0 = id.0;
|
||||
w.set_txrq(true);
|
||||
});
|
||||
}
|
||||
@ -756,16 +792,17 @@ where
|
||||
debug_assert!(idx < 3);
|
||||
|
||||
let mb = self.canregs.tx(idx);
|
||||
// Read back the pending frame.
|
||||
let mut pending_frame = Frame {
|
||||
id: IdReg(mb.tir().read().0),
|
||||
data: Data::empty(),
|
||||
};
|
||||
pending_frame.data.bytes[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes());
|
||||
pending_frame.data.bytes[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes());
|
||||
pending_frame.data.len = mb.tdtr().read().dlc();
|
||||
|
||||
Some(pending_frame)
|
||||
let id = IdReg(mb.tir().read().0).id();
|
||||
let mut data = [0xff; 8];
|
||||
data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes());
|
||||
data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes());
|
||||
let len = mb.tdtr().read().dlc();
|
||||
|
||||
Some(Frame::new(
|
||||
Header::new(id, len, false),
|
||||
ClassicData::new(&data).unwrap(),
|
||||
))
|
||||
} else {
|
||||
// Abort request failed because the frame was already sent (or being sent) on
|
||||
// the bus. All mailboxes are now free. This can happen for small prescaler
|
||||
@ -898,18 +935,19 @@ fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result<Fra
|
||||
}
|
||||
|
||||
// Read the frame.
|
||||
let mut frame = Frame {
|
||||
id: IdReg(rx.rir().read().0),
|
||||
data: [0; 8].into(),
|
||||
};
|
||||
frame.data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes());
|
||||
frame.data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes());
|
||||
frame.data.len = rx.rdtr().read().dlc();
|
||||
let id = IdReg(rx.rir().read().0).id();
|
||||
let mut data = [0xff; 8];
|
||||
data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes());
|
||||
data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes());
|
||||
let len = rx.rdtr().read().dlc();
|
||||
|
||||
// Release the mailbox.
|
||||
rfr.write(|w| w.set_rfom(true));
|
||||
|
||||
Ok(frame)
|
||||
Ok(Frame::new(
|
||||
Header::new(id, len, false),
|
||||
ClassicData::new(&data).unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Identifies one of the two receive FIFOs.
|
||||
|
@ -6,7 +6,7 @@ use core::task::Poll;
|
||||
|
||||
pub mod bx;
|
||||
|
||||
pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Id, StandardId};
|
||||
pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use futures::FutureExt;
|
||||
|
||||
@ -18,19 +18,20 @@ use crate::{interrupt, peripherals, Peripheral};
|
||||
|
||||
pub mod enums;
|
||||
use enums::*;
|
||||
pub mod frame;
|
||||
pub mod util;
|
||||
|
||||
/// Contains CAN frame and additional metadata.
|
||||
///
|
||||
/// Timestamp is available if `time` feature is enabled.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct Envelope {
|
||||
/// Reception time.
|
||||
#[cfg(feature = "time")]
|
||||
pub ts: embassy_time::Instant,
|
||||
/// The actual CAN frame.
|
||||
pub frame: crate::can::bx::Frame,
|
||||
pub frame: Frame,
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
@ -260,20 +261,20 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
}
|
||||
|
||||
let rir = fifo.rir().read();
|
||||
let id = if rir.ide() == Ide::STANDARD {
|
||||
Id::from(StandardId::new_unchecked(rir.stid()))
|
||||
let id: embedded_can::Id = if rir.ide() == Ide::STANDARD {
|
||||
embedded_can::StandardId::new(rir.stid()).unwrap().into()
|
||||
} else {
|
||||
let stid = (rir.stid() & 0x7FF) as u32;
|
||||
let exid = rir.exid() & 0x3FFFF;
|
||||
let id = (stid << 18) | (exid);
|
||||
Id::from(ExtendedId::new_unchecked(id))
|
||||
embedded_can::ExtendedId::new(id).unwrap().into()
|
||||
};
|
||||
let data_len = fifo.rdtr().read().dlc() as usize;
|
||||
let data_len = fifo.rdtr().read().dlc();
|
||||
let mut data: [u8; 8] = [0; 8];
|
||||
data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
|
||||
data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
|
||||
|
||||
let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap());
|
||||
let frame = Frame::new(Header::new(id, data_len, false), Data::new(&data).unwrap());
|
||||
let envelope = Envelope {
|
||||
#[cfg(feature = "time")]
|
||||
ts,
|
||||
|
@ -182,7 +182,7 @@ impl Registers {
|
||||
DataLength::Fdcan(len) => len,
|
||||
DataLength::Classic(len) => len,
|
||||
};
|
||||
if len as usize > ClassicFrame::MAX_DATA_LEN {
|
||||
if len as usize > ClassicData::MAX_DATA_LEN {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,20 @@ pub struct Header {
|
||||
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; // Remote
|
||||
const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
|
||||
@ -54,6 +68,14 @@ impl Header {
|
||||
pub fn bit_rate_switching(&self) -> bool {
|
||||
self.flags.get_bit(Self::FLAG_BRS)
|
||||
}
|
||||
|
||||
/// Get priority of frame
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for FDCAN frame types, providing ability to construct from a Header
|
||||
@ -70,11 +92,13 @@ pub trait CanHeader: Sized {
|
||||
///
|
||||
/// Contains 0 to 8 Bytes of data.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct ClassicData {
|
||||
pub(crate) bytes: [u8; 8],
|
||||
pub(crate) bytes: [u8; Self::MAX_DATA_LEN],
|
||||
}
|
||||
|
||||
impl ClassicData {
|
||||
pub(crate) const MAX_DATA_LEN: usize = 8;
|
||||
/// Creates a data payload from a raw byte slice.
|
||||
///
|
||||
/// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
|
||||
@ -110,19 +134,34 @@ impl ClassicData {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for ClassicData {
|
||||
fn from(d: &[u8]) -> Self {
|
||||
ClassicData::new(d).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Frame with up to 8 bytes of data payload as per Classic CAN
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct ClassicFrame {
|
||||
can_header: Header,
|
||||
data: ClassicData,
|
||||
}
|
||||
|
||||
impl ClassicFrame {
|
||||
pub(crate) const MAX_DATA_LEN: usize = 8;
|
||||
|
||||
/// Create a new CAN classic Frame
|
||||
pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame {
|
||||
ClassicFrame { can_header, data }
|
||||
pub fn new(can_header: Header, data: impl Into<ClassicData>) -> ClassicFrame {
|
||||
ClassicFrame {
|
||||
can_header,
|
||||
data: data.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new data frame.
|
||||
pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Self {
|
||||
let eid: embedded_can::Id = id.into();
|
||||
let header = Header::new(eid, data.len() as u8, false);
|
||||
Self::new(header, data)
|
||||
}
|
||||
|
||||
/// Create new extended frame
|
||||
@ -181,6 +220,11 @@ impl ClassicFrame {
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data.raw()
|
||||
}
|
||||
|
||||
/// Get priority of frame
|
||||
pub fn priority(&self) -> u32 {
|
||||
self.header().priority()
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_can::Frame for ClassicFrame {
|
||||
|
@ -46,16 +46,16 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
let mut i: u8 = 0;
|
||||
loop {
|
||||
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i, 0, 1, 2, 3, 4, 5, 6]);
|
||||
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]);
|
||||
can.write(&tx_frame).await;
|
||||
|
||||
match can.read().await {
|
||||
Ok(env) => match env.frame.id() {
|
||||
Id::Extended(id) => {
|
||||
defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap());
|
||||
defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
|
||||
}
|
||||
Id::Standard(id) => {
|
||||
defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap());
|
||||
defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
|
@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
let mut i: u8 = 0;
|
||||
loop {
|
||||
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
|
||||
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]);
|
||||
let tx_ts = Instant::now();
|
||||
can.write(&tx_frame).await;
|
||||
|
||||
@ -65,7 +65,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
info!(
|
||||
"loopback frame {=u8}, latency: {} us",
|
||||
unwrap!(envelope.frame.data())[0],
|
||||
envelope.frame.data()[0],
|
||||
latency.as_micros()
|
||||
);
|
||||
i += 1;
|
||||
|
@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs {
|
||||
#[embassy_executor::task]
|
||||
pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) {
|
||||
loop {
|
||||
let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]);
|
||||
let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]);
|
||||
tx.write(&frame).await;
|
||||
embassy_time::Timer::after_secs(1).await;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
let mut i: u8 = 0;
|
||||
loop {
|
||||
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
|
||||
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]);
|
||||
|
||||
info!("Transmitting frame...");
|
||||
let tx_ts = Instant::now();
|
||||
@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Frame received!");
|
||||
|
||||
info!("loopback time {}", envelope.ts);
|
||||
info!("loopback frame {=u8}", envelope.frame.data().unwrap()[0]);
|
||||
info!("loopback frame {=u8}", envelope.frame.data()[0]);
|
||||
|
||||
let latency = envelope.ts.saturating_duration_since(tx_ts);
|
||||
info!("loopback latency {} us", latency.as_micros());
|
||||
|
Loading…
Reference in New Issue
Block a user