Skip to main content

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