Add TxGuard and RxGuard which impl RAII for the STM32 CAN reference counting

This commit is contained in:
Tobias Naumann 2025-06-05 15:24:29 +02:00 committed by Corey Schuhen
parent b2dcdad51d
commit e75b344089
2 changed files with 66 additions and 76 deletions

View File

@ -25,7 +25,7 @@ pub(crate) struct FdBufferedTxInner {
pub struct BufferedSender<'ch, FRAME> { pub struct BufferedSender<'ch, FRAME> {
pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>, pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>,
pub(crate) waker: fn(), pub(crate) waker: fn(),
pub(crate) internal_operation: fn(InternalOperation), pub(crate) tx_guard: TxGuard,
} }
impl<'ch, FRAME> BufferedSender<'ch, FRAME> { impl<'ch, FRAME> BufferedSender<'ch, FRAME> {
@ -50,28 +50,21 @@ impl<'ch, FRAME> BufferedSender<'ch, FRAME> {
impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> { impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
(self.internal_operation)(InternalOperation::NotifySenderCreated);
Self { Self {
tx_buf: self.tx_buf, tx_buf: self.tx_buf,
waker: self.waker, 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. /// Sender that can be used for sending Classic CAN frames.
pub type BufferedCanSender = BufferedSender<'static, Frame>; 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. /// 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 struct BufferedReceiver<'ch, ENVELOPE> {
pub(crate) rx_buf: embassy_sync::channel::SendDynamicReceiver<'ch, Result<ENVELOPE, BusError>>, pub(crate) rx_buf: embassy_sync::channel::SendDynamicReceiver<'ch, Result<ENVELOPE, BusError>>,
pub(crate) internal_operation: fn(InternalOperation), pub(crate) rx_guard: RxGuard,
} }
impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> { impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> {
@ -106,19 +99,47 @@ impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> {
impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> { impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
(self.internal_operation)(InternalOperation::NotifyReceiverCreated);
Self { Self {
rx_buf: self.rx_buf, 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. /// A BufferedCanReceiver for Classic CAN frames.
pub type BufferedCanReceiver = BufferedReceiver<'static, Envelope>; 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);
}
}

View File

@ -21,6 +21,7 @@ use self::fd::config::*;
use self::fd::filter::*; use self::fd::filter::*;
pub use self::fd::{config, filter}; pub use self::fd::{config, filter};
pub use super::common::{BufferedCanReceiver, BufferedCanSender}; pub use super::common::{BufferedCanReceiver, BufferedCanSender};
use super::common::{RxGuard, TxGuard};
use super::enums::*; use super::enums::*;
use super::frame::*; use super::frame::*;
use super::util; use super::util;
@ -171,6 +172,7 @@ pub struct CanConfigurator<'d> {
/// Reference to internals. /// Reference to internals.
properties: Properties, properties: Properties,
periph_clock: crate::time::Hertz, periph_clock: crate::time::Hertz,
raii_guards: (TxGuard, RxGuard),
} }
impl<'d> CanConfigurator<'d> { 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().tx_pin_port = Some(tx.pin_port());
s.borrow_mut().rx_pin_port = Some(rx.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(); let mut config = crate::can::fd::config::FdCanConfig::default();
config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
@ -214,6 +214,10 @@ impl<'d> CanConfigurator<'d> {
info, info,
properties: Properties::new(T::info()), properties: Properties::new(T::info()),
periph_clock: T::frequency(), 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; s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick;
}); });
self.info.regs.into_mode(self.config, mode); self.info.regs.into_mode(self.config, mode);
(self.info.internal_operation)(InternalOperation::NotifySenderCreated);
(self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
Can { Can {
_phantom: PhantomData, _phantom: PhantomData,
config: self.config, config: self.config,
info: self.info, info: self.info,
_mode: mode, _mode: mode,
properties: Properties::new(self.info), 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 /// FDCAN Instance
pub struct Can<'d> { pub struct Can<'d> {
_phantom: PhantomData<&'d ()>, _phantom: PhantomData<&'d ()>,
@ -308,6 +304,7 @@ pub struct Can<'d> {
info: &'static Info, info: &'static Info,
_mode: OperatingMode, _mode: OperatingMode,
properties: Properties, properties: Properties,
raii_guards: (TxGuard, RxGuard),
} }
impl<'d> Can<'d> { impl<'d> Can<'d> {
@ -364,19 +361,19 @@ impl<'d> Can<'d> {
/// Split instance into separate portions: Tx(write), Rx(read), common properties /// Split instance into separate portions: Tx(write), Rx(read), common properties
pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) { pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) {
(self.info.internal_operation)(InternalOperation::NotifySenderCreated);
(self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
( (
CanTx { CanTx {
_phantom: PhantomData, _phantom: PhantomData,
info: self.info, info: self.info,
config: self.config, config: self.config,
_mode: self._mode, _mode: self._mode,
tx_guard: self.raii_guards.0,
}, },
CanRx { CanRx {
_phantom: PhantomData, _phantom: PhantomData,
info: self.info, info: self.info,
_mode: self._mode, _mode: self._mode,
rx_guard: self.raii_guards.1,
}, },
Properties { Properties {
info: self.properties.info, info: self.properties.info,
@ -385,14 +382,13 @@ impl<'d> Can<'d> {
} }
/// Join split rx and tx portions back together /// Join split rx and tx portions back together
pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self { pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self {
(tx.info.internal_operation)(InternalOperation::NotifySenderCreated);
(tx.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
Can { Can {
_phantom: PhantomData, _phantom: PhantomData,
config: tx.config, config: tx.config,
info: tx.info, info: tx.info,
_mode: rx._mode, _mode: rx._mode,
properties: Properties::new(tx.info), 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 /// User supplied buffer for RX Buffering
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>; pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
@ -436,6 +425,7 @@ pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
tx_buf: &'static TxBuf<TX_BUF_SIZE>, tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>, rx_buf: &'static RxBuf<RX_BUF_SIZE>,
properties: Properties, 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> { 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<TX_BUF_SIZE>, tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>, rx_buf: &'static RxBuf<RX_BUF_SIZE>,
) -> Self { ) -> Self {
(info.internal_operation)(InternalOperation::NotifySenderCreated);
(info.internal_operation)(InternalOperation::NotifyReceiverCreated);
BufferedCan { BufferedCan {
_phantom: PhantomData, _phantom: PhantomData,
info, info,
@ -454,6 +442,10 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d,
tx_buf, tx_buf,
rx_buf, rx_buf,
properties: Properties::new(info), properties: Properties::new(info),
_raii_guards: (
TxGuard::new(info.internal_operation),
RxGuard::new(info.internal_operation),
),
} }
.setup() .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. /// Returns a sender that can be used for sending CAN frames.
pub fn writer(&self) -> BufferedCanSender { pub fn writer(&self) -> BufferedCanSender {
(self.info.internal_operation)(InternalOperation::NotifySenderCreated);
BufferedCanSender { BufferedCanSender {
tx_buf: self.tx_buf.sender().into(), tx_buf: self.tx_buf.sender().into(),
waker: self.info.tx_waker, 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. /// 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 { pub fn reader(&self) -> BufferedCanReceiver {
(self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
BufferedCanReceiver { BufferedCanReceiver {
rx_buf: self.rx_buf.receiver().into(), 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 /// User supplied buffer for RX Buffering
pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>; pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>;
@ -537,6 +520,7 @@ pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
properties: Properties, 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> { 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<TX_BUF_SIZE>, tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
) -> Self { ) -> Self {
(info.internal_operation)(InternalOperation::NotifySenderCreated);
(info.internal_operation)(InternalOperation::NotifyReceiverCreated);
BufferedCanFd { BufferedCanFd {
_phantom: PhantomData, _phantom: PhantomData,
info, info,
@ -555,6 +537,10 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
tx_buf, tx_buf,
rx_buf, rx_buf,
properties: Properties::new(info), properties: Properties::new(info),
_raii_guards: (
TxGuard::new(info.internal_operation),
RxGuard::new(info.internal_operation),
),
} }
.setup() .setup()
} }
@ -597,7 +583,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
BufferedFdCanSender { BufferedFdCanSender {
tx_buf: self.tx_buf.sender().into(), tx_buf: self.tx_buf.sender().into(),
waker: self.info.tx_waker, 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); (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
BufferedFdCanReceiver { BufferedFdCanReceiver {
rx_buf: self.rx_buf.receiver().into(), 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 /// FDCAN Rx only Instance
pub struct CanRx<'d> { pub struct CanRx<'d> {
_phantom: PhantomData<&'d ()>, _phantom: PhantomData<&'d ()>,
info: &'static Info, info: &'static Info,
_mode: OperatingMode, _mode: OperatingMode,
rx_guard: RxGuard,
} }
impl<'d> CanRx<'d> { 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 /// FDCAN Tx only Instance
pub struct CanTx<'d> { pub struct CanTx<'d> {
_phantom: PhantomData<&'d ()>, _phantom: PhantomData<&'d ()>,
info: &'static Info, info: &'static Info,
config: crate::can::fd::config::FdCanConfig, config: crate::can::fd::config::FdCanConfig,
_mode: OperatingMode, _mode: OperatingMode,
tx_guard: TxGuard,
} }
impl<'c, 'd> CanTx<'d> { 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 { enum RxMode {
NonBuffered(AtomicWaker), NonBuffered(AtomicWaker),
ClassicBuffered(super::common::ClassicBufferedRxInner), ClassicBuffered(super::common::ClassicBufferedRxInner),