va416xx_hal/can/
asynch.rs

1use core::{
2    future::Future,
3    sync::atomic::{AtomicU8, Ordering},
4};
5
6use crate::can::regs::BufferState;
7
8use super::{
9    regs::{DiagnosticRegister, InterruptClear, MmioCan, StatusPending},
10    CanChannelLowLevel, CanFrame, CanId, InvalidBufferIndexError,
11};
12
13#[derive(Debug)]
14pub enum TxChannelState {
15    Unconfigured = 0,
16    Idle = 1,
17    TxDataFrame = 2,
18    TxRtrTransmission = 3,
19    TxRtrReception = 4,
20    Finished = 5,
21}
22
23static TX_STATES: [AtomicU8; 15] = [const { AtomicU8::new(0) }; 15];
24static TX_WAKERS: [embassy_sync::waitqueue::AtomicWaker; 15] =
25    [const { embassy_sync::waitqueue::AtomicWaker::new() }; 15];
26
27#[derive(Debug, PartialEq, Eq, Clone, Copy)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum TxEventId {
30    /// Buffer state went from [BufferState::TxOnce] to [BufferState::TxNotActive].
31    TxDataFrame,
32    /// Buffer state went from [BufferState::TxOnce] to [BufferState::TxNotActive] for a remote
33    /// frame (RTR bit set). Channel might be in reception mode [BufferState::RxReady] now.
34    TxRemoteFrame,
35    /// A response to a remote frame was performed successfully, and the buffer state went from
36    /// [BufferState::TxOnceRtr] to [BufferState::TxRtr].
37    RtrResponse,
38    /// A remote frame was received and the transmission of a response frame was scheduled. The
39    /// buffer state went from [BufferState::TxRtr] to [BufferState::TxOnceRtr].
40    TransmitScheduling,
41}
42
43#[derive(Debug)]
44pub enum InterruptResult {
45    NoInterrupt,
46    ReceivedFrame {
47        channel_index: usize,
48        frame: CanFrame,
49    },
50    TransmissionEvent {
51        channel_index: usize,
52        id: TxEventId,
53    },
54}
55
56#[derive(Debug)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub enum InterruptError {
59    UnexpectedError,
60    InvalidInterruptId(StatusPending),
61    InvalidStatus(u8),
62    UnexpectedState(BufferState),
63    CanError(DiagnosticRegister),
64}
65
66/// This interrupt handler allow asynchronous transmission and reception of CAN frames.
67///
68/// This handler will re-configure a channel to [BufferState::RxReady] after successfull reception
69/// of a frame without disabling the interrupts, assuming that the user wants to immediately
70/// receive the next frame on the channel.
71/// The user should re-configure the buffer state to [BufferState::RxNotActive] if the reception
72/// should be disabled.
73///
74/// The handler will re-configure a channel to [BufferState::TxNotActive] instead of
75/// [BufferState::RxReady] if the completed frame transmission was a remote frame and after
76/// successfully having received a response to that remote frame. The assumption is that this
77/// channel is used to request more frames. If the argument `reconfigure_tx_rtr_to_tx` is set to
78/// true, the channel will automatically be configured back to [BufferState::TxNotActive] with
79/// interrupts for the respective channel disabled after transmission of a remote frame.
80///
81/// The handler will not disable the interrupts realted to the TX RTR and TX RTR ONCE auto-response
82/// functionality of the CAN peripheral. It will report the event type to the caller via the
83/// [TxEventId] enumeration.
84pub fn on_interrupt_can(
85    id: CanId,
86    reconfigure_tx_rtr_to_tx: bool,
87) -> Result<InterruptResult, InterruptError> {
88    let mut regs = unsafe { id.steal_regs() };
89    // Check if any interrupts are enabled.
90    let ie = regs.read_ien();
91    if ie.raw_value() == 0 {
92        return Ok(InterruptResult::NoInterrupt);
93    }
94    let pending_id = regs.read_status_pending();
95    if pending_id.interrupt_id().is_none() {
96        regs.write_iclr(InterruptClear::new_with_raw_value(0xFFFF_FFFF));
97        return Err(InterruptError::InvalidInterruptId(pending_id));
98    }
99    match pending_id.interrupt_id().unwrap() {
100        super::regs::CanInterruptId::None => Ok(InterruptResult::NoInterrupt),
101        super::regs::CanInterruptId::Error => Err(InterruptError::CanError(regs.read_diag())),
102        super::regs::CanInterruptId::Buffer(idx) => {
103            let mut channel = unsafe { CanChannelLowLevel::steal_unchecked(id, idx) };
104            let status = channel.read_state();
105            if let Err(e) = status {
106                let mut clr = InterruptClear::new_with_raw_value(0);
107                clr.set_buffer(idx, true);
108                regs.write_iclr(clr);
109                regs.modify_ien(|mut val| {
110                    val.set_buffer(idx, false);
111                    val
112                });
113                return Err(InterruptError::InvalidStatus(e));
114            }
115            let buf_state = status.unwrap();
116            if buf_state == BufferState::TxNotActive {
117                let tx_state = TX_STATES[idx].load(Ordering::Relaxed);
118                clear_and_disable_interrupt(&mut regs, idx);
119                // Handle reading frames, updating states etc.
120                if tx_state == TxChannelState::TxDataFrame as u8 {
121                    // Transmission complete.
122                    TX_STATES[idx].store(TxChannelState::Finished as u8, Ordering::Relaxed);
123                    TX_WAKERS[idx].wake();
124                    return Ok(InterruptResult::TransmissionEvent {
125                        channel_index: idx,
126                        id: TxEventId::TxDataFrame,
127                    });
128                }
129            }
130            if buf_state == BufferState::RxReady {
131                let tx_state = TX_STATES[idx].load(Ordering::Relaxed);
132                if tx_state == TxChannelState::TxRtrTransmission as u8 {
133                    if reconfigure_tx_rtr_to_tx {
134                        channel.write_state(BufferState::TxNotActive);
135                        clear_and_disable_interrupt(&mut regs, idx);
136                        // Transmission complete.
137                        TX_STATES[idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
138                    } else {
139                        // Do not disable interrupt, channel is now used to receive the frame.
140                        clear_interrupt(&mut regs, idx);
141                        // Transmission complete.
142                        TX_STATES[idx]
143                            .store(TxChannelState::TxRtrReception as u8, Ordering::Relaxed);
144                    }
145                    TX_WAKERS[idx].wake();
146                    return Ok(InterruptResult::TransmissionEvent {
147                        channel_index: idx,
148                        id: TxEventId::TxRemoteFrame,
149                    });
150                }
151            }
152            if buf_state == BufferState::RxOverrun || buf_state == BufferState::RxFull {
153                let tx_state = TX_STATES[idx].load(Ordering::Relaxed);
154                // Do not disable interrupt and assume continuous reception.
155                clear_interrupt(&mut regs, idx);
156                let frame = channel.read_frame_unchecked();
157                if tx_state == TxChannelState::TxRtrReception as u8 {
158                    // Reception of response complete. We can release the channel for TX (or RX)
159                    // usage again.
160                    TX_STATES[idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
161                    channel.write_state(BufferState::TxNotActive);
162                } else {
163                    // Assume continous reception of frames.
164                    channel.write_state(BufferState::RxReady);
165                }
166                return Ok(InterruptResult::ReceivedFrame {
167                    channel_index: idx,
168                    frame,
169                });
170            }
171            if buf_state == BufferState::TxRtr {
172                // Do not disable interrupt and assume continuous transmission.
173                clear_interrupt(&mut regs, idx);
174                return Ok(InterruptResult::TransmissionEvent {
175                    channel_index: idx,
176                    id: TxEventId::RtrResponse,
177                });
178            }
179            if buf_state == BufferState::TxOnceRtr {
180                // Do not disable interrupt and assume continuous transmission.
181                clear_interrupt(&mut regs, idx);
182                return Ok(InterruptResult::TransmissionEvent {
183                    channel_index: idx,
184                    id: TxEventId::TransmitScheduling,
185                });
186            }
187
188            Err(InterruptError::UnexpectedState(buf_state))
189        }
190    }
191}
192
193#[inline(always)]
194fn clear_interrupt(regs: &mut MmioCan<'static>, idx: usize) {
195    let mut clr = InterruptClear::new_with_raw_value(0);
196    clr.set_buffer(idx, true);
197    regs.write_iclr(clr);
198}
199
200#[inline(always)]
201fn clear_and_disable_interrupt(regs: &mut MmioCan<'static>, idx: usize) {
202    clear_interrupt(regs, idx);
203    regs.modify_ien(|mut val| {
204        val.set_buffer(idx, false);
205        val
206    });
207}
208
209#[derive(Debug, thiserror::Error)]
210#[error("all channels are unconfigured, none available for TX")]
211pub struct AllTxChannelsUnconfiguredError;
212
213pub struct CanTxFuture(usize);
214
215impl Future for CanTxFuture {
216    type Output = ();
217
218    fn poll(
219        self: core::pin::Pin<&mut Self>,
220        cx: &mut core::task::Context<'_>,
221    ) -> core::task::Poll<Self::Output> {
222        TX_WAKERS[self.0].register(cx.waker());
223        if TX_STATES[self.0].load(Ordering::Relaxed) == TxChannelState::Finished as u8 {
224            TX_STATES[self.0].store(TxChannelState::Idle as u8, Ordering::Relaxed);
225            return core::task::Poll::Ready(());
226        }
227        core::task::Poll::Pending
228    }
229}
230
231impl CanTxFuture {
232    pub fn new(frame: CanFrame) -> nb::Result<Self, AllTxChannelsUnconfiguredError> {
233        let mut channel_is_free = [false; 15];
234        let mut all_channels_unused = true;
235        for (idx, state) in TX_STATES.iter().enumerate() {
236            let state = state.load(Ordering::Relaxed);
237            if state == TxChannelState::Idle as u8 {
238                channel_is_free[idx] = true;
239            }
240            if state != TxChannelState::Unconfigured as u8 {
241                all_channels_unused = false;
242            }
243        }
244        if channel_is_free.iter().all(|&x| !x) {
245            return Err(nb::Error::WouldBlock);
246        }
247        if all_channels_unused {
248            return Err(nb::Error::Other(AllTxChannelsUnconfiguredError));
249        }
250        let free_channel_id = channel_is_free.iter().position(|&x| x).unwrap();
251        let mut channel =
252            unsafe { CanChannelLowLevel::steal_unchecked(CanId::Can0, free_channel_id) };
253        TX_STATES[free_channel_id].store(TxChannelState::TxDataFrame as u8, Ordering::Relaxed);
254        channel.write_state(BufferState::TxNotActive);
255        channel.transmit_frame_unchecked(frame);
256        channel.clear_interrupt();
257        channel.enable_interrupt(true);
258        channel.enable_error_interrupt(true);
259        Ok(CanTxFuture(free_channel_id))
260    }
261}
262
263#[derive(Debug, thiserror::Error)]
264#[cfg_attr(feature = "defmt", derive(defmt::Format))]
265pub enum ChannelConfigError {
266    #[error("channel is busy")]
267    Busy,
268    #[error("invalid offset: {0}")]
269    Offset(#[from] InvalidBufferIndexError),
270}
271
272pub struct CanTxAsync;
273
274impl CanTxAsync {
275    pub fn new(can: &mut super::Can) -> Self {
276        can.clear_interrupts();
277        can.enable_nvic_interrupt();
278        CanTxAsync
279    }
280
281    pub fn configure_channel(&mut self, channel_idx: usize) -> Result<(), ChannelConfigError> {
282        if channel_idx >= TX_STATES.len() {
283            return Err(ChannelConfigError::Offset(InvalidBufferIndexError(
284                channel_idx,
285            )));
286        }
287        let state = TX_STATES[channel_idx].load(Ordering::Relaxed);
288        if state != TxChannelState::Idle as u8 && state != TxChannelState::Unconfigured as u8 {
289            return Err(ChannelConfigError::Busy);
290        }
291        TX_STATES[channel_idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
292        Ok(())
293    }
294
295    /// Start a transmission and returns the future which can be polled to completion.
296    pub fn start_transmit(
297        &mut self,
298        frame: CanFrame,
299    ) -> nb::Result<CanTxFuture, AllTxChannelsUnconfiguredError> {
300        CanTxFuture::new(frame)
301    }
302
303    /// Calls [Self::start_transmit] and awaits the returned future to completion immediately.
304    pub async fn transmit(
305        &mut self,
306        frame: CanFrame,
307    ) -> nb::Result<(), AllTxChannelsUnconfiguredError> {
308        self.start_transmit(frame)?.await;
309        Ok(())
310    }
311}