Use Result instead of Option for Frame creation.

This commit is contained in:
Corey Schuhen 2024-03-12 21:19:06 +10:00
parent 12a3af5043
commit 242759a600
9 changed files with 78 additions and 100 deletions

View file

@ -44,7 +44,6 @@ pub type Data = crate::can::frame::ClassicData;
pub type Frame = crate::can::frame::ClassicFrame; pub type Frame = crate::can::frame::ClassicFrame;
use crate::can::bx::filter::MasterFilters; use crate::can::bx::filter::MasterFilters;
use crate::can::frame::ClassicData;
/// A bxCAN peripheral instance. /// A bxCAN peripheral instance.
/// ///
@ -799,10 +798,7 @@ where
data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes());
let len = mb.tdtr().read().dlc(); let len = mb.tdtr().read().dlc();
Some(Frame::new( Some(Frame::new(Header::new(id, len, false), &data).unwrap())
Header::new(id, len, false),
ClassicData::new(&data).unwrap(),
))
} else { } else {
// Abort request failed because the frame was already sent (or being sent) on // 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 // the bus. All mailboxes are now free. This can happen for small prescaler
@ -944,10 +940,7 @@ fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result<Fra
// Release the mailbox. // Release the mailbox.
rfr.write(|w| w.set_rfom(true)); rfr.write(|w| w.set_rfom(true));
Ok(Frame::new( Ok(Frame::new(Header::new(id, len, false), &data).unwrap())
Header::new(id, len, false),
ClassicData::new(&data).unwrap(),
))
} }
/// Identifies one of the two receive FIFOs. /// Identifies one of the two receive FIFOs.

View file

