From 8b280688e18bd92b126601d9af26d73e147edeac Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 7 Jun 2025 17:25:15 +1000 Subject: [PATCH] FDCAN/BXCAN: Finish implementation of RAII instance counters. - Use DeRef in all types - Change Name of internal_operation and its enum - move into Info to avoid macro code dup --- embassy-stm32/src/can/bxcan/mod.rs | 191 ++++++++++++++--------------- embassy-stm32/src/can/common.rs | 120 ++++++++++++------ embassy-stm32/src/can/enums.rs | 2 +- embassy-stm32/src/can/fdcan.rs | 163 ++++++++++-------------- 4 files changed, 249 insertions(+), 227 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index e2d1c8182..4c0795a2a 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -15,9 +15,10 @@ pub use embedded_can::{ExtendedId, Id, StandardId}; use self::filter::MasterFilters; use self::registers::{Registers, RxFifo}; pub use super::common::{BufferedCanReceiver, BufferedCanSender}; +use super::common::{InfoRef, RxInfoRef, TxInfoRef}; use super::frame::{Envelope, Frame}; use super::util; -use crate::can::enums::{BusError, InternalOperation, TryReadError}; +use crate::can::enums::{BusError, RefCountOp, TryReadError}; use crate::gpio::{AfType, OutputType, Pull, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; @@ -90,7 +91,6 @@ impl interrupt::typelevel::Handler for SceInterrup // an indefinite amount of time. let ier = T::regs().ier(); ier.modify(|i| i.set_errie(false)); - T::info().state.lock(|state| { state.borrow().err_waker.wake(); }); @@ -101,7 +101,7 @@ impl interrupt::typelevel::Handler for SceInterrup /// Configuration proxy returned by [`Can::modify_config`]. pub struct CanConfig<'a> { phantom: PhantomData<&'a ()>, - info: &'static Info, + info: InfoRef, periph_clock: crate::time::Hertz, } @@ -166,7 +166,7 @@ impl Drop for CanConfig<'_> { /// CAN driver pub struct Can<'d> { phantom: PhantomData<&'d ()>, - info: &'static Info, + info: InfoRef, periph_clock: crate::time::Hertz, } @@ -236,7 +236,7 @@ impl<'d> Can<'d> { Self { phantom: PhantomData, - info: T::info(), + info: InfoRef::new(T::info()), periph_clock: T::frequency(), } } @@ -256,7 +256,7 @@ impl<'d> Can<'d> { CanConfig { phantom: self.phantom, - info: self.info, + info: InfoRef::new(&self.info), periph_clock: self.periph_clock, } } @@ -305,8 +305,8 @@ impl<'d> Can<'d> { self.info.regs.0.mcr().modify(|m| m.set_sleep(true)); poll_fn(|cx| { - self.info.state.lock(|state| { - state.borrow().err_waker.register(cx.waker()); + self.info.state.lock(|s| { + s.borrow().err_waker.register(cx.waker()); }); if self.is_sleeping() { Poll::Ready(()) @@ -360,7 +360,7 @@ impl<'d> Can<'d> { pub async fn flush(&self, mb: Mailbox) { CanTx { _phantom: PhantomData, - info: self.info, + info: TxInfoRef::new(&self.info), } .flush_inner(mb) .await; @@ -375,7 +375,7 @@ impl<'d> Can<'d> { pub async fn flush_any(&self) { CanTx { _phantom: PhantomData, - info: self.info, + info: TxInfoRef::new(&self.info), } .flush_any_inner() .await @@ -385,7 +385,7 @@ impl<'d> Can<'d> { pub async fn flush_all(&self) { CanTx { _phantom: PhantomData, - info: self.info, + info: TxInfoRef::new(&self.info), } .flush_all_inner() .await @@ -413,19 +413,19 @@ impl<'d> Can<'d> { /// /// Returns a tuple of the time the message was received and the message frame pub async fn read(&mut self) -> Result { - RxMode::read(self.info).await + RxMode::read(&self.info).await } /// Attempts to read a CAN frame without blocking. /// /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. pub fn try_read(&mut self) -> Result { - RxMode::try_read(self.info) + RxMode::try_read(&self.info) } /// Waits while receive queue is empty. pub async fn wait_not_empty(&mut self) { - RxMode::wait_not_empty(self.info).await + RxMode::wait_not_empty(&self.info).await } /// Split the CAN driver into transmit and receive halves. @@ -435,11 +435,11 @@ impl<'d> Can<'d> { ( CanTx { _phantom: PhantomData, - info: self.info, + info: TxInfoRef::new(&self.info), }, CanRx { _phantom: PhantomData, - info: self.info, + info: RxInfoRef::new(&self.info), }, ) } @@ -464,7 +464,7 @@ impl<'d> Can<'d> { /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master /// peripheral instead. pub fn modify_filters(&mut self) -> MasterFilters<'_> { - unsafe { MasterFilters::new(self.info) } + unsafe { MasterFilters::new(&self.info) } } } @@ -519,7 +519,7 @@ impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_ /// CAN driver, transmit half. pub struct CanTx<'d> { _phantom: PhantomData<&'d ()>, - info: &'static Info, + info: TxInfoRef, } impl<'d> CanTx<'d> { @@ -528,8 +528,8 @@ impl<'d> CanTx<'d> { /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { poll_fn(|cx| { - self.info.state.lock(|state| { - state.borrow().tx_mode.register(cx.waker()); + self.info.state.lock(|s| { + s.borrow().tx_mode.register(cx.waker()); }); if let Ok(status) = self.info.regs.transmit(frame) { return Poll::Ready(status); @@ -555,8 +555,8 @@ impl<'d> CanTx<'d> { async fn flush_inner(&self, mb: Mailbox) { poll_fn(|cx| { - self.info.state.lock(|state| { - state.borrow().tx_mode.register(cx.waker()); + self.info.state.lock(|s| { + s.borrow().tx_mode.register(cx.waker()); }); if self.info.regs.0.tsr().read().tme(mb.index()) { return Poll::Ready(()); @@ -574,8 +574,8 @@ impl<'d> CanTx<'d> { async fn flush_any_inner(&self) { poll_fn(|cx| { - self.info.state.lock(|state| { - state.borrow().tx_mode.register(cx.waker()); + self.info.state.lock(|s| { + s.borrow().tx_mode.register(cx.waker()); }); let tsr = self.info.regs.0.tsr().read(); @@ -603,8 +603,8 @@ impl<'d> CanTx<'d> { async fn flush_all_inner(&self) { poll_fn(|cx| { - self.info.state.lock(|state| { - state.borrow().tx_mode.register(cx.waker()); + self.info.state.lock(|s| { + s.borrow().tx_mode.register(cx.waker()); }); let tsr = self.info.regs.0.tsr().read(); @@ -646,7 +646,7 @@ impl<'d> CanTx<'d> { self, txb: &'static mut TxBuf, ) -> BufferedCanTx<'d, TX_BUF_SIZE> { - BufferedCanTx::new(self.info, self, txb) + BufferedCanTx::new(&self.info, self, txb) } } @@ -655,23 +655,30 @@ pub type TxBuf = Channel { - info: &'static Info, + info: TxInfoRef, _tx: CanTx<'d>, tx_buf: &'static TxBuf, } impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> { fn new(info: &'static Info, _tx: CanTx<'d>, tx_buf: &'static TxBuf) -> Self { - Self { info, _tx, tx_buf }.setup() + Self { + info: TxInfoRef::new(info), + _tx, + tx_buf, + } + .setup() } fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. - let tx_inner = super::common::ClassicBufferedTxInner { - tx_receiver: self.tx_buf.receiver().into(), - }; - self.info.state.lock(|state| { - state.borrow_mut().tx_mode = TxMode::Buffered(tx_inner); + critical_section::with(|_| { + let tx_inner = super::common::ClassicBufferedTxInner { + tx_receiver: self.tx_buf.receiver().into(), + }; + self.info.state.lock(|s| { + s.borrow_mut().tx_mode = TxMode::Buffered(tx_inner); + }); }); self } @@ -685,26 +692,18 @@ impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> { /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedCanSender { - (self.info.internal_operation)(InternalOperation::NotifySenderCreated); BufferedCanSender { tx_buf: self.tx_buf.sender().into(), - waker: self.info.tx_waker, - internal_operation: self.info.internal_operation, + info: TxInfoRef::new(&self.info), } } } -impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> { - fn drop(&mut self) { - (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); - } -} - /// CAN driver, receive half. #[allow(dead_code)] pub struct CanRx<'d> { _phantom: PhantomData<&'d ()>, - info: &'static Info, + info: RxInfoRef, } impl<'d> CanRx<'d> { @@ -714,19 +713,19 @@ impl<'d> CanRx<'d> { /// /// Returns a tuple of the time the message was received and the message frame pub async fn read(&mut self) -> Result { - RxMode::read(self.info).await + RxMode::read(&self.info).await } /// Attempts to read a CAN frame without blocking. /// /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. pub fn try_read(&mut self) -> Result { - RxMode::try_read(self.info) + RxMode::try_read(&self.info) } /// Waits while receive queue is empty. pub async fn wait_not_empty(&mut self) { - RxMode::wait_not_empty(self.info).await + RxMode::wait_not_empty(&self.info).await } /// Return a buffered instance of driver. User must supply Buffers @@ -734,7 +733,7 @@ impl<'d> CanRx<'d> { self, rxb: &'static mut RxBuf, ) -> BufferedCanRx<'d, RX_BUF_SIZE> { - BufferedCanRx::new(self.info, self, rxb) + BufferedCanRx::new(&self.info, self, rxb) } /// Accesses the filter banks owned by this CAN peripheral. @@ -742,7 +741,7 @@ impl<'d> CanRx<'d> { /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master /// peripheral instead. pub fn modify_filters(&mut self) -> MasterFilters<'_> { - unsafe { MasterFilters::new(self.info) } + unsafe { MasterFilters::new(&self.info) } } } @@ -751,23 +750,30 @@ pub type RxBuf = Channel { - info: &'static Info, + info: RxInfoRef, rx: CanRx<'d>, rx_buf: &'static RxBuf, } impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { fn new(info: &'static Info, rx: CanRx<'d>, rx_buf: &'static RxBuf) -> Self { - BufferedCanRx { info, rx, rx_buf }.setup() + BufferedCanRx { + info: RxInfoRef::new(info), + rx, + rx_buf, + } + .setup() } fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. - let rx_inner = super::common::ClassicBufferedRxInner { - rx_sender: self.rx_buf.sender().into(), - }; - self.info.state.lock(|state| { - state.borrow_mut().rx_mode = RxMode::Buffered(rx_inner); + critical_section::with(|_| { + let rx_inner = super::common::ClassicBufferedRxInner { + rx_sender: self.rx_buf.sender().into(), + }; + self.info.state.lock(|s| { + s.borrow_mut().rx_mode = RxMode::Buffered(rx_inner); + }); }); self } @@ -809,10 +815,9 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub fn reader(&self) -> BufferedCanReceiver { - (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedCanReceiver { rx_buf: self.rx_buf.receiver().into(), - internal_operation: self.info.internal_operation, + info: RxInfoRef::new(&self.info), } } @@ -825,12 +830,6 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { } } -impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> { - fn drop(&mut self) { - (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); - } -} - impl Drop for Can<'_> { fn drop(&mut self) { // Cannot call `free()` because it moves the instance. @@ -1005,6 +1004,7 @@ impl TxMode { pub fn on_interrupt(&self) { T::info().state.lock(|state| { let tx_mode = &state.borrow().tx_mode; + match tx_mode { TxMode::NonBuffered(waker) => waker.wake(), TxMode::Buffered(buf) => { @@ -1062,8 +1062,7 @@ pub(crate) struct Info { rx0_interrupt: crate::interrupt::Interrupt, rx1_interrupt: crate::interrupt::Interrupt, sce_interrupt: crate::interrupt::Interrupt, - tx_waker: fn(), - internal_operation: fn(InternalOperation), + pub(crate) tx_waker: fn(), state: SharedState, /// The total number of filter banks available to the instance. @@ -1072,10 +1071,37 @@ pub(crate) struct Info { num_filter_banks: u8, } +impl Info { + pub(crate) fn adjust_reference_counter(&self, val: RefCountOp) { + self.state.lock(|s| { + let mut mut_state = s.borrow_mut(); + match val { + RefCountOp::NotifySenderCreated => { + mut_state.sender_instance_count += 1; + } + RefCountOp::NotifySenderDestroyed => { + mut_state.sender_instance_count -= 1; + if 0 == mut_state.sender_instance_count { + (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + RefCountOp::NotifyReceiverCreated => { + mut_state.receiver_instance_count += 1; + } + RefCountOp::NotifyReceiverDestroyed => { + mut_state.receiver_instance_count -= 1; + if 0 == mut_state.receiver_instance_count { + (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + } + }); + } +} + trait SealedInstance { fn info() -> &'static Info; fn regs() -> crate::pac::can::Can; - fn internal_operation(val: InternalOperation); } /// CAN instance trait. @@ -1133,43 +1159,16 @@ foreach_peripheral!( rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ, sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ, tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend, - internal_operation: peripherals::$inst::internal_operation, - state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())), num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS, + state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())), }; &INFO } fn regs() -> crate::pac::can::Can { crate::pac::$inst } - - fn internal_operation(val: InternalOperation) { - peripherals::$inst::info().state.lock(|s| { - let mut mut_state = s.borrow_mut(); - //let mut_state = state as *mut State; - match val { - InternalOperation::NotifySenderCreated => { - mut_state.sender_instance_count += 1; - } - InternalOperation::NotifySenderDestroyed => { - mut_state.sender_instance_count -= 1; - if ( 0 == mut_state.sender_instance_count) { - (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - } - InternalOperation::NotifyReceiverCreated => { - mut_state.receiver_instance_count += 1; - } - InternalOperation::NotifyReceiverDestroyed => { - mut_state.receiver_instance_count -= 1; - if ( 0 == mut_state.receiver_instance_count) { - (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - } - } - }); - } } + impl Instance for peripherals::$inst { type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX; type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0; diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 651fa12d5..980f33a04 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -24,22 +24,21 @@ pub(crate) struct FdBufferedTxInner { /// Sender that can be used for sending CAN frames. pub struct BufferedSender<'ch, FRAME> { pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>, - pub(crate) waker: fn(), - pub(crate) tx_guard: TxGuard, + pub(crate) info: TxInfoRef, } impl<'ch, FRAME> BufferedSender<'ch, FRAME> { /// Async write frame to TX buffer. pub fn try_write(&mut self, frame: FRAME) -> Result<(), embassy_sync::channel::TrySendError> { self.tx_buf.try_send(frame)?; - (self.waker)(); + (self.info.tx_waker)(); Ok(()) } /// Async write frame to TX buffer. pub async fn write(&mut self, frame: FRAME) { self.tx_buf.send(frame).await; - (self.waker)(); + (self.info.tx_waker)(); } /// Allows a poll_fn to poll until the channel is ready to write @@ -52,8 +51,7 @@ impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> { fn clone(&self) -> Self { Self { tx_buf: self.tx_buf, - waker: self.waker, - tx_guard: TxGuard::new(self.tx_guard.internal_operation), + info: TxInfoRef::new(&self.info), } } } @@ -64,7 +62,7 @@ pub type BufferedCanSender = BufferedSender<'static, Frame>; /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub struct BufferedReceiver<'ch, ENVELOPE> { pub(crate) rx_buf: embassy_sync::channel::SendDynamicReceiver<'ch, Result>, - pub(crate) rx_guard: RxGuard, + pub(crate) info: RxInfoRef, } impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> { @@ -101,7 +99,7 @@ impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> { fn clone(&self) -> Self { Self { rx_buf: self.rx_buf, - rx_guard: RxGuard::new(self.rx_guard.internal_operation), + info: RxInfoRef::new(&self.info), } } } @@ -109,37 +107,89 @@ impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> { /// A BufferedCanReceiver for Classic CAN frames. pub type BufferedCanReceiver = BufferedReceiver<'static, Envelope>; -/// Implements RAII for the internal reference counting (TX side). Each TX type should contain one -/// of these. The new method and the Drop impl will automatically call the reference counting -/// function. Like this, the reference counting function does not need to be called manually for -/// each TX type. Transceiver types (TX and RX) should contain one TxGuard and one RxGuard. -pub(crate) struct TxGuard { - internal_operation: fn(InternalOperation), +/// Provides a reference to the driver internals and implements RAII for the internal reference +/// counting. Each type that can operate on the driver should contain either InfoRef +/// or the similar TxInfoRef or RxInfoRef. The new method and the Drop impl will automatically +/// call the reference counting function. Like this, the reference counting function does not +/// need to be called manually for each type. +pub(crate) struct InfoRef { + info: &'static super::Info, } -impl TxGuard { - pub(crate) fn new(internal_operation: fn(InternalOperation)) -> Self { - internal_operation(InternalOperation::NotifySenderCreated); - Self { internal_operation } - } -} -impl Drop for TxGuard { - fn drop(&mut self) { - (self.internal_operation)(InternalOperation::NotifySenderDestroyed); +impl InfoRef { + pub(crate) fn new(info: &'static super::Info) -> Self { + info.adjust_reference_counter(RefCountOp::NotifyReceiverCreated); + info.adjust_reference_counter(RefCountOp::NotifySenderCreated); + Self { info } } } -/// Implements RAII for the internal reference counting (RX side). See TxGuard for further doc. -pub(crate) struct RxGuard { - internal_operation: fn(InternalOperation), -} -impl RxGuard { - pub(crate) fn new(internal_operation: fn(InternalOperation)) -> Self { - internal_operation(InternalOperation::NotifyReceiverCreated); - Self { internal_operation } - } -} -impl Drop for RxGuard { +impl Drop for InfoRef { fn drop(&mut self) { - (self.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + self.info.adjust_reference_counter(RefCountOp::NotifyReceiverDestroyed); + self.info.adjust_reference_counter(RefCountOp::NotifySenderDestroyed); + } +} + +impl core::ops::Deref for InfoRef { + type Target = &'static super::Info; + + fn deref(&self) -> &Self::Target { + &self.info + } +} + +/// Provides a reference to the driver internals and implements RAII for the internal reference +/// counting for Tx only types. +/// See InfoRef for further doc. +pub(crate) struct TxInfoRef { + info: &'static super::Info, +} + +impl TxInfoRef { + pub(crate) fn new(info: &'static super::Info) -> Self { + info.adjust_reference_counter(RefCountOp::NotifySenderCreated); + Self { info } + } +} + +impl Drop for TxInfoRef { + fn drop(&mut self) { + self.info.adjust_reference_counter(RefCountOp::NotifySenderDestroyed); + } +} + +impl core::ops::Deref for TxInfoRef { + type Target = &'static super::Info; + + fn deref(&self) -> &Self::Target { + &self.info + } +} + +/// Provides a reference to the driver internals and implements RAII for the internal reference +/// counting for Rx only types. +/// See InfoRef for further doc. +pub(crate) struct RxInfoRef { + info: &'static super::Info, +} + +impl RxInfoRef { + pub(crate) fn new(info: &'static super::Info) -> Self { + info.adjust_reference_counter(RefCountOp::NotifyReceiverCreated); + Self { info } + } +} + +impl Drop for RxInfoRef { + fn drop(&mut self) { + self.info.adjust_reference_counter(RefCountOp::NotifyReceiverDestroyed); + } +} + +impl core::ops::Deref for RxInfoRef { + type Target = &'static super::Info; + + fn deref(&self) -> &Self::Target { + &self.info } } diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 97cb47640..6d91020fc 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs @@ -72,7 +72,7 @@ pub enum TryReadError { /// Internal Operation #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum InternalOperation { +pub enum RefCountOp { /// Notify receiver created NotifyReceiverCreated, /// Notify receiver destroyed diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 2846fb44a..99e40ba62 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -21,7 +21,7 @@ use self::fd::config::*; use self::fd::filter::*; pub use self::fd::{config, filter}; pub use super::common::{BufferedCanReceiver, BufferedCanSender}; -use super::common::{RxGuard, TxGuard}; +use super::common::{InfoRef, RxInfoRef, TxInfoRef}; use super::enums::*; use super::frame::*; use super::util; @@ -168,11 +168,10 @@ fn calc_ns_per_timer_tick( pub struct CanConfigurator<'d> { _phantom: PhantomData<&'d ()>, config: crate::can::fd::config::FdCanConfig, - info: &'static Info, /// Reference to internals. properties: Properties, periph_clock: crate::time::Hertz, - raii_guards: (TxGuard, RxGuard), + info: InfoRef, } impl<'d> CanConfigurator<'d> { @@ -211,13 +210,9 @@ impl<'d> CanConfigurator<'d> { Self { _phantom: PhantomData, config, - info, properties: Properties::new(T::info()), periph_clock: T::frequency(), - raii_guards: ( - TxGuard::new(info.internal_operation), - RxGuard::new(info.internal_operation), - ), + info: InfoRef::new(info), } } @@ -266,7 +261,7 @@ impl<'d> CanConfigurator<'d> { /// Start in mode. pub fn start(self, mode: OperatingMode) -> Can<'d> { - let ns_per_timer_tick = calc_ns_per_timer_tick(self.info, self.periph_clock, self.config.frame_transmit); + let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit); self.info.state.lock(|s| { s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; }); @@ -274,10 +269,9 @@ impl<'d> CanConfigurator<'d> { Can { _phantom: PhantomData, config: self.config, - info: self.info, _mode: mode, - properties: Properties::new(self.info), - raii_guards: self.raii_guards, + properties: Properties::new(&self.info), + info: InfoRef::new(&self.info), } } @@ -301,10 +295,9 @@ impl<'d> CanConfigurator<'d> { pub struct Can<'d> { _phantom: PhantomData<&'d ()>, config: crate::can::fd::config::FdCanConfig, - info: &'static Info, _mode: OperatingMode, properties: Properties, - raii_guards: (TxGuard, RxGuard), + info: InfoRef, } impl<'d> Can<'d> { @@ -338,12 +331,12 @@ impl<'d> Can<'d> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write(&mut self, frame: &Frame) -> Option { - TxMode::write(self.info, frame).await + TxMode::write(&self.info, frame).await } /// Returns the next received message frame pub async fn read(&mut self) -> Result { - RxMode::read_classic(self.info).await + RxMode::read_classic(&self.info).await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -351,12 +344,12 @@ impl<'d> Can<'d> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { - TxMode::write_fd(self.info, frame).await + TxMode::write_fd(&self.info, frame).await } /// Returns the next received message frame pub async fn read_fd(&mut self) -> Result { - RxMode::read_fd(self.info).await + RxMode::read_fd(&self.info).await } /// Split instance into separate portions: Tx(write), Rx(read), common properties @@ -364,16 +357,14 @@ impl<'d> Can<'d> { ( CanTx { _phantom: PhantomData, - info: self.info, config: self.config, _mode: self._mode, - tx_guard: self.raii_guards.0, + info: TxInfoRef::new(&self.info), }, CanRx { _phantom: PhantomData, - info: self.info, _mode: self._mode, - rx_guard: self.raii_guards.1, + info: RxInfoRef::new(&self.info), }, Properties { info: self.properties.info, @@ -385,10 +376,9 @@ impl<'d> Can<'d> { Can { _phantom: PhantomData, config: tx.config, - info: tx.info, _mode: rx._mode, - properties: Properties::new(tx.info), - raii_guards: (tx.tx_guard, rx.rx_guard), + properties: Properties::new(&tx.info), + info: InfoRef::new(&tx.info), } } @@ -398,7 +388,7 @@ impl<'d> Can<'d> { tx_buf: &'static mut TxBuf, rxb: &'static mut RxBuf, ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { - BufferedCan::new(self.info, self._mode, tx_buf, rxb) + BufferedCan::new(&self.info, self._mode, tx_buf, rxb) } /// Return a buffered instance of driver with CAN FD support. User must supply Buffers @@ -407,7 +397,7 @@ impl<'d> Can<'d> { tx_buf: &'static mut TxFdBuf, rxb: &'static mut RxFdBuf, ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { - BufferedCanFd::new(self.info, self._mode, tx_buf, rxb) + BufferedCanFd::new(&self.info, self._mode, tx_buf, rxb) } } @@ -420,12 +410,11 @@ pub type TxBuf = Channel { _phantom: PhantomData<&'d ()>, - info: &'static Info, _mode: OperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, properties: Properties, - _raii_guards: (TxGuard, RxGuard), + info: InfoRef, } impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { @@ -437,15 +426,11 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, ) -> Self { BufferedCan { _phantom: PhantomData, - info, _mode, tx_buf, rx_buf, properties: Properties::new(info), - _raii_guards: ( - TxGuard::new(info.internal_operation), - RxGuard::new(info.internal_operation), - ), + info: InfoRef::new(info), } .setup() } @@ -486,8 +471,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, pub fn writer(&self) -> BufferedCanSender { BufferedCanSender { tx_buf: self.tx_buf.sender().into(), - waker: self.info.tx_waker, - tx_guard: TxGuard::new(self.info.internal_operation), + info: TxInfoRef::new(&self.info), } } @@ -495,7 +479,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, pub fn reader(&self) -> BufferedCanReceiver { BufferedCanReceiver { rx_buf: self.rx_buf.receiver().into(), - rx_guard: RxGuard::new(self.info.internal_operation), + info: RxInfoRef::new(&self.info), } } } @@ -515,12 +499,11 @@ pub type BufferedFdCanReceiver = super::common::BufferedReceiver<'static, FdEnve /// Buffered FDCAN Instance pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { _phantom: PhantomData<&'d ()>, - info: &'static Info, _mode: OperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, properties: Properties, - _raii_guards: (TxGuard, RxGuard), + info: InfoRef, } impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { @@ -532,15 +515,11 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' ) -> Self { BufferedCanFd { _phantom: PhantomData, - info, _mode, tx_buf, rx_buf, properties: Properties::new(info), - _raii_guards: ( - TxGuard::new(info.internal_operation), - RxGuard::new(info.internal_operation), - ), + info: InfoRef::new(info), } .setup() } @@ -579,20 +558,17 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedFdCanSender { - (self.info.internal_operation)(InternalOperation::NotifySenderCreated); BufferedFdCanSender { tx_buf: self.tx_buf.sender().into(), - waker: self.info.tx_waker, - tx_guard: TxGuard::new(self.info.internal_operation), + info: TxInfoRef::new(&self.info), } } /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub fn reader(&self) -> BufferedFdCanReceiver { - (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedFdCanReceiver { rx_buf: self.rx_buf.receiver().into(), - rx_guard: RxGuard::new(self.info.internal_operation), + info: RxInfoRef::new(&self.info), } } } @@ -600,9 +576,8 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' /// FDCAN Rx only Instance pub struct CanRx<'d> { _phantom: PhantomData<&'d ()>, - info: &'static Info, _mode: OperatingMode, - rx_guard: RxGuard, + info: RxInfoRef, } impl<'d> CanRx<'d> { @@ -620,10 +595,9 @@ impl<'d> CanRx<'d> { /// FDCAN Tx only Instance pub struct CanTx<'d> { _phantom: PhantomData<&'d ()>, - info: &'static Info, config: crate::can::fd::config::FdCanConfig, _mode: OperatingMode, - tx_guard: TxGuard, + info: TxInfoRef, } impl<'c, 'd> CanTx<'d> { @@ -632,7 +606,7 @@ impl<'c, 'd> CanTx<'d> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write(&mut self, frame: &Frame) -> Option { - TxMode::write(self.info, frame).await + TxMode::write(&self.info, frame).await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -640,7 +614,7 @@ impl<'c, 'd> CanTx<'d> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { - TxMode::write_fd(self.info, frame).await + TxMode::write_fd(&self.info, frame).await } } @@ -907,21 +881,56 @@ impl State { } type SharedState = embassy_sync::blocking_mutex::Mutex>; -struct Info { +pub(crate) struct Info { regs: Registers, interrupt0: crate::interrupt::Interrupt, _interrupt1: crate::interrupt::Interrupt, - tx_waker: fn(), - internal_operation: fn(InternalOperation), + pub(crate) tx_waker: fn(), state: SharedState, } +impl Info { + pub(crate) fn adjust_reference_counter(&self, val: RefCountOp) { + self.state.lock(|s| { + let mut mut_state = s.borrow_mut(); + match val { + RefCountOp::NotifySenderCreated => { + mut_state.sender_instance_count += 1; + } + RefCountOp::NotifySenderDestroyed => { + mut_state.sender_instance_count -= 1; + if 0 == mut_state.sender_instance_count { + (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + RefCountOp::NotifyReceiverCreated => { + mut_state.receiver_instance_count += 1; + } + RefCountOp::NotifyReceiverDestroyed => { + mut_state.receiver_instance_count -= 1; + if 0 == mut_state.receiver_instance_count { + (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + } + if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 { + unsafe { + let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap()); + tx_pin.set_as_disconnected(); + let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap()); + rx_pin.set_as_disconnected(); + self.interrupt0.disable(); + } + } + }); + } +} + trait SealedInstance { const MSG_RAM_OFFSET: usize; fn info() -> &'static Info; fn registers() -> crate::can::fd::peripheral::Registers; - fn internal_operation(val: InternalOperation); } /// Instance trait @@ -943,41 +952,6 @@ macro_rules! impl_fdcan { impl SealedInstance for peripherals::$inst { const MSG_RAM_OFFSET: usize = $msg_ram_offset; - fn internal_operation(val: InternalOperation) { - peripherals::$inst::info().state.lock(|s| { - let mut mut_state = s.borrow_mut(); - match val { - InternalOperation::NotifySenderCreated => { - mut_state.sender_instance_count += 1; - } - InternalOperation::NotifySenderDestroyed => { - mut_state.sender_instance_count -= 1; - if ( 0 == mut_state.sender_instance_count) { - (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - } - InternalOperation::NotifyReceiverCreated => { - mut_state.receiver_instance_count += 1; - } - InternalOperation::NotifyReceiverDestroyed => { - mut_state.receiver_instance_count -= 1; - if ( 0 == mut_state.receiver_instance_count) { - (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - } - } - if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 { - unsafe { - let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap()); - tx_pin.set_as_disconnected(); - let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap()); - rx_pin.set_as_disconnected(); - rcc::disable::(); - } - } - }); - } - fn info() -> &'static Info { static INFO: Info = Info { @@ -985,7 +959,6 @@ macro_rules! impl_fdcan { interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ, _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ, tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend, - internal_operation: peripherals::$inst::internal_operation, state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())), }; &INFO