-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
314: Controller Area Network (CAN) Take 4 r=eldruin a=timokroeger Updated to the latest HAL changes: * Removed `try_` prefix * Moved non-blocking implementation to `nb` module * Removed default `blocking` implementaions ## Usage Example [stm32-fwupdate](https://github.com/timokroeger/pcan-basic-rs/blob/eh-take-4/pcan-basic/examples/stm32-fwupdate.rs) ## Implementations Updated for this PR: * [pcan-basic](https://github.com/timokroeger/pcan-basic-rs/blob/eh-take-4/pcan-basic/src/lib.rs) on top of an existing software API * [bxcan](https://github.com/timokroeger/bxcan/blob/eh-take-4/src/lib.rs#L460) Based on the very similar predecessor traits `embedded-can` v0.3 ([diff v0.3 -> this PR](https://github.com/timokroeger/embedded-can/compare/eh-take-4)) * [candev](https://github.com/reneherrero/candev) implementing the traits for linux SocketCAN * [socketcan-isotc](https://github.com/marcelbuesing/socketcan-isotp) ## Previous Discussion * #212 * #77 * #21 * #53 Co-authored-by: Timo Kröger <[email protected]>
- Loading branch information
Showing
10 changed files
with
278 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
//! Blocking CAN API | ||
/// A blocking CAN interface that is able to transmit and receive frames. | ||
pub trait Can { | ||
/// Associated frame type. | ||
type Frame: crate::can::Frame; | ||
|
||
/// Associated error type. | ||
type Error: crate::can::Error; | ||
|
||
/// Puts a frame in the transmit buffer. Blocks until space is available in | ||
/// the transmit buffer. | ||
fn transmit(&mut self, frame: &Self::Frame) -> Result<(), Self::Error>; | ||
|
||
/// Blocks until a frame was received or an error occured. | ||
fn receive(&mut self) -> Result<Self::Frame, Self::Error>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
//! 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. | ||
#[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. | ||
#[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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
//! Controller Area Network | ||
pub mod blocking; | ||
pub mod nb; | ||
|
||
mod id; | ||
|
||
pub use id::*; | ||
|
||
/// A CAN2.0 Frame | ||
pub trait Frame: Sized { | ||
/// Creates a new frame. | ||
/// Returns an error when the data slice is too long. | ||
fn new(id: impl Into<Id>, data: &[u8]) -> Result<Self, ()>; | ||
|
||
/// Creates a new remote frame (RTR bit set). | ||
/// Returns an error when the data length code (DLC) is not valid. | ||
fn new_remote(id: impl Into<Id>, dlc: usize) -> Result<Self, ()>; | ||
|
||
/// Returns true if this frame is a extended frame. | ||
fn is_extended(&self) -> bool; | ||
|
||
/// Returns true if this frame is a standard frame. | ||
fn is_standard(&self) -> bool { | ||
!self.is_extended() | ||
} | ||
|
||
/// Returns true if this frame is a remote frame. | ||
fn is_remote_frame(&self) -> bool; | ||
|
||
/// Returns true if this frame is a data frame. | ||
fn is_data_frame(&self) -> bool { | ||
!self.is_remote_frame() | ||
} | ||
|
||
/// Returns the frame identifier. | ||
fn id(&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. | ||
fn dlc(&self) -> usize; | ||
|
||
/// Returns the frame data (0..8 bytes in length). | ||
fn data(&self) -> &[u8]; | ||
} | ||
|
||
/// CAN error | ||
pub trait Error: core::fmt::Debug { | ||
/// Convert error to a generic CAN error kind | ||
/// | ||
/// By using this method, CAN errors freely defined by HAL implementations | ||
/// can be converted to a set of generic serial errors upon which generic | ||
/// code can act. | ||
fn kind(&self) -> ErrorKind; | ||
} | ||
|
||
/// CAN error kind | ||
/// | ||
/// This represents a common set of CAN operation errors. HAL implementations are | ||
/// free to define more specific or additional error types. However, by providing | ||
/// a mapping to these common CAN errors, generic code can still react to them. | ||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] | ||
#[non_exhaustive] | ||
pub enum ErrorKind { | ||
/// The peripheral receive buffer was overrun. | ||
Overrun, | ||
|
||
// MAC sublayer errors | ||
/// A bit error is detected at that bit time when the bit value that is | ||
/// monitored differs from the bit value sent. | ||
Bit, | ||
|
||
/// A stuff error is detected at the bit time of the sixth consecutive | ||
/// equal bit level in a frame field that shall be coded by the method | ||
/// of bit stuffing. | ||
Stuff, | ||
|
||
/// Calculated CRC sequence does not equal the received one. | ||
Crc, | ||
|
||
/// A form error shall be detected when a fixed-form bit field contains | ||
/// one or more illegal bits. | ||
Form, | ||
|
||
/// An ACK error shall be detected by a transmitter whenever it does not | ||
/// monitor a dominant bit during the ACK slot. | ||
Acknowledge, | ||
|
||
/// A different error occurred. The original error may contain more information. | ||
Other, | ||
} | ||
|
||
impl Error for ErrorKind { | ||
fn kind(&self) -> ErrorKind { | ||
*self | ||
} | ||
} | ||
|
||
impl core::fmt::Display for ErrorKind { | ||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
match self { | ||
Self::Overrun => write!(f, "The peripheral receive buffer was overrun"), | ||
Self::Bit => write!( | ||
f, | ||
"Bit value that is monitored differs from the bit value sent" | ||
), | ||
Self::Stuff => write!(f, "Sixth consecutive equal bits detected"), | ||
Self::Crc => write!(f, "Calculated CRC sequence does not equal the received one"), | ||
Self::Form => write!( | ||
f, | ||
"A fixed-form bit field contains one or more illegal bits" | ||
), | ||
Self::Acknowledge => write!(f, "Transmitted frame was not acknowledged"), | ||
Self::Other => write!( | ||
f, | ||
"A different error occurred. The original error may contain more information" | ||
), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
//! Non-blocking CAN API | ||
/// A CAN interface that is able to transmit and receive frames. | ||
pub trait Can { | ||
/// Associated frame type. | ||
type Frame: crate::can::Frame; | ||
|
||
/// Associated error type. | ||
type Error: crate::can::Error; | ||
|
||
/// Puts a frame in the transmit buffer to be sent on the bus. | ||
/// | ||
/// If the transmit buffer is full, this function will try to replace a pending | ||
/// lower priority frame and return the frame that was replaced. | ||
/// Returns `Err(WouldBlock)` if the transmit buffer is full and no frame can be | ||
/// replaced. | ||
/// | ||
/// # Notes for implementers | ||
/// | ||
/// * Frames of equal identifier shall be transmited in FIFO fashion when more | ||
/// than one transmit buffer is available. | ||
/// * When replacing pending frames make sure the frame is not in the process of | ||
/// being send to the bus. | ||
fn transmit(&mut self, frame: &Self::Frame) -> nb::Result<Option<Self::Frame>, Self::Error>; | ||
|
||
/// Returns a received frame if available. | ||
fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters