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(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<ENVELOPE, BusError>>,
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);
}
}

View File

@ -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<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>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
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<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
) -> 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<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>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
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<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
) -> 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),