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 TxDataFrame,
32 TxRemoteFrame,
35 RtrResponse,
38 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
66pub 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 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 if tx_state == TxChannelState::TxDataFrame as u8 {
121 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 TX_STATES[idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
138 } else {
139 clear_interrupt(&mut regs, idx);
141 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 clear_interrupt(&mut regs, idx);
156 let frame = channel.read_frame_unchecked();
157 if tx_state == TxChannelState::TxRtrReception as u8 {
158 TX_STATES[idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
161 channel.write_state(BufferState::TxNotActive);
162 } else {
163 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 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 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 pub fn start_transmit(
297 &mut self,
298 frame: CanFrame,
299 ) -> nb::Result<CanTxFuture, AllTxChannelsUnconfiguredError> {
300 CanTxFuture::new(frame)
301 }
302
303 pub async fn transmit(
305 &mut self,
306 frame: CanFrame,
307 ) -> nb::Result<(), AllTxChannelsUnconfiguredError> {
308 self.start_transmit(frame)?.await;
309 Ok(())
310 }
311}