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 TxDataFrame,
34 TxRemoteFrame,
37 RtrResponse,
40 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
68pub 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 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 if tx_state == TxChannelState::TxDataFrame as u8 {
123 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 TX_STATES[idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
140 } else {
141 clear_interrupt(&mut regs, idx);
143 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 clear_interrupt(&mut regs, idx);
158 let frame = channel.read_frame_unchecked();
159 if tx_state == TxChannelState::TxRtrReception as u8 {
160 TX_STATES[idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
163 channel.write_state(BufferState::TxNotActive);
164 } else {
165 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 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 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 pub fn start_transmit(
299 &mut self,
300 frame: CanFrame,
301 ) -> nb::Result<CanTxFuture, AllTxChannelsUnconfiguredError> {
302 CanTxFuture::new(frame)
303 }
304
305 pub async fn transmit(
307 &mut self,
308 frame: CanFrame,
309 ) -> nb::Result<(), AllTxChannelsUnconfiguredError> {
310 self.start_transmit(frame)?.await;
311 Ok(())
312 }
313}