va416xx_hal/can/
mod.rs

1//! # CAN peripheral driver.
2//!
3//! The VA416xx CAN module is based on the CP3UB26 module.
4//!
5//! Using the CAN bus generally involves the following steps:
6//!
7//!  1. Create a [Can] instance
8//!  2. The [CanChannels] resource management singleton can be retrieved by using
9//!     [Can::take_channels].
10//!  3. Individual [CanRx] and [CanTx] channels can be created using the [CanChannels::take]
11//!     function. These allow to send or receive CAN frames on individual channels.
12//!  4. The [asynch::CanTxAsync] structure can be created to transmit frames asynchronously.
13//!     The [asynch::on_interrupt_can] function should be called in the user interrupt handler
14//!     for CAN0 and CAN1 for this to work properly. The interrupt handler can also take care of
15//!     receiving frames on [CanRx] channels with enabled interrupts.
16//!
17//! # Example
18//!
19//! - [CAN example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/embassy/src/bin/can.rs)
20use core::sync::atomic::AtomicBool;
21
22use arbitrary_int::{prelude::*, u11, u15, u2, u3, u4, u7};
23use embedded_can::Frame;
24use ll::CanChannelLowLevel;
25use regs::{BaseId, BufferState, Control, MmioCan, TimingConfig};
26use vorago_shared_hal::enable_nvic_interrupt;
27
28use crate::{clock::Clocks, enable_peripheral_clock, time::Hertz, PeripheralSelect};
29use libm::roundf;
30
31pub mod frame;
32pub use frame::*;
33
34pub mod asynch;
35pub mod ll;
36pub mod regs;
37
38pub const PRESCALER_MIN: u8 = 2;
39pub const PRESCALER_MAX: u8 = 128;
40/// 1 is the minimum value, but not recommended by Vorago.
41pub const TSEG1_MIN: u8 = 1;
42pub const TSEG1_MAX: u8 = 16;
43pub const TSEG2_MAX: u8 = 8;
44/// In addition, SJW may not be larger than TSEG2.
45pub const SJW_MAX: u8 = 4;
46
47pub const MIN_SAMPLE_POINT: f32 = 0.5;
48pub const MAX_BITRATE_DEVIATION: f32 = 0.005;
49
50static CHANNELS_TAKEN: [AtomicBool; 2] = [AtomicBool::new(false), AtomicBool::new(false)];
51
52#[derive(Debug, PartialEq, Eq, Clone, Copy)]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54pub enum CanId {
55    Can0 = 0,
56    Can1 = 1,
57}
58
59impl CanId {
60    /// Steal the register block for the CAN ID.
61    ///
62    /// # Safety
63    ///
64    /// See safety of the [regs::Can::new_mmio_fixed_0].
65    #[inline]
66    pub const unsafe fn steal_regs(&self) -> regs::MmioCan<'static> {
67        match self {
68            CanId::Can0 => unsafe { regs::Can::new_mmio_fixed_0() },
69            CanId::Can1 => unsafe { regs::Can::new_mmio_fixed_1() },
70        }
71    }
72
73    #[inline]
74    pub const fn irq_id(&self) -> va416xx::Interrupt {
75        match self {
76            CanId::Can0 => va416xx::Interrupt::CAN0,
77            CanId::Can1 => va416xx::Interrupt::CAN1,
78        }
79    }
80}
81
82/// Sample point between 0 and 1.0 for the given time segments.
83pub const fn calculate_sample_point(tseg1: u8, tseg2: u8) -> f32 {
84    let tseg1_val = tseg1 as f32;
85    (tseg1_val + 1.0) / (1.0 + tseg1_val + tseg2 as f32)
86}
87
88#[derive(Debug, Clone, Copy)]
89#[cfg_attr(feature = "defmt", derive(defmt::Format))]
90pub struct ClockConfig {
91    prescaler: u8,
92    tseg1: u8,
93    tseg2: u8,
94    sjw: u8,
95}
96
97impl ClockConfig {
98    /// New clock configuration from the raw configuration values.
99    ///
100    /// The values specified here are not the register values, but the actual numerical values
101    /// relevant for calculations.
102    ///
103    /// The values have the following requirements:
104    ///
105    /// - Prescaler must be between 2 and 128.
106    /// - TSEG1 must be smaller than 16 and should be larger than 1.
107    /// - TSEG2 must be smaller than 8 and small enough so that the calculated sample point
108    ///   is larger than 0.5 (50 %).
109    /// - SJW (Synchronization Jump Width) must be smaller than the smaller of the time segment
110    ///   configuration values and smaller than 4.
111    pub fn new(prescaler: u8, tseg1: u8, tseg2: u8, sjw: u8) -> Result<Self, ClockConfigError> {
112        if !(PRESCALER_MIN..=PRESCALER_MAX).contains(&prescaler.value()) {
113            return Err(ClockConfigError::CanNotFindPrescaler);
114        }
115        if tseg1 == 0 || tseg2 == 0 {
116            return Err(ClockConfigError::TsegIsZero);
117        }
118        if tseg1 > TSEG1_MAX {
119            return Err(ClockConfigError::InvalidTseg1);
120        }
121        if tseg2 > TSEG2_MAX {
122            return Err(ClockConfigError::InvalidTseg2);
123        }
124        let smaller_tseg = core::cmp::min(tseg1.value(), tseg2.value());
125        if sjw.value() > smaller_tseg || sjw > SJW_MAX {
126            return Err(InvalidSjwError(sjw).into());
127        }
128        let sample_point = calculate_sample_point(tseg1, tseg2);
129        if sample_point < MIN_SAMPLE_POINT {
130            return Err(InvalidSamplePointError { sample_point }.into());
131        }
132        Ok(Self {
133            prescaler,
134            tseg1,
135            tseg2,
136            sjw,
137        })
138    }
139
140    /// Calculate the clock configuration for the given input clock, the target bitrate and for a
141    /// set of timing parameters. The CAN controller uses the APB1 clock.
142    ///
143    /// This function basically calculates the necessary prescaler to achieve the given timing
144    /// parameters. It also performs sanity and validity checks for the calculated prescaler:
145    /// The bitrate error for the given prescaler needs to be smaller than 0.5 %.
146    pub fn from_bitrate_and_segments(
147        clocks: &Clocks,
148        bitrate: Hertz,
149        tseg1: u8,
150        tseg2: u8,
151        sjw: u8,
152    ) -> Result<ClockConfig, ClockConfigError> {
153        if bitrate.raw() == 0 {
154            return Err(ClockConfigError::BitrateIsZero);
155        }
156        let nominal_bit_time = 1 + tseg1 as u32 + tseg2 as u32;
157        let prescaler =
158            roundf(clocks.apb1().raw() as f32 / (bitrate.raw() as f32 * nominal_bit_time as f32))
159                as u32;
160        if !(PRESCALER_MIN as u32..=PRESCALER_MAX as u32).contains(&prescaler) {
161            return Err(ClockConfigError::CanNotFindPrescaler);
162        }
163
164        let actual_bitrate = (clocks.apb1().raw() as f32) / (prescaler * nominal_bit_time) as f32;
165        let bitrate_deviation = calculate_bitrate_deviation(actual_bitrate, bitrate);
166        if bitrate_deviation > MAX_BITRATE_DEVIATION {
167            return Err(ClockConfigError::BitrateErrorTooLarge);
168        }
169        // The subtractions are fine because we made checks to avoid underflows.
170        Self::new(prescaler as u8, tseg1, tseg2, sjw)
171    }
172
173    #[inline]
174    pub fn sjw_reg_value(&self) -> u2 {
175        u2::new(self.sjw.value() - 1)
176    }
177
178    #[inline]
179    pub fn tseg1_reg_value(&self) -> u4 {
180        u4::new(self.tseg1.value() - 1)
181    }
182
183    #[inline]
184    pub fn tseg2_reg_value(&self) -> u3 {
185        u3::new(self.tseg2.value() - 1)
186    }
187
188    #[inline]
189    pub fn prescaler_reg_value(&self) -> u7 {
190        u7::new(self.prescaler.value() - 2)
191    }
192}
193
194/// Calculate all viable clock configurations for the given input clock, the target bitrate and
195/// for a sample point between 0.5 and 1.0.
196///
197/// There are various recommendations for the sample point when using the CAN bus. The value
198/// depends on different parameters like the bus length and propagation time, as well as
199/// the information processing time of the nodes. It should always be at least 50 %.
200/// In doubt, select a value like 0.75.
201///
202///  - The [Python CAN library](https://python-can.readthedocs.io/en/stable/bit_timing.html)
203///    assumes a default value of 69 % as the sample point if none is specified.
204///  - CiA-301 recommends 87.5 %
205///  - For simpler setups like laboratory setups, smaller values should work as well.
206///
207/// A clock configuration is consideres viable when
208///
209///  - The sample point deviation is less than 5 %.
210///  - The bitrate error is less than +-0.5 %.
211///
212///  SJW will be set to either TSEG2 or 4, whichever is smaller.
213#[cfg(feature = "alloc")]
214pub fn calculate_all_viable_clock_configs(
215    apb1_clock: Hertz,
216    bitrate: Hertz,
217    sample_point: f32,
218) -> Result<alloc::vec::Vec<(ClockConfig, f32)>, InvalidSamplePointError> {
219    if sample_point < 0.5 || sample_point > 1.0 {
220        return Err(InvalidSamplePointError { sample_point });
221    }
222    let mut configs = alloc::vec::Vec::new();
223    for prescaler in PRESCALER_MIN..PRESCALER_MAX {
224        let nom_bit_time = calculate_nominal_bit_time(apb1_clock, bitrate, prescaler);
225        // This is taken from the Python CAN library. NBT should not be too small.
226        if nom_bit_time < 8 {
227            break;
228        }
229        let actual_bitrate = calculate_actual_bitrate(apb1_clock, prescaler, nom_bit_time);
230        let bitrate_deviation = calculate_bitrate_deviation(actual_bitrate, bitrate);
231        if bitrate_deviation > 0.05 {
232            continue;
233        }
234        let tseg1 = roundf(sample_point * nom_bit_time as f32) as u32 - 1;
235        if tseg1 > TSEG1_MAX as u32 || tseg1 < TSEG1_MIN as u32 {
236            continue;
237        }
238        // limit tseg1, so tseg2 is at least 1 TQ
239        let tseg1 = core::cmp::min(tseg1, nom_bit_time - 2) as u8;
240        let tseg2 = nom_bit_time - tseg1 as u32 - 1;
241        if tseg2 > TSEG2_MAX as u32 {
242            continue;
243        }
244        let tseg2 = tseg2 as u8;
245        let sjw = core::cmp::min(tseg2, 4) as u8;
246        // Use percent to have a higher resolution for the sample point deviation.
247        let sample_point_actual = roundf(calculate_sample_point(tseg1, tseg2) * 100.0) as u32;
248        let sample_point = roundf(sample_point * 100.0) as u32;
249        let deviation = (sample_point_actual as i32 - sample_point as i32).abs();
250        if deviation > 5 {
251            continue;
252        }
253        configs.push((
254            ClockConfig {
255                prescaler,
256                tseg1,
257                tseg2,
258                sjw,
259            },
260            bitrate_deviation,
261        ));
262    }
263    Ok(configs)
264}
265
266#[inline]
267pub const fn calculate_nominal_bit_time(
268    apb1_clock: Hertz,
269    target_bitrate: Hertz,
270    prescaler: u8,
271) -> u32 {
272    apb1_clock.raw() / (target_bitrate.raw() * prescaler as u32)
273}
274
275#[inline]
276pub const fn calculate_actual_bitrate(apb1_clock: Hertz, prescaler: u8, nom_bit_time: u32) -> f32 {
277    apb1_clock.raw() as f32 / (prescaler as u32 * nom_bit_time) as f32
278}
279
280#[inline]
281pub const fn calculate_bitrate_deviation(actual_bitrate: f32, target_bitrate: Hertz) -> f32 {
282    (actual_bitrate - target_bitrate.raw() as f32).abs() / target_bitrate.raw() as f32
283}
284
285pub trait CanInstance {
286    const ID: CanId;
287    const IRQ: va416xx::Interrupt;
288    const PERIPH_SEL: PeripheralSelect;
289}
290
291impl CanInstance for va416xx::Can0 {
292    const ID: CanId = CanId::Can0;
293    const IRQ: va416xx::Interrupt = va416xx::Interrupt::CAN0;
294    const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Can0;
295}
296
297impl CanInstance for va416xx::Can1 {
298    const ID: CanId = CanId::Can1;
299    const IRQ: va416xx::Interrupt = va416xx::Interrupt::CAN1;
300    const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Can1;
301}
302
303#[derive(Debug, thiserror::Error)]
304#[cfg_attr(feature = "defmt", derive(defmt::Format))]
305#[error("invalid buffer index {0}")]
306pub struct InvalidBufferIndexError(usize);
307
308#[derive(Debug, thiserror::Error)]
309#[cfg_attr(feature = "defmt", derive(defmt::Format))]
310#[error("sjw must be less than or equal to the smaller tseg value")]
311pub struct InvalidSjwError(u8);
312
313#[derive(Debug, thiserror::Error)]
314#[error("invalid sample point {sample_point}")]
315#[cfg_attr(feature = "defmt", derive(defmt::Format))]
316pub struct InvalidSamplePointError {
317    /// Sample point, should be larger than 0.5 (50 %) but was not.
318    sample_point: f32,
319}
320
321#[derive(Debug, thiserror::Error)]
322#[cfg_attr(feature = "defmt", derive(defmt::Format))]
323pub enum ClockConfigError {
324    #[error("invalid sjw: {0}")]
325    InvalidSjw(#[from] InvalidSjwError),
326    #[error("TSEG is zero which is not allowed")]
327    TsegIsZero,
328    #[error("TSEG1 is larger than 16")]
329    InvalidTseg1,
330    #[error("TSEG1 is larger than 8")]
331    InvalidTseg2,
332    #[error("invalid sample point: {0}")]
333    InvalidSamplePoint(#[from] InvalidSamplePointError),
334    #[error("bitrate is zero")]
335    BitrateIsZero,
336    #[error("bitrate error larger than +-0.5 %")]
337    BitrateErrorTooLarge,
338    #[error("maximum or minimum allowed prescaler is not sufficient for target bitrate clock")]
339    CanNotFindPrescaler,
340}
341
342/// The main CAN peripheral driver.
343pub struct Can {
344    regs: regs::MmioCan<'static>,
345    id: CanId,
346}
347
348impl Can {
349    pub fn new<CanI: CanInstance>(_can: CanI, clk_config: ClockConfig) -> Self {
350        enable_peripheral_clock(CanI::PERIPH_SEL);
351        let id = CanI::ID;
352        let mut regs = if id == CanId::Can0 {
353            unsafe { regs::Can::new_mmio_fixed_0() }
354        } else {
355            unsafe { regs::Can::new_mmio_fixed_1() }
356        };
357        // Disable the CAN bus before configuring it.
358        regs.write_control(Control::new_with_raw_value(0));
359        for i in 0..15 {
360            regs.cmbs(i).unwrap().reset();
361        }
362        regs.write_timing(
363            TimingConfig::builder()
364                .with_tseg2(clk_config.tseg2_reg_value())
365                .with_tseg1(clk_config.tseg1_reg_value())
366                .with_sync_jump_width(clk_config.sjw_reg_value())
367                .with_prescaler(clk_config.prescaler_reg_value())
368                .build(),
369        );
370        Self { regs, id }
371    }
372
373    /// This configures the global mask so that acceptance is only determined by an exact match
374    /// with the ID in the receive message buffers. This is the default reset configuration for
375    /// the global mask as well.
376    pub fn set_global_mask_for_exact_id_match(&mut self) {
377        self.regs
378            .write_gmskx(regs::ExtendedId::new_with_raw_value(0));
379        self.regs.write_gmskb(BaseId::new_with_raw_value(0));
380    }
381
382    /// Retrieve a resource management singleton for the 15 CAN channels.
383    pub fn take_channels(&self) -> Option<CanChannels> {
384        if CHANNELS_TAKEN[self.id() as usize].swap(true, core::sync::atomic::Ordering::SeqCst) {
385            return None;
386        }
387        Some(CanChannels::new(self.id))
388    }
389
390    /// Similar to [Self::set_global_mask_for_exact_id_match] but masks the XRTR and RTR/SRR bits.
391    ///
392    /// This is useful for when transmitting remote frames with the RTR bit set. The hardware
393    /// will automatically go into the [regs::BufferState::RxReady] state after the transmission,
394    /// but the XRTR and RTR/SRR bits need to be masked for the response frame to be accepted
395    /// on that buffer.
396    pub fn set_global_mask_for_exact_id_match_with_rtr_masked(&mut self) {
397        self.regs.write_gmskx(
398            regs::ExtendedId::builder()
399                .with_mask_14_0(u15::new(0))
400                .with_xrtr(true)
401                .build(),
402        );
403        self.regs.write_gmskb(
404            BaseId::builder()
405                .with_mask_28_18(u11::new(0))
406                .with_rtr_or_srr(true)
407                .with_ide(false)
408                .with_mask_17_15(u3::new(0))
409                .build(),
410        );
411    }
412
413    /// This configures the base mask for buffer 14 so that acceptance is only determined by an
414    /// exact match with the ID in the receive message buffers. This is the default reset
415    /// configuration for the global mask as well.
416    #[inline]
417    pub fn set_base_mask_for_exact_id_match(&mut self) {
418        self.regs
419            .write_bmskx(regs::ExtendedId::new_with_raw_value(0));
420        self.regs.write_bmskb(BaseId::new_with_raw_value(0));
421    }
422
423    /// This configures the base mask so that all CAN frames which are not handled by any other
424    /// buffers are accepted by the base buffer 14.
425    #[inline]
426    pub fn set_base_mask_for_all_match(&mut self) {
427        self.regs
428            .write_bmskx(regs::ExtendedId::new_with_raw_value(0xffff));
429        self.regs.write_bmskb(BaseId::new_with_raw_value(0xffff));
430    }
431
432    #[inline]
433    pub fn regs(&mut self) -> &mut MmioCan<'static> {
434        &mut self.regs
435    }
436
437    /// Clear all interrupts.
438    #[inline]
439    pub fn clear_interrupts(&mut self) {
440        self.regs
441            .write_iclr(regs::InterruptClear::new_with_raw_value(0xFFFF_FFFF));
442    }
443
444    /// This function only enable the CAN interrupt vector in the NVIC.
445    ///
446    /// The interrupts for the individual channels or errors still need to be enabled
447    /// separately.
448    #[inline]
449    pub fn enable_nvic_interrupt(&mut self) {
450        unsafe {
451            enable_nvic_interrupt(self.id().irq_id());
452        }
453    }
454
455    #[inline]
456    pub fn read_error_counters(&self) -> regs::ErrorCounter {
457        self.regs.read_error_counter()
458    }
459
460    #[inline]
461    pub fn read_error_diagnostics(&self) -> regs::DiagnosticRegister {
462        self.regs.read_diag()
463    }
464
465    #[inline]
466    pub fn id(&self) -> CanId {
467        self.id
468    }
469
470    #[inline]
471    pub fn write_ctrl_reg(&mut self, ctrl: Control) {
472        self.regs.write_control(ctrl);
473    }
474
475    #[inline]
476    pub fn modify_control<F>(&mut self, f: F)
477    where
478        F: FnOnce(Control) -> Control,
479    {
480        self.regs.modify_control(f);
481    }
482
483    #[inline]
484    pub fn set_bufflock(&mut self, enable: bool) {
485        self.regs.modify_control(|mut ctrl| {
486            ctrl.set_bufflock(enable);
487            ctrl
488        });
489    }
490
491    #[inline]
492    pub fn enable(&mut self) {
493        self.regs.modify_control(|mut ctrl| {
494            ctrl.set_enable(true);
495            ctrl
496        });
497    }
498}
499
500#[derive(Debug, PartialEq, Eq, Clone, Copy)]
501#[cfg_attr(feature = "defmt", derive(defmt::Format))]
502pub enum TxState {
503    Idle,
504    TransmittingDataFrame,
505    TransmittingRemoteFrame,
506    AwaitingRemoteFrameReply,
507}
508
509#[derive(Debug)]
510#[cfg_attr(feature = "defmt", derive(defmt::Format))]
511pub enum InvalidTxState {
512    State(TxState),
513    BufferState(BufferState),
514}
515
516impl From<TxState> for InvalidTxState {
517    fn from(state: TxState) -> Self {
518        InvalidTxState::State(state)
519    }
520}
521
522impl From<BufferState> for InvalidTxState {
523    fn from(state: BufferState) -> Self {
524        InvalidTxState::BufferState(state)
525    }
526}
527
528#[derive(Debug, thiserror::Error)]
529#[error("invalid tx state {0:?}")]
530#[cfg_attr(feature = "defmt", derive(defmt::Format))]
531pub struct InvalidTxStateError(pub InvalidTxState);
532
533#[derive(Debug, PartialEq, Eq, Clone, Copy)]
534#[cfg_attr(feature = "defmt", derive(defmt::Format))]
535pub enum RxState {
536    Idle,
537    Receiving,
538}
539
540#[derive(Debug, thiserror::Error)]
541#[error("invalid rx state {0:?}")]
542#[cfg_attr(feature = "defmt", derive(defmt::Format))]
543pub struct InvalidRxStateError(pub RxState);
544
545/// Driver instance to use an individual CAN channel as a transmission channel.
546#[derive(Debug)]
547pub struct CanTx {
548    ll: CanChannelLowLevel,
549    mode: TxState,
550}
551
552impl CanTx {
553    pub fn new(mut ll: CanChannelLowLevel, tx_priority: Option<u4>) -> Self {
554        ll.reset();
555        ll.configure_for_transmission(tx_priority);
556        Self {
557            ll,
558            mode: TxState::Idle,
559        }
560    }
561
562    #[inline]
563    pub fn into_rx_channel(self) -> CanRx {
564        CanRx::new(self.ll)
565    }
566
567    /// Start transmitting a frame.
568    ///
569    /// The frame transmission can be polled/awaited to completion using the [Self::transfer_done]
570    /// method.
571    ///
572    /// This function will return a [state error][InvalidTxStateError] if a transmission is already
573    /// active and/or the transmit buffer has an invalid state.
574    pub fn transmit_frame(&mut self, frame: CanFrame) -> Result<(), InvalidTxStateError> {
575        if self.mode == TxState::AwaitingRemoteFrameReply {
576            self.ll.configure_for_transmission(None);
577            self.mode = TxState::Idle;
578        }
579        if self.mode != TxState::Idle {
580            return Err(InvalidTxStateError(self.mode.into()));
581        }
582        if !frame.is_remote_frame() {
583            self.mode = TxState::TransmittingDataFrame;
584        } else {
585            self.mode = TxState::TransmittingRemoteFrame;
586        }
587        if let Ok(state) = self.ll.read_state() {
588            if state != BufferState::TxNotActive {
589                return Err(InvalidTxStateError(state.into()));
590            }
591        }
592        self.ll.transmit_frame_unchecked(frame);
593        Ok(())
594    }
595
596    /// Poll whether an active data frame transmission is done.
597    ///
598    /// Returns a [state error][InvalidTxStateError] if no transmission is active.
599    pub fn transfer_done(&mut self) -> nb::Result<(), InvalidTxStateError> {
600        if self.mode != TxState::TransmittingDataFrame {
601            return Err(nb::Error::Other(InvalidTxStateError(self.mode.into())));
602        }
603        let status = self.ll.read_state();
604        if status.is_err() {
605            return Err(nb::Error::WouldBlock);
606        }
607        let status = status.unwrap();
608        if status == BufferState::TxNotActive {
609            self.mode = TxState::Idle;
610            return Ok(());
611        }
612        Err(nb::Error::WouldBlock)
613    }
614
615    /// Poll whether an active remote frame transmission is done.
616    ///
617    /// On success, returns the channel re-configured to a [CanRx] channel. This is because the
618    /// default behaviour of the hardware will be to re-configure the channel state to
619    /// [BufferState::RxReady] once the remote frame has been transmitted so that the response
620    /// frame can be awaited.
621    ///
622    /// If the channel should instead be re-configured for transmission again,
623    /// [Self::remote_transfer_done_with_tx_reconfig] can be used.
624    ///
625    /// Returns a [state error][InvalidTxStateError] if no transmission is active.
626    pub fn remote_transfer_done(&mut self) -> nb::Result<CanRx, InvalidTxStateError> {
627        if self.mode != TxState::TransmittingRemoteFrame {
628            return Err(nb::Error::Other(InvalidTxStateError(self.mode.into())));
629        }
630        let status = self.ll.read_state();
631        if status.is_err() {
632            return Err(nb::Error::WouldBlock);
633        }
634        let status = status.unwrap();
635        if status == BufferState::RxReady {
636            self.mode = TxState::AwaitingRemoteFrameReply;
637            return Ok(CanRx {
638                ll: unsafe { self.ll.clone() },
639                mode: RxState::Receiving,
640            });
641        }
642        Err(nb::Error::WouldBlock)
643    }
644
645    /// Poll whether an active remote frame transmission is done.
646    ///
647    /// This function will re-configure the buffer back for transmission once the
648    /// transmission has completed.
649    ///
650    /// Returns a [state error][InvalidTxStateError] if no transmission is active.
651    pub fn remote_transfer_done_with_tx_reconfig(&mut self) -> nb::Result<(), InvalidTxStateError> {
652        if self.mode != TxState::TransmittingRemoteFrame {
653            return Err(nb::Error::Other(InvalidTxStateError(self.mode.into())));
654        }
655        let status = self.ll.read_state();
656        if status.is_err() {
657            return Err(nb::Error::WouldBlock);
658        }
659        let status = status.unwrap();
660        if status == BufferState::RxReady {
661            self.ll.write_state(BufferState::TxNotActive);
662            self.mode = TxState::Idle;
663            return Ok(());
664        }
665        Err(nb::Error::WouldBlock)
666    }
667
668    pub fn reset(&mut self) {
669        self.ll.reset();
670        self.mode = TxState::Idle;
671    }
672}
673
674/// Driver instance to use an individual CAN channel as a reception channel.
675pub struct CanRx {
676    ll: CanChannelLowLevel,
677    mode: RxState,
678}
679
680impl CanRx {
681    pub fn new(mut ll: CanChannelLowLevel) -> Self {
682        ll.reset();
683        Self {
684            ll,
685            mode: RxState::Idle,
686        }
687    }
688
689    #[inline]
690    pub fn into_tx_channel(self, tx_priority: Option<u4>) -> CanTx {
691        CanTx::new(self.ll, tx_priority)
692    }
693
694    #[inline]
695    pub fn enable_interrupt(&mut self, enable_translation: bool) {
696        self.ll.enable_interrupt(enable_translation);
697    }
698
699    pub fn configure_for_reception_with_standard_id(
700        &mut self,
701        standard_id: embedded_can::StandardId,
702        set_rtr: bool,
703    ) {
704        self.ll.set_standard_id(standard_id, set_rtr);
705        self.configure_for_reception();
706    }
707
708    pub fn configure_for_reception_with_extended_id(
709        &mut self,
710        extended_id: embedded_can::ExtendedId,
711        set_rtr: bool,
712    ) {
713        self.ll.set_extended_id(extended_id, set_rtr);
714        self.configure_for_reception();
715    }
716
717    pub fn configure_for_reception(&mut self) {
718        self.ll.configure_for_reception();
719        self.mode = RxState::Receiving;
720    }
721
722    #[inline]
723    pub fn frame_available(&self) -> bool {
724        self.ll
725            .read_state()
726            .is_ok_and(|state| state == BufferState::RxFull || state == BufferState::RxOverrun)
727    }
728
729    /// Poll for frame reception. Returns the frame if one is available.
730    pub fn receive(
731        &mut self,
732        reconfigure_for_reception: bool,
733    ) -> nb::Result<CanFrame, InvalidRxStateError> {
734        if self.mode != RxState::Receiving {
735            return Err(nb::Error::Other(InvalidRxStateError(self.mode)));
736        }
737        let status = self.ll.read_state();
738        if status.is_err() {
739            return Err(nb::Error::WouldBlock);
740        }
741        let status = status.unwrap();
742        if status == BufferState::RxFull || status == BufferState::RxOverrun {
743            self.mode = RxState::Idle;
744            if reconfigure_for_reception {
745                self.ll.write_state(BufferState::RxReady);
746            }
747            return Ok(self.ll.read_frame_unchecked());
748        }
749        Err(nb::Error::WouldBlock)
750    }
751}
752
753pub struct CanChannels {
754    id: CanId,
755    channels: [Option<CanChannelLowLevel>; 15],
756}
757
758impl CanChannels {
759    const fn new(id: CanId) -> Self {
760        // Safety: Private function, ownership rules enforced by public API.
761        unsafe {
762            Self {
763                id,
764                channels: [
765                    Some(CanChannelLowLevel::steal_unchecked(id, 0)),
766                    Some(CanChannelLowLevel::steal_unchecked(id, 1)),
767                    Some(CanChannelLowLevel::steal_unchecked(id, 2)),
768                    Some(CanChannelLowLevel::steal_unchecked(id, 3)),
769                    Some(CanChannelLowLevel::steal_unchecked(id, 4)),
770                    Some(CanChannelLowLevel::steal_unchecked(id, 5)),
771                    Some(CanChannelLowLevel::steal_unchecked(id, 6)),
772                    Some(CanChannelLowLevel::steal_unchecked(id, 7)),
773                    Some(CanChannelLowLevel::steal_unchecked(id, 8)),
774                    Some(CanChannelLowLevel::steal_unchecked(id, 9)),
775                    Some(CanChannelLowLevel::steal_unchecked(id, 10)),
776                    Some(CanChannelLowLevel::steal_unchecked(id, 11)),
777                    Some(CanChannelLowLevel::steal_unchecked(id, 12)),
778                    Some(CanChannelLowLevel::steal_unchecked(id, 13)),
779                    Some(CanChannelLowLevel::steal_unchecked(id, 14)),
780                ],
781            }
782        }
783    }
784
785    pub const fn can_id(&self) -> CanId {
786        self.id
787    }
788
789    /// Take the indidivual CAN channel low level driver instance.
790    pub fn take(&mut self, idx: usize) -> Option<CanChannelLowLevel> {
791        if idx > 14 {
792            return None;
793        }
794        self.channels[idx].take()
795    }
796
797    pub fn give(&mut self, idx: usize, channel: CanChannelLowLevel) {
798        if idx > 14 {
799            panic!("invalid buffer index for CAN channel");
800        }
801        self.channels[idx] = Some(channel);
802    }
803}
804
805#[cfg(test)]
806mod tests {
807    #[cfg(feature = "alloc")]
808    use std::println;
809
810    #[cfg(feature = "alloc")]
811    #[test]
812    pub fn test_clock_calculator_example_1() {
813        let configs = super::calculate_all_viable_clock_configs(
814            crate::time::Hertz::from_raw(50_000_000),
815            crate::time::Hertz::from_raw(25_000),
816            0.75,
817        )
818        .expect("clock calculation failed");
819        // Bitrate: 25278.05 Hz. Sample point: 0.7391
820        assert_eq!(configs[0].prescaler, 84);
821        assert_eq!(configs[0].tseg1, 16);
822        assert_eq!(configs[0].tseg2, 6);
823        assert_eq!(configs[0].sjw, 4);
824        // Vorago sample value.
825        let sample_cfg = configs
826            .iter()
827            .find(|c| c.prescaler == 100)
828            .expect("clock config not found");
829        // Slightly different distribution because we use a different sample point, but
830        // the sum of TSEG1 and TSEG2 is the same as the Vorago example 1.
831        assert_eq!(sample_cfg.tseg1, 14);
832        assert_eq!(sample_cfg.tseg2, 5);
833    }
834}