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
This commit is contained in:
Corey Schuhen 2025-06-07 17:25:15 +10:00
parent e75b344089
commit 8b280688e1
4 changed files with 249 additions and 227 deletions

View File

@ -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<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> 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<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> 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<Envelope, BusError> {
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<Envelope, TryReadError> {
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<TX_BUF_SIZE>,
) -> BufferedCanTx<'d, TX_BUF_SIZE> {
BufferedCanTx::new(self.info, self, txb)
BufferedCanTx::new(&self.info, self, txb)
}
}
@ -655,23 +655,30 @@ pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame,
/// Buffered CAN driver, transmit half.
pub struct BufferedCanTx<'d, const TX_BUF_SIZE: usize> {
info: &'static Info,
info: TxInfoRef,
_tx: CanTx<'d>,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
}
impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> {
fn new(info: &'static Info, _tx: CanTx<'d>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> 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<Envelope, BusError> {
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<Envelope, TryReadError> {
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<RX_BUF_SIZE>,
) -> 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<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<
/// CAN driver, receive half in Buffered mode.
pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> {
info: &'static Info,
info: RxInfoRef,
rx: CanRx<'d>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
}
impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
fn new(info: &'static Info, rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> 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<T: Instance>(&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;

View File

@ -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<FRAME>> {
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<ENVELOPE, BusError>>,
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
}
}

View File

@ -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

View File

@ -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<Frame> {
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<Envelope, BusError> {
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<FdFrame> {
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<FdEnvelope, BusError> {
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<TX_BUF_SIZE>,
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
) -> 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<TX_BUF_SIZE>,
rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
) -> 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<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame,
/// Buffered FDCAN Instance
pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
_phantom: PhantomData<&'d ()>,
info: &'static Info,
_mode: OperatingMode,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
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<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
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<Frame> {
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<FdFrame> {
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<CriticalSectionRawMutex, core::cell::RefCell<State>>;
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::<peripherals::$inst>();
}
}
});
}
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