pub use crate::reg::{self, tscc::TSSSELECT_A as TimeStampSelect};
use core::ops::RangeInclusive;
use fugit::HertzU32;
#[derive(Copy, Clone)]
pub struct CanConfig {
pub mode: Mode,
pub loopback: bool,
pub nominal_timing: BitTiming,
pub timestamp: Timestamp,
pub rx_fifo_0: RxFifoConfig,
pub rx_fifo_1: RxFifoConfig,
pub tx: TxConfig,
}
#[derive(Default, Copy, Clone)]
pub struct TxConfig {
pub tx_event_fifo_watermark: u8,
pub tx_queue_submode: TxQueueMode,
}
#[derive(Copy, Clone)]
pub struct BitTiming {
pub sjw: u8,
pub phase_seg_1: u8,
pub phase_seg_2: u8,
pub bitrate: HertzU32,
}
impl BitTiming {
pub fn new(bitrate: HertzU32) -> Self {
Self {
sjw: 0x4,
phase_seg_1: 0xB,
phase_seg_2: 0x4,
bitrate,
}
}
}
#[derive(Copy, Clone)]
pub struct Timestamp {
pub select: TimeStampSelect,
pub prescaler: u8,
}
impl Default for Timestamp {
fn default() -> Self {
Self {
select: TimeStampSelect::ZERO,
prescaler: 1,
}
}
}
#[derive(Debug)]
pub enum BitTimingError {
SynchronizationJumpWidthOutOfRange(RangeInclusive<u32>),
PhaseSeg1OutOfRange(RangeInclusive<u32>),
PhaseSeg2OutOfRange(RangeInclusive<u32>),
BitTimeOutOfRange(RangeInclusive<u32>),
PrescalerOutOfRange(RangeInclusive<u32>),
NoValidPrescaler {
can_clock: HertzU32,
bitrate: HertzU32,
bit_time_quanta: u32,
},
}
#[derive(Clone)]
pub(crate) struct BitTimingRanges {
sjw: RangeInclusive<u32>,
phase_seg_1: RangeInclusive<u32>,
phase_seg_2: RangeInclusive<u32>,
time_quanta_per_bit: RangeInclusive<u32>,
prescaler: RangeInclusive<u32>,
}
pub(crate) const NOMINAL_BIT_TIMING_RANGES: BitTimingRanges = BitTimingRanges {
sjw: 1..=128,
phase_seg_1: 2..=256,
phase_seg_2: 2..=128,
time_quanta_per_bit: 5..=385,
prescaler: 1..=512,
};
pub(crate) const DATA_BIT_TIMING_RANGES: BitTimingRanges = BitTimingRanges {
sjw: 1..=16,
phase_seg_1: 1..=32,
phase_seg_2: 1..=16,
time_quanta_per_bit: 3..=49,
prescaler: 1..=32,
};
impl BitTiming {
pub fn time_quanta_per_bit(&self) -> u32 {
1 + u32::from(self.phase_seg_1) + u32::from(self.phase_seg_2)
}
fn check(&self, valid: &BitTimingRanges) -> Result<(), BitTimingError> {
if !valid.sjw.contains(&self.sjw.into()) {
Err(BitTimingError::SynchronizationJumpWidthOutOfRange(
valid.sjw.clone(),
))
} else if !valid.phase_seg_1.contains(&self.phase_seg_1.into()) {
Err(BitTimingError::PhaseSeg1OutOfRange(
valid.phase_seg_1.clone(),
))
} else if !valid.phase_seg_2.contains(&self.phase_seg_2.into()) {
Err(BitTimingError::PhaseSeg2OutOfRange(
valid.phase_seg_2.clone(),
))
} else if !valid
.time_quanta_per_bit
.contains(&self.time_quanta_per_bit())
{
Err(BitTimingError::BitTimeOutOfRange(
valid.time_quanta_per_bit.clone(),
))
} else {
Ok(())
}
}
pub(crate) fn prescaler(
&self,
f_can: HertzU32,
valid: &BitTimingRanges,
) -> Result<u16, BitTimingError> {
self.check(valid)?;
let f_out = self.bitrate;
let bit_time_quanta = self.time_quanta_per_bit();
let f_q = f_out * bit_time_quanta;
if let Some(0) = f_can.to_Hz().checked_rem(f_q.to_Hz()) {
let prescaler = f_can / f_q;
if !valid.prescaler.contains(&prescaler) {
Err(BitTimingError::PrescalerOutOfRange(valid.prescaler.clone()))
} else {
Ok(prescaler as u16)
}
} else {
Err(BitTimingError::NoValidPrescaler {
can_clock: f_can,
bitrate: f_out,
bit_time_quanta,
})
}
}
}
#[derive(Default, Copy, Clone)]
pub enum Mode {
#[default]
Classic,
Fd {
allow_bit_rate_switching: bool,
data_phase_timing: BitTiming,
},
}
impl CanConfig {
pub fn new(bitrate: HertzU32) -> Self {
Self {
mode: Default::default(),
loopback: Default::default(),
nominal_timing: BitTiming::new(bitrate),
timestamp: Default::default(),
rx_fifo_0: Default::default(),
rx_fifo_1: Default::default(),
tx: Default::default(),
}
}
}
#[derive(Default, Copy, Clone)]
pub struct RxFifoConfig {
pub mode: RxFifoMode,
pub watermark: u8,
}
#[derive(Default, Copy, Clone)]
pub struct RxFifoMode(RxFifoModeVariant);
impl RxFifoMode {
pub fn blocking() -> Self {
Self(RxFifoModeVariant::Blocking)
}
pub unsafe fn overwrite() -> Self {
Self(RxFifoModeVariant::Overwrite)
}
}
#[derive(Default, Copy, Clone)]
pub enum RxFifoModeVariant {
#[default]
Blocking,
Overwrite,
}
impl From<RxFifoMode> for bool {
fn from(val: RxFifoMode) -> Self {
match val.0 {
RxFifoModeVariant::Overwrite => true,
RxFifoModeVariant::Blocking => false,
}
}
}
impl From<RxFifoMode> for RxFifoModeVariant {
fn from(val: RxFifoMode) -> Self {
val.0
}
}
#[derive(Default, Copy, Clone)]
pub enum TxQueueMode {
#[default]
Fifo,
Priority,
}
impl From<TxQueueMode> for bool {
fn from(val: TxQueueMode) -> Self {
match val {
TxQueueMode::Priority => true,
TxQueueMode::Fifo => false,
}
}
}