-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: David Beechey <[email protected]>
- Loading branch information
1 parent
dd18d71
commit 25bf8a5
Showing
7 changed files
with
202 additions
and
49 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,9 @@ | ||
[package] | ||
name = "hyped_can" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
heapless = "0.8.0" | ||
embassy-sync = { version = "0.6.0", features = ["defmt"], git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"} | ||
embassy-time = { version = "0.3.1", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"], git = "https://github.com/embassy-rs/embassy", rev = "1c466b81e6af6b34b1f706318cc0870a459550b7"} |
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,135 @@ | ||
#![no_std] | ||
|
||
/// CAN errors that can occur | ||
/// From: https://docs.embassy.dev/embassy-stm32/git/stm32f767zi/can/enums/enum.BusError.html, | ||
/// https://docs.embassy.dev/embassy-stm32/git/stm32f767zi/can/enum.TryWriteError.html | ||
/// https://docs.embassy.dev/embassy-stm32/git/stm32f767zi/can/enum.TryReadError.html, | ||
/// and https://docs.embassy.dev/embassy-stm32/git/stm32f767zi/can/enums/enum.FrameCreateError.html | ||
#[derive(Debug)] | ||
pub enum CanError { | ||
Stuff, | ||
Form, | ||
Acknowledge, | ||
BitRecessive, | ||
BitDominant, | ||
Crc, | ||
Software, | ||
BusOff, | ||
BusPassive, | ||
BusWarning, | ||
Full, | ||
Empty, | ||
Unknown, | ||
NotEnoughData, | ||
InvalidDataLength, | ||
InvalidCanId, | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct HypedCanFrame { | ||
pub can_id: u32, // 32 bit CAN_ID + EFF/RTR/ERR flags | ||
pub data: [u8; 8], // data that is sent over CAN, split into bytes | ||
} | ||
|
||
pub type Timestamp = embassy_time::Instant; | ||
|
||
#[derive(Clone)] | ||
pub struct HypedEnvelope { | ||
/// Reception time. | ||
pub ts: Timestamp, | ||
/// The actual CAN frame. | ||
pub frame: HypedCanFrame, | ||
} | ||
|
||
/// CAN trait used to abstract the CAN operations | ||
pub trait HypedCan { | ||
/// Attempts to read a CAN frame without blocking. | ||
/// | ||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
fn read_frame(&mut self) -> Result<HypedEnvelope, CanError>; | ||
/// Attempts to transmit a frame without blocking. | ||
/// | ||
/// Returns [Err(CanError::Full)] if the frame can not be queued for transmission now. | ||
/// | ||
/// The frame will only be accepted if there is no frame with the same priority already queued. This is done | ||
/// to work around a hardware limitation that could lead to out-of-order delivery of frames with the same priority. | ||
fn write_frame(&mut self, frame: &HypedCanFrame) -> Result<(), CanError>; | ||
} | ||
|
||
pub mod mock_can { | ||
use core::cell::RefCell; | ||
use embassy_sync::blocking_mutex::{raw::CriticalSectionRawMutex, Mutex}; | ||
use heapless::Deque; | ||
|
||
use crate::HypedCanFrame; | ||
|
||
/// A fixed-size map of CAN frames | ||
type CanValues = Deque<HypedCanFrame, 8>; | ||
|
||
/// A mock CAN instance which can be used for testing | ||
pub struct MockCan<'a> { | ||
/// Values that have been read from the CAN bus | ||
frames_to_read: &'a Mutex<CriticalSectionRawMutex, RefCell<CanValues>>, | ||
/// Values that have been sent over the CAN bus | ||
frames_sent: CanValues, | ||
/// Whether to fail reading frames | ||
fail_read: &'a Mutex<CriticalSectionRawMutex, bool>, | ||
/// Whether to fail writing frames | ||
fail_write: &'a Mutex<CriticalSectionRawMutex, bool>, | ||
} | ||
|
||
impl crate::HypedCan for MockCan<'_> { | ||
fn read_frame(&mut self) -> Result<super::HypedEnvelope, super::CanError> { | ||
if self.fail_read.lock(|fail_read| *fail_read) { | ||
return Err(super::CanError::Unknown); | ||
} | ||
self.frames_to_read.lock(|frames_to_read| { | ||
match frames_to_read.borrow_mut().pop_front() { | ||
Some(frame) => Ok(super::HypedEnvelope { | ||
ts: embassy_time::Instant::now(), | ||
frame, | ||
}), | ||
None => Err(super::CanError::Empty), | ||
} | ||
}) | ||
} | ||
|
||
fn write_frame(&mut self, frame: &super::HypedCanFrame) -> Result<(), super::CanError> { | ||
if self.fail_write.lock(|fail_write| *fail_write) { | ||
return Err(super::CanError::Unknown); | ||
} | ||
match self.frames_sent.push_front(frame.clone()) { | ||
Ok(_) => Ok(()), | ||
Err(_) => Err(super::CanError::Unknown), | ||
} | ||
} | ||
} | ||
|
||
impl MockCan<'_> { | ||
pub fn new( | ||
frames_to_read: &'static Mutex<CriticalSectionRawMutex, RefCell<CanValues>>, | ||
) -> Self { | ||
static FAIL_READ: Mutex<CriticalSectionRawMutex, bool> = Mutex::new(false); | ||
static FAIL_WRITE: Mutex<CriticalSectionRawMutex, bool> = Mutex::new(false); | ||
MockCan::new_with_failures(frames_to_read, &FAIL_READ, &FAIL_WRITE) | ||
} | ||
|
||
pub fn new_with_failures( | ||
frames_to_read: &'static Mutex<CriticalSectionRawMutex, RefCell<CanValues>>, | ||
fail_read: &'static Mutex<CriticalSectionRawMutex, bool>, | ||
fail_write: &'static Mutex<CriticalSectionRawMutex, bool>, | ||
) -> Self { | ||
MockCan { | ||
frames_to_read, | ||
frames_sent: CanValues::new(), | ||
fail_read, | ||
fail_write, | ||
} | ||
} | ||
|
||
/// Get the values that have been sent over the CAN bus | ||
pub fn get_can_frames(&self) -> &CanValues { | ||
&self.frames_sent | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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