#![doc(html_root_url = "https://docs.rs/fdcan/0.1.0")]
#![no_std]
#[allow(clippy::all)] mod pac;
use self::pac::generic::*; pub use crate::pac::fdcan::RegisterBlock;
pub mod config;
pub mod filter;
pub mod frame;
pub mod id;
pub mod interrupt;
pub mod message_ram;
mod sealed {
pub trait Sealed {}
}
use config::{
DataBitTiming, FdCanConfig, FrameTransmissionConfig, GlobalFilter,
NominalBitTiming, TimestampSource,
};
use filter::{
ActivateFilter as _, ExtendedFilter, ExtendedFilterSlot, StandardFilter,
StandardFilterSlot, EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX,
};
use frame::MergeTxFrameHeader;
use frame::{RxFrameInfo, TxFrameHeader};
use id::{Id, IdReg};
use interrupt::{Interrupt, InterruptLine, Interrupts};
use message_ram::RxFifoElement;
use core::cmp::Ord;
use core::convert::Infallible;
use core::convert::TryFrom;
use core::marker::PhantomData;
use core::ptr::NonNull;
use core::slice;
pub unsafe trait Instance: message_ram::Instance {
const REGISTERS: *mut RegisterBlock;
}
#[derive(Clone, Copy, Debug)]
pub enum ReceiveErrorOverflow {
Normal(u8),
Overflow(u8),
}
#[derive(Clone, Copy, Debug)]
#[allow(dead_code)]
pub struct ErrorCounters {
can_errors: u8,
receive_err: ReceiveErrorOverflow,
transmit_err: u8,
}
#[derive(Clone, Copy, Debug)]
enum LoopbackMode {
None,
Internal,
External,
}
#[derive(Clone, Copy, Debug)]
pub enum Activity {
Synchronizing = 0b00,
Idle = 0b01,
Receiver = 0b10,
Transmitter = 0b11,
}
impl TryFrom<u8> for Activity {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0b000 => Ok(Self::Synchronizing),
0b001 => Ok(Self::Idle),
0b010 => Ok(Self::Receiver),
0b011 => Ok(Self::Transmitter),
_ => Err(()),
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum LastErrorCode {
NoError = 0b000,
StuffError = 0b001,
FormError = 0b010,
AckError = 0b011,
Bit1Error = 0b100,
Bit0Error = 0b101,
CRCError = 0b110,
NoChange = 0b111,
}
impl TryFrom<u8> for LastErrorCode {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0b000 => Ok(Self::NoError),
0b001 => Ok(Self::StuffError),
0b010 => Ok(Self::FormError),
0b011 => Ok(Self::AckError),
0b100 => Ok(Self::Bit1Error),
0b101 => Ok(Self::Bit0Error),
0b110 => Ok(Self::CRCError),
0b111 => Ok(Self::NoChange),
_ => Err(()),
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct ProtocolStatus {
activity: Activity,
transmitter_delay_comp: u8,
bus_off_status: bool,
error_warning: bool,
error_passive_state: bool,
last_error: LastErrorCode,
}
pub trait Transmit {}
pub trait Receive {}
pub struct PoweredDownMode;
pub struct ConfigMode;
pub struct InternalLoopbackMode;
impl Transmit for InternalLoopbackMode {}
impl Receive for InternalLoopbackMode {}
pub struct ExternalLoopbackMode;
impl Transmit for ExternalLoopbackMode {}
impl Receive for ExternalLoopbackMode {}
pub struct NormalOperationMode;
impl Transmit for NormalOperationMode {}
impl Receive for NormalOperationMode {}
pub struct RestrictedOperationMode;
impl Receive for RestrictedOperationMode {}
pub struct BusMonitoringMode;
impl Receive for BusMonitoringMode {}
pub struct TestMode;
pub struct FdCan<I: Instance, MODE> {
control: FdCanControl<I, MODE>,
}
impl<I, MODE> FdCan<I, MODE>
where
I: Instance,
{
fn create_can<NEW>(config: FdCanConfig, instance: I) -> FdCan<I, NEW> {
FdCan {
control: FdCanControl {
config,
instance,
_mode: core::marker::PhantomData,
},
}
}
fn into_can_mode<NEW>(self) -> FdCan<I, NEW> {
FdCan {
control: FdCanControl {
config: self.control.config,
instance: self.control.instance,
_mode: core::marker::PhantomData,
},
}
}
#[inline]
pub fn instance(&mut self) -> &mut I {
&mut self.control.instance
}
#[inline]
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
#[inline]
fn msg_ram_mut(&mut self) -> &mut message_ram::RegisterBlock {
self.instance().msg_ram_mut()
}
#[inline]
fn reset_msg_ram(&mut self) {
self.msg_ram_mut().reset();
}
#[inline]
fn enter_init_mode(&mut self) {
let can = self.registers();
can.cccr.modify(|_, w| w.init().set_bit());
while can.cccr.read().init().bit_is_clear() {}
can.cccr.modify(|_, w| w.cce().set_bit());
}
#[inline]
pub fn get_config(&self) -> FdCanConfig {
self.control.config
}
#[inline]
fn set_loopback_mode(&mut self, mode: LoopbackMode) {
let (test, mon, lbck) = match mode {
LoopbackMode::None => (false, false, false),
LoopbackMode::Internal => (true, true, true),
LoopbackMode::External => (true, false, true),
};
self.set_test_mode(test);
self.set_bus_monitoring_mode(mon);
let can = self.registers();
can.test.modify(|_, w| w.lbck().bit(lbck));
}
#[inline]
fn set_bus_monitoring_mode(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.mon().bit(enabled));
}
#[inline]
fn set_restricted_operations(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.asm().bit(enabled));
}
#[inline]
fn set_normal_operations(&mut self, _enabled: bool) {
self.set_loopback_mode(LoopbackMode::None);
}
#[inline]
fn set_test_mode(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.test().bit(enabled));
}
#[inline]
fn set_power_down_mode(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.csr().bit(enabled));
while can.cccr.read().csa().bit() != enabled {}
}
#[inline]
pub fn enable_interrupt_line(&mut self, line: InterruptLine, enabled: bool) {
let can = self.registers();
match line {
InterruptLine::_0 => can.ile.modify(|_, w| w.eint0().bit(enabled)),
InterruptLine::_1 => can.ile.modify(|_, w| w.eint1().bit(enabled)),
}
}
#[inline]
pub fn enable_interrupt(&mut self, interrupt: Interrupt) {
self.enable_interrupts(Interrupts::from_bits_truncate(interrupt as u32))
}
#[inline]
pub fn enable_interrupts(&mut self, interrupts: Interrupts) {
self.registers()
.ie
.modify(|r, w| unsafe { w.bits(r.bits() | interrupts.bits()) })
}
pub fn disable_interrupt(&mut self, interrupt: Interrupt) {
self.disable_interrupts(Interrupts::from_bits_truncate(interrupt as u32))
}
#[inline]
pub fn disable_interrupts(&mut self, interrupts: Interrupts) {
self.registers()
.ie
.modify(|r, w| unsafe { w.bits(r.bits() & !interrupts.bits()) })
}
#[inline]
pub fn error_counters(&self) -> ErrorCounters {
self.control.error_counters()
}
#[inline]
pub fn set_standard_filter(
&mut self,
slot: StandardFilterSlot,
filter: StandardFilter,
) {
self.msg_ram_mut().filters.flssa[slot as usize].activate(filter);
}
pub fn set_standard_filters(
&mut self,
filters: &[StandardFilter; STANDARD_FILTER_MAX as usize],
) {
for (i, f) in filters.iter().enumerate() {
self.msg_ram_mut().filters.flssa[i].activate(*f);
}
}
#[inline]
pub fn set_extended_filter(
&mut self,
slot: ExtendedFilterSlot,
filter: ExtendedFilter,
) {
self.msg_ram_mut().filters.flesa[slot as usize].activate(filter);
}
pub fn set_extended_filters(
&mut self,
filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize],
) {
for (i, f) in filters.iter().enumerate() {
self.msg_ram_mut().filters.flesa[i].activate(*f);
}
}
pub fn get_protocol_status(&self) -> ProtocolStatus {
let psr = self.registers().psr.read();
ProtocolStatus {
activity: Activity::try_from(0 ).unwrap(), transmitter_delay_comp: psr.tdcv().bits(),
bus_off_status: psr.bo().bit_is_set(),
error_warning: psr.ew().bit_is_set(),
error_passive_state: psr.ep().bit_is_set(),
last_error: LastErrorCode::try_from(psr.lec().bits()).unwrap(),
}
}
#[inline]
pub fn has_interrupt(&mut self, interrupt: Interrupt) -> bool {
self.control.has_interrupt(interrupt)
}
#[inline]
pub fn clear_interrupt(&mut self, interrupt: Interrupt) {
self.control.clear_interrupt(interrupt)
}
#[inline]
pub fn clear_interrupts(&mut self, interrupts: Interrupts) {
self.control.clear_interrupts(interrupts)
}
#[inline]
#[allow(clippy::type_complexity)]
fn split_by_ref_generic(
&mut self,
) -> (
&mut FdCanControl<I, MODE>,
&mut Tx<I, MODE>,
&mut Rx<I, MODE, Fifo0>,
&mut Rx<I, MODE, Fifo1>,
) {
let tx = unsafe { Tx::conjure_by_ref() };
let rx0 = unsafe { Rx::conjure_by_ref() };
let rx1 = unsafe { Rx::conjure_by_ref() };
(&mut self.control, tx, rx0, rx1)
}
#[inline]
#[allow(clippy::type_complexity)]
fn split_generic(
self,
) -> (
FdCanControl<I, MODE>,
Tx<I, MODE>,
Rx<I, MODE, Fifo0>,
Rx<I, MODE, Fifo1>,
) {
unsafe { (self.control, Tx::conjure(), Rx::conjure(), Rx::conjure()) }
}
#[inline]
#[allow(clippy::type_complexity)]
pub fn combine(
t: (
FdCanControl<I, MODE>,
Tx<I, MODE>,
Rx<I, MODE, Fifo0>,
Rx<I, MODE, Fifo1>,
),
) -> Self {
Self::create_can(t.0.config, t.0.instance)
}
}
impl<I> FdCan<I, PoweredDownMode>
where
I: Instance,
{
pub fn new(instance: I) -> Self {
Self::create_can(FdCanConfig::default(), instance)
}
#[inline]
pub fn into_config_mode(mut self) -> FdCan<I, ConfigMode> {
self.set_power_down_mode(false);
self.enter_init_mode();
self.reset_msg_ram();
let can = self.registers();
assert!(
can.crel.read().rel().bits() == 3,
"Expected FDCAN core major release 3"
);
assert!(
can.endn.read().bits() == 0x87654321_u32,
"Error reading endianness test value from FDCAN core"
);
can.txbc.write(|w| w.tfqm().set_bit());
#[cfg(feature = "fdcan_g0_g4_l5")]
{
can.rxgfc.modify(|_, w| unsafe {
w.lss()
.bits(STANDARD_FILTER_MAX)
.lse()
.bits(EXTENDED_FILTER_MAX)
});
}
#[cfg(feature = "fdcan_h7")]
{
can.sidfc
.modify(|_, w| unsafe { w.lss().bits(STANDARD_FILTER_MAX) });
can.xidfc
.modify(|_, w| unsafe { w.lse().bits(EXTENDED_FILTER_MAX) });
}
for fid in 0..STANDARD_FILTER_MAX {
self.set_standard_filter((fid as u8).into(), StandardFilter::disable());
}
for fid in 0..EXTENDED_FILTER_MAX {
self.set_extended_filter(fid.into(), ExtendedFilter::disable());
}
self.into_can_mode()
}
#[inline]
pub fn free(mut self) -> I {
self.disable_interrupts(Interrupts::all());
self.enter_init_mode();
self.set_power_down_mode(true);
self.control.instance
}
}
impl<I> FdCan<I, ConfigMode>
where
I: Instance,
{
#[inline]
fn leave_init_mode(&mut self) {
self.apply_config(self.control.config);
let can = self.registers();
can.cccr.modify(|_, w| w.cce().clear_bit());
can.cccr.modify(|_, w| w.init().clear_bit());
while can.cccr.read().init().bit_is_set() {}
}
#[inline]
pub fn into_internal_loopback(mut self) -> FdCan<I, InternalLoopbackMode> {
self.set_loopback_mode(LoopbackMode::Internal);
self.leave_init_mode();
self.into_can_mode()
}
#[inline]
pub fn into_external_loopback(mut self) -> FdCan<I, ExternalLoopbackMode> {
self.set_loopback_mode(LoopbackMode::External);
self.leave_init_mode();
self.into_can_mode()
}
#[inline]
pub fn into_restricted(mut self) -> FdCan<I, RestrictedOperationMode> {
self.set_restricted_operations(true);
self.leave_init_mode();
self.into_can_mode()
}
#[inline]
pub fn into_normal(mut self) -> FdCan<I, NormalOperationMode> {
self.set_normal_operations(true);
self.leave_init_mode();
self.into_can_mode()
}
#[inline]
pub fn into_bus_monitoring(mut self) -> FdCan<I, BusMonitoringMode> {
self.set_bus_monitoring_mode(true);
self.leave_init_mode();
self.into_can_mode()
}
#[inline]
pub fn into_test_mode(mut self) -> FdCan<I, TestMode> {
self.set_test_mode(true);
self.leave_init_mode();
self.into_can_mode()
}
#[inline]
pub fn into_powered_down(mut self) -> FdCan<I, PoweredDownMode> {
self.set_power_down_mode(true);
self.leave_init_mode();
self.into_can_mode()
}
#[inline]
pub fn apply_config(&mut self, config: FdCanConfig) {
self.set_data_bit_timing(config.dbtr);
self.set_nominal_bit_timing(config.nbtr);
self.set_automatic_retransmit(config.automatic_retransmit);
self.set_transmit_pause(config.transmit_pause);
self.set_frame_transmit(config.frame_transmit);
self.set_interrupt_line_config(config.interrupt_line_config);
self.set_non_iso_mode(config.non_iso_mode);
self.set_edge_filtering(config.edge_filtering);
self.set_protocol_exception_handling(config.protocol_exception_handling);
self.set_global_filter(config.global_filter);
}
#[inline]
pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) {
self.control.config.nbtr = btr;
let can = self.registers();
can.nbtp.write(|w| unsafe {
w.nbrp()
.bits(btr.nbrp() - 1)
.ntseg1()
.bits(btr.ntseg1() - 1)
.ntseg2()
.bits(btr.ntseg2() - 1)
.nsjw()
.bits(btr.nsjw() - 1)
});
}
#[inline]
pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) {
self.control.config.dbtr = btr;
let can = self.registers();
can.dbtp.write(|w| unsafe {
w.dbrp()
.bits(btr.dbrp() - 1)
.dtseg1()
.bits(btr.dtseg1() - 1)
.dtseg2()
.bits(btr.dtseg2() - 1)
.dsjw()
.bits(btr.dsjw() - 1)
});
}
#[inline]
pub fn set_automatic_retransmit(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.dar().bit(!enabled));
self.control.config.automatic_retransmit = enabled;
}
#[inline]
pub fn set_transmit_pause(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.dar().bit(!enabled));
self.control.config.transmit_pause = enabled;
}
#[inline]
pub fn set_non_iso_mode(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.niso().bit(enabled));
self.control.config.non_iso_mode = enabled;
}
#[inline]
pub fn set_edge_filtering(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.efbi().bit(enabled));
self.control.config.edge_filtering = enabled;
}
#[inline]
pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) {
let (fdoe, brse) = match fts {
FrameTransmissionConfig::ClassicCanOnly => (false, false),
FrameTransmissionConfig::AllowFdCan => (true, false),
FrameTransmissionConfig::AllowFdCanAndBRS => (true, true),
};
let can = self.registers();
can.cccr.modify(|_, w| w.fdoe().bit(fdoe).brse().bit(brse));
self.control.config.frame_transmit = fts;
}
#[inline]
pub fn set_interrupt_line_config(&mut self, l0int: Interrupts) {
let can = self.registers();
can.ils.modify(|_, w| unsafe { w.bits(l0int.bits()) });
self.control.config.interrupt_line_config = l0int;
}
#[inline]
pub fn set_protocol_exception_handling(&mut self, enabled: bool) {
let can = self.registers();
can.cccr.modify(|_, w| w.pxhd().bit(!enabled));
self.control.config.protocol_exception_handling = enabled;
}
#[inline]
pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) {
let (tcp, tss) = match select {
TimestampSource::None => (0, 0b00),
TimestampSource::Prescaler(p) => (p as u8, 0b01),
TimestampSource::FromTIM3 => (0, 0b10),
};
self.registers()
.tscc
.write(|w| unsafe { w.tcp().bits(tcp).tss().bits(tss) });
self.control.config.timestamp_source = select;
}
#[inline]
pub fn set_global_filter(&mut self, filter: GlobalFilter) {
self.registers().rxgfc.modify(|_, w| {
unsafe {
w.anfs()
.bits(filter.handle_standard_frames as u8)
.anfe()
.bits(filter.handle_extended_frames as u8)
}
.rrfs()
.bit(filter.reject_remote_standard_frames)
.rrfe()
.bit(filter.reject_remote_extended_frames)
});
}
#[inline]
pub fn timestamp(&self) -> u16 {
self.control.timestamp()
}
}
impl<I> FdCan<I, InternalLoopbackMode>
where
I: Instance,
{
#[inline]
pub fn into_config_mode(mut self) -> FdCan<I, ConfigMode> {
self.set_loopback_mode(LoopbackMode::None);
self.enter_init_mode();
self.into_can_mode()
}
}
impl<I> FdCan<I, ExternalLoopbackMode>
where
I: Instance,
{
#[inline]
pub fn into_config_mode(mut self) -> FdCan<I, ConfigMode> {
self.set_loopback_mode(LoopbackMode::None);
self.enter_init_mode();
self.into_can_mode()
}
}
impl<I> FdCan<I, NormalOperationMode>
where
I: Instance,
{
#[inline]
pub fn into_config_mode(mut self) -> FdCan<I, ConfigMode> {
self.set_normal_operations(false);
self.enter_init_mode();
self.into_can_mode()
}
}
impl<I> FdCan<I, RestrictedOperationMode>
where
I: Instance,
{
#[inline]
pub fn into_config_mode(mut self) -> FdCan<I, ConfigMode> {
self.set_restricted_operations(false);
self.enter_init_mode();
self.into_can_mode()
}
}
impl<I> FdCan<I, BusMonitoringMode>
where
I: Instance,
{
#[inline]
pub fn into_config_mode(mut self) -> FdCan<I, ConfigMode> {
self.set_bus_monitoring_mode(false);
self.enter_init_mode();
self.into_can_mode()
}
}
pub enum TestTransmitPinState {
CoreHasControl = 0b00,
ShowSamplePoint = 0b01,
SetDominant = 0b10,
SetRecessive = 0b11,
}
impl<I> FdCan<I, TestMode>
where
I: Instance,
{
#[inline]
pub fn into_config_mode(mut self) -> FdCan<I, ConfigMode> {
self.set_test_mode(false);
self.enter_init_mode();
self.into_can_mode()
}
pub fn get_receive_pin(&mut self) -> bool {
let can = self.registers();
can.test.read().rx().bit_is_set()
}
pub fn set_transmit_pin(&mut self, state: TestTransmitPinState) {
let can = self.registers();
can.test.modify(|_, w| unsafe { w.tx().bits(state as u8) });
}
}
impl<I, M> FdCan<I, M>
where
I: Instance,
M: Transmit + Receive,
{
#[inline]
#[allow(clippy::type_complexity)]
pub fn split_by_ref(
&mut self,
) -> (
&mut FdCanControl<I, M>,
&mut Tx<I, M>,
&mut Rx<I, M, Fifo0>,
&mut Rx<I, M, Fifo1>,
) {
self.split_by_ref_generic()
}
#[allow(clippy::type_complexity)]
pub fn split(
self,
) -> (
FdCanControl<I, M>,
Tx<I, M>,
Rx<I, M, Fifo0>,
Rx<I, M, Fifo1>,
) {
self.split_generic()
}
}
impl<I, M> FdCan<I, M>
where
I: Instance,
M: Transmit,
{
#[inline]
pub fn transmit(
&mut self,
frame: TxFrameHeader,
buffer: &[u8],
) -> nb::Result<Option<()>, Infallible> {
unsafe { Tx::<I, M>::conjure().transmit(frame, buffer) }
}
pub fn transmit_preserve<PTX, P>(
&mut self,
frame: TxFrameHeader,
buffer: &[u8],
pending: &mut PTX,
) -> nb::Result<Option<P>, Infallible>
where
PTX: FnMut(Mailbox, TxFrameHeader, &[u32]) -> P,
{
unsafe { Tx::<I, M>::conjure().transmit_preserve(frame, buffer, pending) }
}
#[inline]
pub fn is_transmitter_idle(&self) -> bool {
unsafe { Tx::<I, M>::conjure().is_idle() }
}
#[inline]
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
unsafe { Tx::<I, M>::conjure().abort(mailbox) }
}
}
impl<I, M> FdCan<I, M>
where
I: Instance,
M: Receive,
{
#[inline]
pub fn receive0(
&mut self,
buffer: &mut [u8],
) -> nb::Result<ReceiveOverrun<RxFrameInfo>, Infallible> {
unsafe { Rx::<I, M, Fifo0>::conjure().receive(buffer) }
}
#[inline]
pub fn receive1(
&mut self,
buffer: &mut [u8],
) -> nb::Result<ReceiveOverrun<RxFrameInfo>, Infallible> {
unsafe { Rx::<I, M, Fifo1>::conjure().receive(buffer) }
}
}
pub struct FdCanControl<I, MODE>
where
I: Instance,
{
config: FdCanConfig,
instance: I,
_mode: PhantomData<MODE>,
}
impl<I, MODE> FdCanControl<I, MODE>
where
I: Instance,
{
#[inline]
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
#[inline]
pub fn error_counters(&self) -> ErrorCounters {
let can = self.registers();
let cel: u8 = can.ecr.read().cel().bits();
let rp: bool = can.ecr.read().rp().bits();
let rec: u8 = can.ecr.read().rec().bits();
let tec: u8 = can.ecr.read().tec().bits();
ErrorCounters {
can_errors: cel,
transmit_err: tec,
receive_err: match rp {
false => ReceiveErrorOverflow::Normal(rec),
true => ReceiveErrorOverflow::Overflow(rec),
},
}
}
#[inline]
pub fn timestamp(&self) -> u16 {
self.registers().tscv.read().tsc().bits()
}
#[inline]
pub fn has_interrupt(&mut self, interrupt: Interrupt) -> bool {
let can = self.registers();
can.ir.read().bits() & (interrupt as u32) > 0
}
#[inline]
pub fn clear_interrupt(&mut self, interrupt: Interrupt) {
let can = self.registers();
can.ir.write(|w| unsafe { w.bits(interrupt as u32) });
}
#[inline]
pub fn clear_interrupts(&mut self, interrupts: Interrupts) {
let can = self.registers();
can.ir.write(|w| unsafe { w.bits(interrupts.bits()) });
}
}
pub struct Tx<I, MODE> {
_can: PhantomData<I>,
_mode: PhantomData<MODE>,
}
impl<I, MODE> Tx<I, MODE>
where
I: Instance,
{
#[inline]
unsafe fn conjure() -> Self {
Self {
_can: PhantomData,
_mode: PhantomData,
}
}
#[inline]
unsafe fn conjure_by_ref<'a>() -> &'a mut Self {
#[allow(clippy::unnecessary_operation)]
[()][core::mem::size_of::<Self>()];
&mut *NonNull::dangling().as_ptr()
}
#[inline]
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
#[inline]
fn tx_msg_ram(&self) -> &message_ram::Transmit {
unsafe { &(*I::MSG_RAM).transmit }
}
#[inline]
fn tx_msg_ram_mut(&mut self) -> &mut message_ram::Transmit {
unsafe { &mut (*I::MSG_RAM).transmit }
}
pub fn transmit(
&mut self,
frame: TxFrameHeader,
buffer: &[u8],
) -> nb::Result<Option<()>, Infallible> {
self.transmit_preserve(frame, buffer, &mut |_, _, _| ())
}
pub fn transmit_preserve<PTX, P>(
&mut self,
frame: TxFrameHeader,
buffer: &[u8],
pending: &mut PTX,
) -> nb::Result<Option<P>, Infallible>
where
PTX: FnMut(Mailbox, TxFrameHeader, &[u32]) -> P,
{
let can = self.registers();
let queue_is_full = self.tx_queue_is_full();
let id = frame.into();
let (idx, pending_frame) = if queue_is_full {
if self.is_available(Mailbox::_0, id) {
(
Mailbox::_0,
self.abort_pending_mailbox(Mailbox::_0, pending),
)
} else if self.is_available(Mailbox::_1, id) {
(
Mailbox::_1,
self.abort_pending_mailbox(Mailbox::_1, pending),
)
} else if self.is_available(Mailbox::_2, id) {
(
Mailbox::_2,
self.abort_pending_mailbox(Mailbox::_2, pending),
)
} else {
return Err(nb::Error::WouldBlock);
}
} else {
let idx = can.txfqs.read().tfqpi().bits();
(Mailbox::new(idx), None)
};
self.write_mailbox(idx, frame, buffer);
Ok(pending_frame)
}
#[inline]
pub fn tx_queue_is_full(&self) -> bool {
self.registers().txfqs.read().tfqf().bit()
}
#[inline]
fn is_available(&self, idx: Mailbox, id: IdReg) -> bool {
if self.has_pending_frame(idx) {
let header: TxFrameHeader =
(&self.tx_msg_ram().tbsa[idx as usize].header).into();
let old_id: IdReg = header.into();
id > old_id
} else {
true
}
}
#[inline]
fn write_mailbox(&mut self, idx: Mailbox, tx_header: TxFrameHeader, buffer: &[u8]) {
let tx_ram = self.tx_msg_ram_mut();
let tx_element = &mut tx_ram.tbsa[idx as usize];
tx_element.reset();
tx_element.header.merge(tx_header);
let lbuffer = [0_u32; 16];
let data = unsafe {
slice::from_raw_parts_mut(
lbuffer.as_ptr() as *mut u8,
tx_header.len as usize,
)
};
data[..tx_header.len as usize]
.copy_from_slice(&buffer[..tx_header.len as usize]);
let data_len = ((tx_header.len as usize) + 3) / 4;
tx_element.data[..data_len].copy_from_slice(&lbuffer[..data_len]);
self.registers()
.txbar
.modify(|r, w| unsafe { w.ar().bits(r.ar().bits() | 1 << (idx as u32)) });
}
#[inline]
fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R>
where
PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
{
if self.abort(idx) {
let tx_ram = self.tx_msg_ram();
let header = (&tx_ram.tbsa[idx as usize].header).into();
Some(pending(idx, header, &tx_ram.tbsa[idx as usize].data))
} else {
None
}
}
#[inline]
fn abort(&mut self, idx: Mailbox) -> bool {
let can = self.registers();
if self.has_pending_frame(idx) {
let idx: u8 = idx.into();
let idx: u32 = 1u32 << (idx as u32);
can.txbcr.write(|w| unsafe { w.cr().bits(idx) });
loop {
if can.txbcf.read().cf().bits() & idx != 0 {
break can.txbto.read().to().bits() & idx == 0;
}
}
} else {
false
}
}
#[inline]
fn has_pending_frame(&self, idx: Mailbox) -> bool {
let can = self.registers();
let idx: u8 = idx.into();
let idx: u32 = 1u32 << (idx as u32);
can.txbrp.read().trp().bits() & idx != 0
}
#[inline]
pub fn is_idle(&self) -> bool {
let can = self.registers();
can.txbrp.read().trp().bits() == 0x0
}
#[inline]
pub fn clear_transmission_completed_flag(&mut self) {
let can = self.registers();
can.ir.write(|w| w.tc().set_bit());
}
#[inline]
pub fn clear_transmission_cancelled_flag(&mut self) {
let can = self.registers();
can.ir.write(|w| w.tcf().set_bit());
}
}
#[doc(hidden)]
pub trait FifoNr: sealed::Sealed {
const NR: usize;
}
#[doc(hidden)]
pub struct Fifo0;
impl sealed::Sealed for Fifo0 {}
impl FifoNr for Fifo0 {
const NR: usize = 0;
}
#[doc(hidden)]
pub struct Fifo1;
impl sealed::Sealed for Fifo1 {}
impl FifoNr for Fifo1 {
const NR: usize = 1;
}
#[derive(Clone, Copy, Debug)]
pub enum ReceiveOverrun<T> {
NoOverrun(T),
Overrun(T),
}
impl<T> ReceiveOverrun<T> {
#[inline]
pub fn unwrap(self) -> T {
match self {
ReceiveOverrun::NoOverrun(t) | ReceiveOverrun::Overrun(t) => t,
}
}
}
pub struct Rx<I, MODE, FIFONR>
where
FIFONR: FifoNr,
{
_can: PhantomData<I>,
_mode: PhantomData<MODE>,
_nr: PhantomData<FIFONR>,
}
impl<I, MODE, FIFONR> Rx<I, MODE, FIFONR>
where
FIFONR: FifoNr,
I: Instance,
{
#[inline]
unsafe fn conjure() -> Self {
Self {
_can: PhantomData,
_mode: PhantomData,
_nr: PhantomData,
}
}
#[inline]
unsafe fn conjure_by_ref<'a>() -> &'a mut Self {
#[allow(clippy::unnecessary_operation)]
[()][core::mem::size_of::<Self>()];
&mut *NonNull::dangling().as_ptr()
}
pub fn receive(
&mut self,
buffer: &mut [u8],
) -> nb::Result<ReceiveOverrun<RxFrameInfo>, Infallible> {
if !self.rx_fifo_is_empty() {
let mbox = self.get_rx_mailbox();
let idx: usize = mbox.into();
let mailbox: &RxFifoElement = &self.rx_msg_ram().fxsa[idx];
let header: RxFrameInfo = (&mailbox.header).into();
let data = unsafe {
slice::from_raw_parts(
mailbox.data.as_ptr() as *const u8,
header.len as usize,
)
};
buffer[..header.len as usize].copy_from_slice(data);
self.release_mailbox(mbox);
if self.has_overrun() {
Ok(ReceiveOverrun::<RxFrameInfo>::Overrun(header))
} else {
Ok(ReceiveOverrun::<RxFrameInfo>::NoOverrun(header))
}
} else {
Err(nb::Error::WouldBlock)
}
}
#[inline]
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
#[inline]
fn rx_msg_ram(&self) -> &message_ram::Receive {
unsafe { &(&(*I::MSG_RAM).receive)[FIFONR::NR] }
}
#[inline]
fn has_overrun(&self) -> bool {
let can = self.registers();
match FIFONR::NR {
0 => can.rxf0s.read().rf0l().bit(),
1 => can.rxf1s.read().rf1l().bit(),
_ => unreachable!(),
}
}
#[inline]
pub fn rx_fifo_is_empty(&self) -> bool {
let can = self.registers();
match FIFONR::NR {
0 => can.rxf0s.read().f0fl().bits() == 0,
1 => can.rxf1s.read().f1fl().bits() == 0,
_ => unreachable!(),
}
}
#[inline]
fn release_mailbox(&mut self, idx: Mailbox) {
unsafe {
(*I::MSG_RAM).receive[FIFONR::NR].fxsa[idx as u8 as usize].reset();
}
let can = self.registers();
match FIFONR::NR {
0 => can.rxf0a.write(|w| unsafe { w.f0ai().bits(idx.into()) }),
1 => can.rxf1a.write(|w| unsafe { w.f1ai().bits(idx.into()) }),
_ => unreachable!(),
}
}
#[inline]
fn get_rx_mailbox(&self) -> Mailbox {
let can = self.registers();
let idx = match FIFONR::NR {
0 => can.rxf0s.read().f0gi().bits(),
1 => can.rxf1s.read().f1gi().bits(),
_ => unreachable!(),
};
Mailbox::new(idx)
}
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Mailbox {
_0 = 0,
_1 = 1,
_2 = 2,
}
impl Mailbox {
#[inline]
fn new(idx: u8) -> Self {
match idx & 0b11 {
0 => Mailbox::_0,
1 => Mailbox::_1,
2 => Mailbox::_2,
_ => unreachable!(),
}
}
}
impl From<Mailbox> for u8 {
#[inline]
fn from(m: Mailbox) -> Self {
m as u8
}
}
impl From<Mailbox> for usize {
#[inline]
fn from(m: Mailbox) -> Self {
m as u8 as usize
}
}