@ -274,7 +274,7 @@ impl<'d, T: Instance> Can<'d, T> {
data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); 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()); data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
let frame = Frame::new(Header::new(id, data_len, false), Data::new(&data).unwrap()); let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap();
let envelope = Envelope { let envelope = Envelope {
#[cfg(feature = "time")] #[cfg(feature = "time")]
ts, ts,

View file

@ -28,3 +28,15 @@ pub enum BusError {
/// At least one of error counter has reached the Error_Warning limit of 96. /// At least one of error counter has reached the Error_Warning limit of 96.
BusWarning, BusWarning,
} }
/// Frame Create Errors
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FrameCreateError {
/// Data in header does not match supplied.
NotEnoughData,
/// Invalid data length not 0-8 for Classic packet or valid for FD.
InvalidDataLength,
/// Invalid ID.
InvalidCanId,
}

View file

@ -56,7 +56,10 @@ impl Registers {
match maybe_header { match maybe_header {
Some((header, ts)) => { Some((header, ts)) => {
let data = &buffer[0..header.len() as usize]; let data = &buffer[0..header.len() as usize];
Some((F::from_header(header, data)?, ts)) match F::from_header(header, data) {
Ok(frame) => Some((frame, ts)),
Err(_) => None,
}
} }
None => None, None => None,
} }

View file

@ -1,6 +1,8 @@
//! Definition for CAN Frames //! Definition for CAN Frames
use bit_field::BitField; use bit_field::BitField;
use crate::can::enums::FrameCreateError;
/// CAN Header, without meta data /// CAN Header, without meta data
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Header { pub struct Header {
@ -82,7 +84,7 @@ impl Header {
/// and to retrieve the Header from a frame /// and to retrieve the Header from a frame
pub trait CanHeader: Sized { pub trait CanHeader: Sized {
/// Construct frame from header and payload /// Construct frame from header and payload
fn from_header(header: Header, data: &[u8]) -> Option<Self>; fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError>;
/// Get this frame's header struct /// Get this frame's header struct
fn header(&self) -> &Header; fn header(&self) -> &Header;
@ -103,15 +105,15 @@ impl ClassicData {
/// ///
/// Returns `None` if `data` is more than 64 bytes (which is the maximum) or /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
/// cannot be represented with an FDCAN DLC. /// cannot be represented with an FDCAN DLC.
pub fn new(data: &[u8]) -> Option<Self> { pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
if !FdData::is_valid_len(data.len()) { if data.len() > 8 {
return None; return Err(FrameCreateError::InvalidDataLength);
} }
let mut bytes = [0; 8]; let mut bytes = [0; 8];
bytes[..data.len()].copy_from_slice(data); bytes[..data.len()].copy_from_slice(data);
Some(Self { bytes }) Ok(Self { bytes })
} }
/// Raw read access to data. /// Raw read access to data.
@ -134,12 +136,6 @@ 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 /// Frame with up to 8 bytes of data payload as per Classic CAN
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -150,59 +146,42 @@ pub struct ClassicFrame {
impl ClassicFrame { impl ClassicFrame {
/// Create a new CAN classic Frame /// Create a new CAN classic Frame
pub fn new(can_header: Header, data: impl Into<ClassicData>) -> ClassicFrame { pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
ClassicFrame { let data = ClassicData::new(raw_data)?;
can_header, Ok(ClassicFrame { can_header, data: data })
data: data.into(),
}
} }
/// Creates a new data frame. /// Creates a new data frame.
pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Self { pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Result<Self, FrameCreateError> {
let eid: embedded_can::Id = id.into(); let eid: embedded_can::Id = id.into();
let header = Header::new(eid, data.len() as u8, false); let header = Header::new(eid, data.len() as u8, false);
Self::new(header, data) Self::new(header, data)
} }
/// Create new extended frame /// Create new extended frame
pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
if let Some(id) = embedded_can::ExtendedId::new(raw_id) { if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
match ClassicData::new(raw_data) { Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
Some(data) => Some(ClassicFrame::new(
Header::new(id.into(), raw_data.len() as u8, false),
data,
)),
None => None,
}
} else { } else {
None Err(FrameCreateError::InvalidCanId)
} }
} }
/// Create new standard frame /// Create new standard frame
pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
if let Some(id) = embedded_can::StandardId::new(raw_id) { if let Some(id) = embedded_can::StandardId::new(raw_id) {
match ClassicData::new(raw_data) { Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
Some(data) => Some(ClassicFrame::new(
Header::new(id.into(), raw_data.len() as u8, false),
data,
)),
None => None,
}
} else { } else {
None Err(FrameCreateError::InvalidCanId)
} }
} }
/// Create new remote frame /// Create new remote frame
pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
if len <= 8usize { if len <= 8usize {
Some(ClassicFrame::new( Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
Header::new(id.into(), len as u8, true),
ClassicData::empty(),
))
} else { } else {
None Err(FrameCreateError::InvalidDataLength)
} }
} }
@ -229,20 +208,19 @@ impl ClassicFrame {
impl embedded_can::Frame for ClassicFrame { impl embedded_can::Frame for ClassicFrame {
fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
match ClassicData::new(raw_data) { let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
Some(data) => Some(ClassicFrame::new( match frameopt {
Header::new(id.into(), raw_data.len() as u8, false), Ok(frame) => Some(frame),
data, Err(_) => None,
)),
None => None,
} }
} }
fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 { if len <= 8 {
Some(ClassicFrame::new( let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
Header::new(id.into(), len as u8, true), match frameopt {
ClassicData::empty(), Ok(frame) => Some(frame),
)) Err(_) => None,
}
} else { } else {
None None
} }
@ -268,8 +246,8 @@ impl embedded_can::Frame for ClassicFrame {
} }
impl CanHeader for ClassicFrame { impl CanHeader for ClassicFrame {
fn from_header(header: Header, data: &[u8]) -> Option<Self> { fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
Some(Self::new(header, ClassicData::new(data)?)) Self::new(header, data)
} }
fn header(&self) -> &Header { fn header(&self) -> &Header {
@ -290,15 +268,15 @@ impl FdData {
/// ///
/// Returns `None` if `data` is more than 64 bytes (which is the maximum) or /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
/// cannot be represented with an FDCAN DLC. /// cannot be represented with an FDCAN DLC.
pub fn new(data: &[u8]) -> Option<Self> { pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
if !FdData::is_valid_len(data.len()) { if !FdData::is_valid_len(data.len()) {
return None; return Err(FrameCreateError::InvalidDataLength);
} }
let mut bytes = [0; 64]; let mut bytes = [0; 64];
bytes[..data.len()].copy_from_slice(data); bytes[..data.len()].copy_from_slice(data);
Some(Self { bytes }) Ok(Self { bytes })
} }
/// Raw read access to data. /// Raw read access to data.
@ -337,40 +315,35 @@ pub struct FdFrame {
impl FdFrame { impl FdFrame {
/// Create a new CAN classic Frame /// Create a new CAN classic Frame
pub fn new(can_header: Header, data: FdData) -> FdFrame { pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
FdFrame { can_header, data } let data = FdData::new(raw_data)?;
Ok(FdFrame { can_header, data })
} }
/// Create new extended frame /// Create new extended frame
pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
if let Some(id) = embedded_can::ExtendedId::new(raw_id) { if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
match FdData::new(raw_data) { Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
None => None,
}
} else { } else {
None Err(FrameCreateError::InvalidCanId)
} }
} }
/// Create new standard frame /// Create new standard frame
pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
if let Some(id) = embedded_can::StandardId::new(raw_id) { if let Some(id) = embedded_can::StandardId::new(raw_id) {
match FdData::new(raw_data) { Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
None => None,
}
} else { } else {
None Err(FrameCreateError::InvalidCanId)
} }
} }
/// Create new remote frame /// Create new remote frame
pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
if len <= 8 { if len <= 8 {
Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty())) Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
} else { } else {
None Err(FrameCreateError::InvalidDataLength)
} }
} }
@ -392,20 +365,17 @@ impl FdFrame {
impl embedded_can::Frame for FdFrame { impl embedded_can::Frame for FdFrame {
fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
match FdData::new(raw_data) { match FdFrame::new(Header::new_fd(id.into(), raw_data.len() as u8, false, true), raw_data) {
Some(data) => Some(FdFrame::new( Ok(frame) => Some(frame),
Header::new_fd(id.into(), raw_data.len() as u8, false, true), Err(_) => None,
data,
)),
None => None,
} }
} }
fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 { if len <= 8 {
Some(FdFrame::new( match FdFrame::new(Header::new_fd(id.into(), len as u8, true, true), &[0; 64]) {
Header::new_fd(id.into(), len as u8, true, true), Ok(frame) => Some(frame),
FdData::empty(), Err(_) => None,
)) }
} else { } else {
None None
} }
@ -432,8 +402,8 @@ impl embedded_can::Frame for FdFrame {
} }
impl CanHeader for FdFrame { impl CanHeader for FdFrame {
fn from_header(header: Header, data: &[u8]) -> Option<Self> { fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
Some(Self::new(header, FdData::new(data)?)) Self::new(header, data)
} }
fn header(&self) -> &Header { fn header(&self) -> &Header {

View file

@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) {
let mut i: u8 = 0; let mut i: u8 = 0;
loop { 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]).unwrap();
can.write(&tx_frame).await; can.write(&tx_frame).await;
match can.read().await { match can.read().await {

View file

@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) {
let mut i: u8 = 0; let mut i: u8 = 0;
loop { 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]).unwrap();
let tx_ts = Instant::now(); let tx_ts = Instant::now();
can.write(&tx_frame).await; can.write(&tx_frame).await;

View file

@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::task] #[embassy_executor::task]
pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) {
loop { loop {
let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]); let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap();
tx.write(&frame).await; tx.write(&frame).await;
embassy_time::Timer::after_secs(1).await; embassy_time::Timer::after_secs(1).await;
} }

View file

@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) {
let mut i: u8 = 0; let mut i: u8 = 0;
loop { 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]).unwrap();
info!("Transmitting frame..."); info!("Transmitting frame...");
let tx_ts = Instant::now(); let tx_ts = Instant::now();