use core::marker::PhantomData;
use super::{ExtendedId, Fifo, Id, StandardId};
const F32_RTR: u32 = 0b010; const F32_IDE: u32 = 0b100; const F16_RTR: u16 = 0b10000;
const F16_IDE: u16 = 0b01000;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ListEntry16(u16);
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ListEntry32(u32);
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Mask16 {
id: u16,
mask: u16,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Mask32 {
id: u32,
mask: u32,
}
impl ListEntry16 {
pub fn data_frames_with_id(id: StandardId) -> Self {
Self(id.as_raw() << 5)
}
pub fn remote_frames_with_id(id: StandardId) -> Self {
Self(id.as_raw() << 5 | F16_RTR)
}
}
impl ListEntry32 {
pub fn data_frames_with_id(id: impl Into<Id>) -> Self {
match id.into() {
Id::Standard(id) => Self(u32::from(id.as_raw()) << 21),
Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE),
}
}
pub fn remote_frames_with_id(id: impl Into<Id>) -> Self {
match id.into() {
Id::Standard(id) => Self(u32::from(id.as_raw()) << 21 | F32_RTR),
Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE | F32_RTR),
}
}
}
impl Mask16 {
pub fn accept_all() -> Self {
Self { id: 0, mask: 0 }
}
pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self {
Self {
id: id.as_raw() << 5,
mask: mask.as_raw() << 5 | F16_IDE, }
}
pub fn data_frames_only(&mut self) -> &mut Self {
self.id &= !F16_RTR; self.mask |= F16_RTR;
self
}
pub fn remote_frames_only(&mut self) -> &mut Self {
self.id |= F16_RTR; self.mask |= F16_RTR;
self
}
}
impl Mask32 {
pub fn accept_all() -> Self {
Self { id: 0, mask: 0 }
}
pub fn frames_with_ext_id(id: ExtendedId, mask: ExtendedId) -> Self {
Self {
id: id.as_raw() << 3 | F32_IDE,
mask: mask.as_raw() << 3 | F32_IDE, }
}
pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self {
Self {
id: u32::from(id.as_raw()) << 21,
mask: u32::from(mask.as_raw()) << 21 | F32_IDE, }
}
pub fn data_frames_only(&mut self) -> &mut Self {
self.id &= !F32_RTR; self.mask |= F32_RTR;
self
}
pub fn remote_frames_only(&mut self) -> &mut Self {
self.id |= F32_RTR; self.mask |= F32_RTR;
self
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BankConfig {
List16([ListEntry16; 4]),
List32([ListEntry32; 2]),
Mask16([Mask16; 2]),
Mask32(Mask32),
}
impl From<[ListEntry16; 4]> for BankConfig {
#[inline]
fn from(entries: [ListEntry16; 4]) -> Self {
Self::List16(entries)
}
}
impl From<[ListEntry32; 2]> for BankConfig {
#[inline]
fn from(entries: [ListEntry32; 2]) -> Self {
Self::List32(entries)
}
}
impl From<[Mask16; 2]> for BankConfig {
#[inline]
fn from(entries: [Mask16; 2]) -> Self {
Self::Mask16(entries)
}
}
impl From<Mask32> for BankConfig {
#[inline]
fn from(filter: Mask32) -> Self {
Self::Mask32(filter)
}
}
pub struct MasterFilters<'a> {
bank_count: u8,
_phantom: PhantomData<&'a ()>,
info: &'static crate::can::Info,
}
impl MasterFilters<'_> {
pub(crate) unsafe fn new(info: &'static crate::can::Info) -> Self {
info.regs.0.fmr().modify(|reg| reg.set_finit(true));
let bank_count = info.regs.0.fmr().read().can2sb();
Self {
bank_count,
_phantom: PhantomData,
info,
}
}
fn banks_imm(&self) -> FilterBanks {
FilterBanks {
start_idx: 0,
bank_count: self.bank_count,
info: self.info,
}
}
pub fn num_banks(&self) -> u8 {
self.bank_count
}
pub fn clear(&mut self) -> &mut Self {
self.banks_imm().clear();
self
}
pub fn disable_bank(&mut self, index: u8) -> &mut Self {
self.banks_imm().disable(index);
self
}
pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into<BankConfig>) -> &mut Self {
self.banks_imm().enable(index, fifo, config.into());
self
}
}
impl MasterFilters<'_> {
pub fn set_split(&mut self, split_index: u8) -> &mut Self {
assert!(split_index <= self.info.num_filter_banks);
self.info.regs.0.fmr().modify(|reg| reg.set_can2sb(split_index));
self.bank_count = split_index;
self
}
pub fn slave_filters(&mut self) -> SlaveFilters<'_> {
SlaveFilters {
start_idx: self.bank_count,
bank_count: self.info.num_filter_banks - self.bank_count,
_phantom: PhantomData,
info: self.info,
}
}
}
impl Drop for MasterFilters<'_> {
#[inline]
fn drop(&mut self) {
self.info.regs.0.fmr().modify(|regs| regs.set_finit(false));
}
}
pub struct SlaveFilters<'a> {
start_idx: u8,
bank_count: u8,
_phantom: PhantomData<&'a ()>,
info: &'static crate::can::Info,
}
impl SlaveFilters<'_> {
fn banks_imm(&self) -> FilterBanks {
FilterBanks {
start_idx: self.start_idx,
bank_count: self.bank_count,
info: self.info,
}
}
pub fn num_banks(&self) -> u8 {
self.bank_count
}
pub fn clear(&mut self) -> &mut Self {
self.banks_imm().clear();
self
}
pub fn disable_bank(&mut self, index: u8) -> &mut Self {
self.banks_imm().disable(index);
self
}
pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into<BankConfig>) -> &mut Self {
self.banks_imm().enable(index, fifo, config.into());
self
}
}
struct FilterBanks {
start_idx: u8,
bank_count: u8,
info: &'static crate::can::Info,
}
impl FilterBanks {
fn clear(&mut self) {
let mask = filter_bitmask(self.start_idx, self.bank_count);
self.info.regs.0.fa1r().modify(|reg| {
for i in 0..28usize {
if (0x01u32 << i) & mask != 0 {
reg.set_fact(i, false);
}
}
});
}
fn assert_bank_index(&self, index: u8) {
assert!((self.start_idx..self.start_idx + self.bank_count).contains(&index));
}
fn disable(&mut self, index: u8) {
self.assert_bank_index(index);
self.info
.regs
.0
.fa1r()
.modify(|reg| reg.set_fact(index as usize, false))
}
fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) {
self.assert_bank_index(index);
let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_));
self.info.regs.0.fm1r().modify(|reg| reg.set_fbm(index as usize, mode));
let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_));
self.info.regs.0.fs1r().modify(|reg| reg.set_fsc(index as usize, scale));
let (fxr1, fxr2);
match config {
BankConfig::List16([a, b, c, d]) => {
fxr1 = (u32::from(b.0) << 16) | u32::from(a.0);
fxr2 = (u32::from(d.0) << 16) | u32::from(c.0);
}
BankConfig::List32([a, b]) => {
fxr1 = a.0;
fxr2 = b.0;
}
BankConfig::Mask16([a, b]) => {
fxr1 = (u32::from(a.mask) << 16) | u32::from(a.id);
fxr2 = (u32::from(b.mask) << 16) | u32::from(b.id);
}
BankConfig::Mask32(a) => {
fxr1 = a.id;
fxr2 = a.mask;
}
};
let bank = self.info.regs.0.fb(index as usize);
bank.fr1().write(|w| w.0 = fxr1);
bank.fr2().write(|w| w.0 = fxr2);
self.info.regs.0.ffa1r().modify(|reg| {
reg.set_ffa(
index as usize,
match fifo {
Fifo::Fifo0 => false,
Fifo::Fifo1 => true,
},
)
});
self.info.regs.0.fa1r().modify(|reg| reg.set_fact(index as usize, true))
}
}
fn filter_bitmask(start_idx: u8, bank_count: u8) -> u32 {
let count_mask = (1 << bank_count) - 1; count_mask << start_idx
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_filter_bitmask() {
assert_eq!(filter_bitmask(0, 1), 0x1);
assert_eq!(filter_bitmask(1, 1), 0b10);
assert_eq!(filter_bitmask(0, 4), 0xf);
assert_eq!(filter_bitmask(1, 3), 0xe);
assert_eq!(filter_bitmask(8, 1), 0x100);
assert_eq!(filter_bitmask(8, 4), 0xf00);
}
}