Skip to content

Commit 0cf9511

Browse files
authored
Merge pull request #3956 from cschuhen/stm_can_count_instances_fix_3610
STM32 CAN: Count senders and receivers so that we don't close down early.
2 parents 05c6640 + 424d207 commit 0cf9511

File tree

4 files changed

+199
-69
lines changed

4 files changed

+199
-69
lines changed

embassy-stm32/src/can/bxcan/mod.rs

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use self::registers::{Registers, RxFifo};
1717
pub use super::common::{BufferedCanReceiver, BufferedCanSender};
1818
use super::frame::{Envelope, Frame};
1919
use super::util;
20-
use crate::can::enums::{BusError, TryReadError};
20+
use crate::can::enums::{BusError, InternalOperation, TryReadError};
2121
use crate::gpio::{AfType, OutputType, Pull, Speed};
2222
use crate::interrupt::typelevel::Interrupt;
2323
use crate::rcc::{self, RccPeripheral};
@@ -685,22 +685,18 @@ impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> {
685685

686686
/// Returns a sender that can be used for sending CAN frames.
687687
pub fn writer(&self) -> BufferedCanSender {
688+
(self.info.internal_operation)(InternalOperation::NotifySenderCreated);
688689
BufferedCanSender {
689690
tx_buf: self.tx_buf.sender().into(),
690691
waker: self.info.tx_waker,
692+
internal_operation: self.info.internal_operation,
691693
}
692694
}
693695
}
694696

695697
impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> {
696698
fn drop(&mut self) {
697-
critical_section::with(|_| {
698-
let state = self.state as *const State;
699-
unsafe {
700-
let mut_state = state as *mut State;
701-
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
702-
}
703-
});
699+
(self.info.internal_operation)(InternalOperation::NotifySenderDestroyed);
704700
}
705701
}
706702

@@ -825,7 +821,11 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
825821

