Skip to main content

va416xx_hal/can/
asynch.rs

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