From 36ae48fcf26f20523203144ddef4da43667eaae4 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sat, 5 Oct 2024 15:21:40 +1000 Subject: [PATCH 1/3] embedded-can-04: Add new feature flag, implement From and Into for Id types. Expand CI to build and test with and without the flag set. --- .github/workflows/ci.yml | 7 ++-- CHANGELOG.md | 1 + Cargo.toml | 12 +++---- src/id.rs | 73 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +-- 5 files changed, 84 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a7d812..dcad825 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,9 @@ jobs: device_feature: - fdcan_g0_g4_l5 - fdcan_h7 + embedded_can_feature: + - "embedded-can-04" + - "" steps: - uses: actions/checkout@v2 - name: Cache cargo registry and index @@ -54,12 +57,12 @@ jobs: with: use-cross: true command: build - args: --verbose --release --target ${{ env.TARGET }} --features ${{ matrix.device_feature }} + args: --verbose --release --target ${{ env.TARGET }} --features ${{ matrix.device_feature }},${{ matrix.embedded_can_feature}} - uses: actions-rs/cargo@v1 with: use-cross: true command: test - args: --verbose --features ${{ matrix.device_feature }} + args: --verbose --features ${{ matrix.device_feature }},${{ matrix.embedded_can_feature}} lint: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 48994b4..a04d60f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] * Update MSRV to 1.60 +* Add `embedded-can-04` feature flag which enables conversions from and into `embedded_can::Id` types. ## [v0.2.1] 2024-09-04 diff --git a/Cargo.toml b/Cargo.toml index ce006a2..d37653a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,22 +19,18 @@ features = ["fdcan_g0_g4_l5"] targets = ["thumbv7em-none-eabihf"] [features] -fdcan_g0_g4_l5 = [] # Peripheral map found on G0 G4 L5 -fdcan_h7 = [] # Peripheral map found on H7 +fdcan_g0_g4_l5 = [] # Peripheral map found on G0 G4 L5 +fdcan_h7 = [] # Peripheral map found on H7 +embedded-can-04 = ["embedded-can"] # Implement embedded-can 0.4 compatible traits [dependencies] bitflags = "1.3.2" +embedded-can = { version = "0.4", optional = true } paste = "1.0" vcell = "0.1.3" nb = "1.0.0" static_assertions = "1.1" volatile-register = "0.2.1" -[dependencies.embedded-can-03] -version = "0.3" -optional = true -package = "embedded-can" - - [profile.test] opt-level = "s" diff --git a/src/id.rs b/src/id.rs index b578085..03cf9c6 100644 --- a/src/id.rs +++ b/src/id.rs @@ -44,12 +44,37 @@ impl StandardId { self.0 } } + impl From for IdType { fn from(_id: StandardId) -> Self { IdType::StandardId } } +#[cfg(feature = "embedded-can-04")] +impl From for StandardId +{ + #[inline] + fn from(value: embedded_can::StandardId) -> Self { + // unsafe: embedded_can range check is the same as here + unsafe { + Self::new_unchecked(value.as_raw()) + } + } +} + +#[cfg(feature = "embedded-can-04")] +impl Into for StandardId +{ + #[inline] + fn into(self) -> embedded_can::StandardId { + // unsafe: embedded_can range check is the same as here + unsafe { + embedded_can::StandardId::new_unchecked(self.as_raw()) + } + } +} + /// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`). #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ExtendedId(u32); @@ -103,6 +128,30 @@ impl From for IdType { } } +#[cfg(feature = "embedded-can-04")] +impl From for ExtendedId +{ + #[inline] + fn from(value: embedded_can::ExtendedId) -> Self { + // Safety: embedded_can range check is the same as here + unsafe { + Self::new_unchecked(value.as_raw()) + } + } +} + +#[cfg(feature = "embedded-can-04")] +impl Into for ExtendedId +{ + #[inline] + fn into(self) -> embedded_can::ExtendedId { + // Safety: embedded_can range check is the same as here + unsafe { + embedded_can::ExtendedId::new_unchecked(self.as_raw()) + } + } +} + /// A CAN Identifier (standard or extended). #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Id { @@ -127,6 +176,30 @@ impl From for Id { } } +#[cfg(feature = "embedded-can-04")] +impl From for Id +{ + #[inline] + fn from(value: embedded_can::Id) -> Self { + match value { + embedded_can::Id::Standard(id) => Id::Standard(id.into()), + embedded_can::Id::Extended(id) => Id::Extended(id.into()), + } + } +} + +#[cfg(feature = "embedded-can-04")] +impl Into for Id +{ + #[inline] + fn into(self) -> embedded_can::Id { + match self { + Id::Standard(id) => embedded_can::Id::Standard(id.into()), + Id::Extended(id) => embedded_can::Id::Extended(id.into()), + } + } +} + impl From for IdType { #[inline] fn from(id: Id) -> Self { diff --git a/src/lib.rs b/src/lib.rs index 839088b..fab6ab9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ //! //! | Feature | Description | //! |---------|-------------| -//! | `embedded-can-03` | ~Implements the [`embedded-can`] 0.3 traits.~ | +//! | `embedded-can-04` | Enables conversions from and into [`embedded_can`] 0.4 CAN ID types. | //! //! [`embedded-can`]: https://docs.rs/embedded-can @@ -28,8 +28,6 @@ pub use crate::pac::fdcan::RegisterBlock; /// Configuration of an FDCAN instance pub mod config; -// #[cfg(feature = "embedded-can-03")] REVERT ME: embedded-can support -// mod embedded_can; /// Filtering of CAN Messages pub mod filter; /// Header and info of transmitted and receiving frames From 11578695c100efa7e580a0f58e8fbed85c98ad98 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sat, 5 Oct 2024 15:47:33 +1000 Subject: [PATCH 2/3] embedded-can-04: Add transmit path for embedded_can::Frame. - Implement Frame.into - Add transmit_frame() & transmit_preserve_frame() for transmitting frames. --- CHANGELOG.md | 2 +- src/frame.rs | 17 +++++++++++++++++ src/lib.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a04d60f..b124090 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## [Unreleased] * Update MSRV to 1.60 -* Add `embedded-can-04` feature flag which enables conversions from and into `embedded_can::Id` types. +* Add `embedded-can-04` feature flag which enables conversions from and into `embedded_can::Id` types, and compatible transmit functions. ## [v0.2.1] 2024-09-04 diff --git a/src/frame.rs b/src/frame.rs index 8bf0ffa..8bbbd13 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -95,6 +95,23 @@ impl From for IdReg { } } +#[cfg(feature = "embedded-can-04")] +impl