826822
/// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
827823
pub fn reader(&self) -> BufferedCanReceiver {
828-
self.rx_buf.receiver().into()
824+
(self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
825+
BufferedCanReceiver {
826+
rx_buf: self.rx_buf.receiver().into(),
827+
internal_operation: self.info.internal_operation,
828+
}
829829
}
830830

831831
/// Accesses the filter banks owned by this CAN peripheral.
@@ -839,13 +839,7 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
839839

840840
impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> {
841841
fn drop(&mut self) {
842-
critical_section::with(|_| {
843-
let state = self.state as *const State;
844-
unsafe {
845-
let mut_state = state as *mut State;
846-
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
847-
}
848-
});
842+
(self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
849843
}
850844
}
851845

@@ -1048,6 +1042,8 @@ pub(crate) struct State {
10481042
pub(crate) rx_mode: RxMode,
10491043
pub(crate) tx_mode: TxMode,
10501044
pub err_waker: AtomicWaker,
1045+
receiver_instance_count: usize,
1046+
sender_instance_count: usize,
10511047
}
10521048

10531049
impl State {
@@ -1056,6 +1052,8 @@ impl State {
10561052
rx_mode: RxMode::NonBuffered(AtomicWaker::new()),
10571053
tx_mode: TxMode::NonBuffered(AtomicWaker::new()),
10581054
err_waker: AtomicWaker::new(),
1055+
receiver_instance_count: 1,
1056+
sender_instance_count: 1,
10591057
}
10601058
}
10611059
}
@@ -1067,6 +1065,7 @@ pub(crate) struct Info {
10671065
rx1_interrupt: crate::interrupt::Interrupt,
10681066
sce_interrupt: crate::interrupt::Interrupt,
10691067
tx_waker: fn(),
1068+
internal_operation: fn(InternalOperation),
10701069

10711070
/// The total number of filter banks available to the instance.
10721071
///
@@ -1079,6 +1078,7 @@ trait SealedInstance {
10791078
fn regs() -> crate::pac::can::Can;
10801079
fn state() -> &'static State;
10811080
unsafe fn mut_state() -> &'static mut State;
1081+
fn internal_operation(val: InternalOperation);
10821082
}
10831083

10841084
/// CAN instance trait.
@@ -1136,6 +1136,7 @@ foreach_peripheral!(
11361136
rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ,
11371137
sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ,
11381138
tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend,
1139+
internal_operation: peripherals::$inst::internal_operation,
11391140
num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS,
11401141
};
11411142
&INFO
@@ -1151,6 +1152,37 @@ foreach_peripheral!(
11511152
fn state() -> &'static State {
11521153
unsafe { peripherals::$inst::mut_state() }
11531154
}
1155+
1156+
1157+
fn internal_operation(val: InternalOperation) {
1158+
critical_section::with(|_| {
1159+
//let state = self.state as *const State;
1160+
unsafe {
1161+
//let mut_state = state as *mut State;
1162+
let mut_state = peripherals::$inst::mut_state();
1163+
match val {
1164+
InternalOperation::NotifySenderCreated => {
1165+
mut_state.sender_instance_count += 1;
1166+
}
1167+
InternalOperation::NotifySenderDestroyed => {
1168+
mut_state.sender_instance_count -= 1;
1169+
if ( 0 == mut_state.sender_instance_count) {
1170+
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
1171+
}
1172+
}
1173+
InternalOperation::NotifyReceiverCreated => {
1174+
mut_state.receiver_instance_count += 1;
1175+
}
1176+
InternalOperation::NotifyReceiverDestroyed => {
1177+
mut_state.receiver_instance_count -= 1;
1178+
if ( 0 == mut_state.receiver_instance_count) {
1179+
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
1180+
}
1181+
}
1182+
}
1183+
}
1184+
});
1185+
}
11541186
}
11551187

11561188
impl Instance for peripherals::$inst {

embassy-stm32/src/can/common.rs

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,22 @@ pub(crate) struct FdBufferedTxInner {
2222
}
2323

2424
/// Sender that can be used for sending CAN frames.
25-
#[derive(Copy, Clone)]
26-
pub struct BufferedCanSender {
27-
pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>,
25+
pub struct BufferedSender<'ch, FRAME> {
26+
pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'ch, FRAME>,
2827
pub(crate) waker: fn(),
28+
pub(crate) internal_operation: fn(InternalOperation),
2929
}
3030

31-
impl BufferedCanSender {
31+
impl<'ch, FRAME> BufferedSender<'ch, FRAME> {
3232
/// Async write frame to TX buffer.
33-
pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError<Frame>> {
33+
pub fn try_write(&mut self, frame: FRAME) -> Result<(), embassy_sync::channel::TrySendError<FRAME>> {
3434
self.tx_buf.try_send(frame)?;
3535
(self.waker)();
3636
Ok(())
3737
}
3838

3939
/// Async write frame to TX buffer.
40-
pub async fn write(&mut self, frame: Frame) {
40+
pub async fn write(&mut self, frame: FRAME) {
4141
self.tx_buf.send(frame).await;
4242
(self.waker)();
4343
}
@@ -48,5 +48,77 @@ impl BufferedCanSender {
4848
}
4949
}
5050

51+
impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> {
52+
fn clone(&self) -> Self {
53+
(self.internal_operation)(InternalOperation::NotifySenderCreated);
54+
Self {
55+
tx_buf: self.tx_buf,
56+
waker: self.waker,
57+
internal_operation: self.internal_operation,
58+
}
59+
}
60+
}
61+
62+
impl<'ch, FRAME> Drop for BufferedSender<'ch, FRAME> {
63+
fn drop(&mut self) {
64+
(self.internal_operation)(InternalOperation::NotifySenderDestroyed);
65+
}
66+
}
67+
68+
/// Sender that can be used for sending Classic CAN frames.
69+
pub type BufferedCanSender = BufferedSender<'static, Frame>;
70+
5171
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
52-
pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result<Envelope, BusError>>;
72+
pub struct BufferedReceiver<'ch, ENVELOPE> {
73+
pub(crate) rx_buf: embassy_sync::channel::DynamicReceiver<'ch, Result<ENVELOPE, BusError>>,
74+
pub(crate) internal_operation: fn(InternalOperation),
75+
}
76+
77+
impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> {
78+
/// Receive the next frame.
79+
///
80+
/// See [`Channel::receive()`].
81+
pub fn receive(&self) -> embassy_sync::channel::DynamicReceiveFuture<'_, Result<ENVELOPE, BusError>> {
82+
self.rx_buf.receive()
83+
}
84+
85+
/// Attempt to immediately receive the next frame.
86+
///
87+
/// See [`Channel::try_receive()`]
88+
pub fn try_receive(&self) -> Result<Result<ENVELOPE, BusError>, embassy_sync::channel::TryReceiveError> {
89+
self.rx_buf.try_receive()
90+
}
91+
92+
/// Allows a poll_fn to poll until the channel is ready to receive
93+
///
94+
/// See [`Channel::poll_ready_to_receive()`]
95+
pub fn poll_ready_to_receive(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
96+
self.rx_buf.poll_ready_to_receive(cx)
97+
}
98+
99+
/// Poll the channel for the next frame
100+
///
101+
/// See [`Channel::poll_receive()`]
102+
pub fn poll_receive(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<Result<ENVELOPE, BusError>> {
103+
self.rx_buf.poll_receive(cx)
104+
}
105+
}
106+
107+
impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> {
108+
fn clone(&self) -> Self {
109+
(self.internal_operation)(InternalOperation::NotifyReceiverCreated);
110+
Self {
111+
rx_buf: self.rx_buf,
112+
internal_operation: self.internal_operation,
113+
}
114+
}
115+
}
116+
117+
impl<'ch, ENVELOPE> Drop for BufferedReceiver<'ch, ENVELOPE> {
118+
fn drop(&mut self) {
119+
(self.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
120+
}
121+
}
122+
123+
/// A BufferedCanReceiver for Classic CAN frames.
124+
pub type BufferedCanReceiver = BufferedReceiver<'static, Envelope>;

embassy-stm32/src/can/enums.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,17 @@ pub enum TryReadError {
6868
/// Receive buffer is empty
6969
Empty,
7070
}
71+
72+
/// Internal Operation
73+
#[derive(Debug)]
74+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75+
pub enum InternalOperation {
76+
/// Notify receiver created
77+
NotifyReceiverCreated,
78+
/// Notify receiver destroyed
79+
NotifyReceiverDestroyed,
80+
/// Notify sender created
81+
NotifySenderCreated,
82+
/// Notify sender destroyed
83+
NotifySenderDestroyed,
84+
}

0 commit comments

Comments
 (0)