diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 386d4467c..651fa12d5 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -25,7 +25,7 @@ pub(crate) struct FdBufferedTxInner { pub struct BufferedSender<'ch, FRAME> { pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>, pub(crate) waker: fn(), - pub(crate) internal_operation: fn(InternalOperation), + pub(crate) tx_guard: TxGuard, } impl<'ch, FRAME> BufferedSender<'ch, FRAME> { @@ -50,28 +50,21 @@ impl<'ch, FRAME> BufferedSender<'ch, FRAME> { impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> { fn clone(&self) -> Self { - (self.internal_operation)(InternalOperation::NotifySenderCreated); Self { tx_buf: self.tx_buf, waker: self.waker, - internal_operation: self.internal_operation, + tx_guard: TxGuard::new(self.tx_guard.internal_operation), } } } -impl<'ch, FRAME> Drop for BufferedSender<'ch, FRAME> { - fn drop(&mut self) { - (self.internal_operation)(InternalOperation::NotifySenderDestroyed); - } -} - /// Sender that can be used for sending Classic CAN frames. 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) internal_operation: fn(InternalOperation), + pub(crate) rx_guard: RxGuard, } impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> { @@ -106,19 +99,47 @@ impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> { impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> { fn clone(&self) -> Self { - (self.internal_operation)(InternalOperation::NotifyReceiverCreated); Self { rx_buf: self.rx_buf, - internal_operation: self.internal_operation, + rx_guard: RxGuard::new(self.rx_guard.internal_operation), } } } -impl<'ch, ENVELOPE> Drop for BufferedReceiver<'ch, ENVELOPE> { - fn drop(&mut self) { - (self.internal_operation)(InternalOperation::NotifyReceiverDestroyed); - } -} - /// 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), +} +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); + } +} + +/// 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 { + fn drop(&mut self) { + (self.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + } +} diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 97d22315a..2846fb44a 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -21,6 +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::enums::*; use super::frame::*; use super::util; @@ -171,6 +172,7 @@ pub struct CanConfigurator<'d> { /// Reference to internals. properties: Properties, periph_clock: crate::time::Hertz, + raii_guards: (TxGuard, RxGuard), } impl<'d> CanConfigurator<'d> { @@ -194,8 +196,6 @@ impl<'d> CanConfigurator<'d> { s.borrow_mut().tx_pin_port = Some(tx.pin_port()); s.borrow_mut().rx_pin_port = Some(rx.pin_port()); }); - (info.internal_operation)(InternalOperation::NotifySenderCreated); - (info.internal_operation)(InternalOperation::NotifyReceiverCreated); let mut config = crate::can::fd::config::FdCanConfig::default(); config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); @@ -214,6 +214,10 @@ impl<'d> CanConfigurator<'d> { info, properties: Properties::new(T::info()), periph_clock: T::frequency(), + raii_guards: ( + TxGuard::new(info.internal_operation), + RxGuard::new(info.internal_operation), + ), } } @@ -267,14 +271,13 @@ impl<'d> CanConfigurator<'d> { s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; }); self.info.regs.into_mode(self.config, mode); - (self.info.internal_operation)(InternalOperation::NotifySenderCreated); - (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); Can { _phantom: PhantomData, config: self.config, info: self.info, _mode: mode, properties: Properties::new(self.info), + raii_guards: self.raii_guards, } } @@ -294,13 +297,6 @@ impl<'d> CanConfigurator<'d> { } } -impl<'d> Drop for CanConfigurator<'d> { - fn drop(&mut self) { - (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); - (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); - } -} - /// FDCAN Instance pub struct Can<'d> { _phantom: PhantomData<&'d ()>, @@ -308,6 +304,7 @@ pub struct Can<'d> { info: &'static Info, _mode: OperatingMode, properties: Properties, + raii_guards: (TxGuard, RxGuard), } impl<'d> Can<'d> { @@ -364,19 +361,19 @@ impl<'d> Can<'d> { /// Split instance into separate portions: Tx(write), Rx(read), common properties pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) { - (self.info.internal_operation)(InternalOperation::NotifySenderCreated); - (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); ( CanTx { _phantom: PhantomData, info: self.info, config: self.config, _mode: self._mode, + tx_guard: self.raii_guards.0, }, CanRx { _phantom: PhantomData, info: self.info, _mode: self._mode, + rx_guard: self.raii_guards.1, }, Properties { info: self.properties.info, @@ -385,14 +382,13 @@ impl<'d> Can<'d> { } /// Join split rx and tx portions back together pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self { - (tx.info.internal_operation)(InternalOperation::NotifySenderCreated); - (tx.info.internal_operation)(InternalOperation::NotifyReceiverCreated); 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), } } @@ -415,13 +411,6 @@ impl<'d> Can<'d> { } } -impl<'d> Drop for Can<'d> { - fn drop(&mut self) { - (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); - (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); - } -} - /// User supplied buffer for RX Buffering pub type RxBuf = Channel, BUF_SIZE>; @@ -436,6 +425,7 @@ pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, properties: Properties, + _raii_guards: (TxGuard, RxGuard), } impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { @@ -445,8 +435,6 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, ) -> Self { - (info.internal_operation)(InternalOperation::NotifySenderCreated); - (info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedCan { _phantom: PhantomData, info, @@ -454,6 +442,10 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, tx_buf, rx_buf, properties: Properties::new(info), + _raii_guards: ( + TxGuard::new(info.internal_operation), + RxGuard::new(info.internal_operation), + ), } .setup() } @@ -492,31 +484,22 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, /// 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, + tx_guard: TxGuard::new(self.info.internal_operation), } } /// 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, + rx_guard: RxGuard::new(self.info.internal_operation), } } } -impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { - fn drop(&mut self) { - (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); - (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); - } -} - /// User supplied buffer for RX Buffering pub type RxFdBuf = Channel, BUF_SIZE>; @@ -537,6 +520,7 @@ pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, properties: Properties, + _raii_guards: (TxGuard, RxGuard), } impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { @@ -546,8 +530,6 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, ) -> Self { - (info.internal_operation)(InternalOperation::NotifySenderCreated); - (info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedCanFd { _phantom: PhantomData, info, @@ -555,6 +537,10 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' tx_buf, rx_buf, properties: Properties::new(info), + _raii_guards: ( + TxGuard::new(info.internal_operation), + RxGuard::new(info.internal_operation), + ), } .setup() } @@ -597,7 +583,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' BufferedFdCanSender { tx_buf: self.tx_buf.sender().into(), waker: self.info.tx_waker, - internal_operation: self.info.internal_operation, + tx_guard: TxGuard::new(self.info.internal_operation), } } @@ -606,23 +592,17 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedFdCanReceiver { rx_buf: self.rx_buf.receiver().into(), - internal_operation: self.info.internal_operation, + rx_guard: RxGuard::new(self.info.internal_operation), } } } -impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { - fn drop(&mut self) { - (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); - (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); - } -} - /// FDCAN Rx only Instance pub struct CanRx<'d> { _phantom: PhantomData<&'d ()>, info: &'static Info, _mode: OperatingMode, + rx_guard: RxGuard, } impl<'d> CanRx<'d> { @@ -637,18 +617,13 @@ impl<'d> CanRx<'d> { } } -impl<'d> Drop for CanRx<'d> { - fn drop(&mut self) { - (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); - } -} - /// 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, } impl<'c, 'd> CanTx<'d> { @@ -669,12 +644,6 @@ impl<'c, 'd> CanTx<'d> { } } -impl<'d> Drop for CanTx<'d> { - fn drop(&mut self) { - (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); - } -} - enum RxMode { NonBuffered(AtomicWaker), ClassicBuffered(super::common::ClassicBufferedRxInner),