From<&P> for TxFrameHeader +where +P: embedded_can::Frame, +{ + fn from(value: &P) -> Self { + TxFrameHeader { + len: value.dlc() as u8, + id: value.id().into(), + // Note: embedded_can::Frame is only CAN 2.0 thus far + frame_format: FrameFormat::Standard, + bit_rate_switching: false, + marker: None, + } + } +} + pub(crate) trait MergeTxFrameHeader { fn merge(&self, header: TxFrameHeader); } diff --git a/src/lib.rs b/src/lib.rs index fab6ab9..c5a8adf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ //! //! | Feature | Description | //! |---------|-------------| -//! | `embedded-can-04` | Enables conversions from and into [`embedded_can`] 0.4 CAN ID types. | +//! | `embedded-can-04` | Enables conversions from and into [`embedded_can`] 0.4 CAN ID types, and compatible transmit functions. | //! //! [`embedded-can`]: https://docs.rs/embedded-can @@ -1058,6 +1058,33 @@ where unsafe { Tx::::conjure().transmit_preserve(frame, buffer, pending) } } + /// Puts an embedded_can Frame in a free transmit mailbox for transmission on the bus. + #[cfg(feature = "embedded-can-04")] + pub fn transmit_frame( + &mut self, + frame: &impl embedded_can::Frame + ) -> nb::Result, Infallible> { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure().transmit_frame(frame) } + } + + /// Puts an embedded_can Frame in a free transmit mailbox for transmission on the bus. + /// + /// Implements the same `pending` behaviour as `transmit_preserve`. + #[cfg(feature = "embedded-can-04")] + pub fn transmit_preserve_frame( + &mut self, + frame: &F, + pending: &mut PTX, + ) -> nb::Result, Infallible> + where + F: embedded_can::Frame, + PTX: FnMut(Mailbox, TxFrameHeader, &[u32]) -> P, + { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure().transmit_preserve_frame(frame, pending) } + } + /// Returns `true` if no frame is pending for transmission. #[inline] pub fn is_transmitter_idle(&self) -> bool { @@ -1296,6 +1323,31 @@ where Ok(pending_frame) } + /// Puts an embedded_can Frame in a free transmit mailbox for transmission on the bus. + #[cfg(feature = "embedded-can-04")] + pub fn transmit_frame( + &mut self, + frame: &impl embedded_can::Frame + ) -> nb::Result, Infallible> { + self.transmit(frame.into(), frame.data()) + } + + /// Puts an embedded_can Frame in a free transmit mailbox for transmission on the bus. + /// + /// Implements the same `pending` behaviour as `transmit_preserve`. + #[cfg(feature = "embedded-can-04")] + pub fn transmit_preserve_frame( + &mut self, + frame: &F, + pending: &mut PTX, + ) -> nb::Result, Infallible> + where + F: embedded_can::Frame, + PTX: FnMut(Mailbox, TxFrameHeader, &[u32]) -> P, + { + self.transmit_preserve(frame.into(), frame.data(), pending) + } + /// Returns if the tx queue is able to accept new messages without having to cancel an existing one #[inline] pub fn tx_queue_is_full(&self) -> bool { From d9632d6d38b7e9835b5717096fd72146737996f8 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 17 Oct 2024 14:22:52 +1100 Subject: [PATCH 3/3] embedded-can-04: Add a receive function for an arbitrary embedded_can::Frame. Classic CAN only, as no CAN-FD support in embedded_can yet. --- CHANGELOG.md | 2 +- src/lib.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b124090..89d626c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## [Unreleased] * Update MSRV to 1.60 -* Add `embedded-can-04` feature flag which enables conversions from and into `embedded_can::Id` types, and compatible transmit functions. +* Add `embedded-can-04` feature flag which enables conversions from and into `embedded_can::Id` types, and compatible receive and transmit functions. ## [v0.2.1] 2024-09-04 diff --git a/src/lib.rs b/src/lib.rs index c5a8adf..dc3d703 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ //! //! | Feature | Description | //! |---------|-------------| -//! | `embedded-can-04` | Enables conversions from and into [`embedded_can`] 0.4 CAN ID types, and compatible transmit functions. | +//! | `embedded-can-04` | Enables conversions from and into [`embedded_can`] 0.4 CAN ID types, and compatible receive transmit functions. Note that only classic CAN is currently supported in `embedded_can`. | //! //! [`embedded-can`]: https://docs.rs/embedded-can @@ -52,7 +52,7 @@ use filter::{ StandardFilterSlot, EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX, }; use frame::MergeTxFrameHeader; -use frame::{RxFrameInfo, TxFrameHeader}; +use frame::{FrameFormat, RxFrameInfo, TxFrameHeader}; use id::{Id, IdReg}; use interrupt::{Interrupt, InterruptLine, Interrupts}; @@ -1140,6 +1140,36 @@ where // Safety: We have a `&mut self` and have unique access to the peripheral. unsafe { Rx::::conjure().receive(buffer) } } + + /// Returns a received Classic CAN frame of a given type from FIFO_0 if available. + /// + /// # Panics + /// + /// Panics if an `CAN-FD` frame is received, as embedded_can::Frame has no FD support. + #[cfg(feature = "embedded-can-04")] + #[inline] + pub fn receive0_frame(&mut self) -> nb::Result, Infallible> + where + F: embedded_can::Frame, + { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Rx::::conjure().receive_frame() } + } + + /// Returns a received Classic CAN frame of a given type from FIFO_1 if available. + /// + /// # Panics + /// + /// Panics if an `CAN-FD` frame is received, as embedded_can::Frame has no FD support. + #[cfg(feature = "embedded-can-04")] + #[inline] + pub fn receive1_frame(&mut self) -> nb::Result, Infallible> + where + F: embedded_can::Frame, + { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Rx::::conjure().receive_frame() } + } } /// FdCanControl Struct @@ -1567,8 +1597,6 @@ where /// Returns a received frame if available. /// - /// Returns `Err` when a frame was lost due to buffer overrun. - /// /// # Panics /// /// Panics if `buffer` is smaller than the header length. @@ -1607,6 +1635,33 @@ where } } + /// Returns a received Classic CAN frame of a given type if available. + /// + /// # Panics + /// + /// Panics if an `CAN-FD` frame is received, as embedded_can::Frame has no FD support. + #[cfg(feature = "embedded-can-04")] + pub fn receive_frame(&mut self) -> nb::Result, Infallible> + where + F: embedded_can::Frame, + { + let mut buffer = [0_u8; 8]; + let overrun = self.receive(&mut buffer)?; + let info = overrun.unwrap(); + if info.frame_format != FrameFormat::Standard { + panic!("Received CAN-FD frame"); + } + let frame = if info.rtr { + F::new_remote(info.id, info.len as usize) + } else { + F::new(info.id, &buffer[..info.len as usize]) + }.unwrap(); + match overrun { + ReceiveOverrun::NoOverrun(_) => Ok(ReceiveOverrun::NoOverrun(frame)), + ReceiveOverrun::Overrun(_) => Ok(ReceiveOverrun::Overrun(frame)), + } + } + #[inline] fn registers(&self) -> &RegisterBlock { unsafe { &*I::REGISTERS }