bxcan_ng/
filter.rs

1//! Filter bank API.
2
3use core::marker::PhantomData;
4
5use crate::pac::can::RegisterBlock;
6use crate::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId};
7
8const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames
9const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers
10const F16_RTR: u16 = 0b10000;
11const F16_IDE: u16 = 0b01000;
12
13/// A 16-bit filter list entry.
14///
15/// This can match data and remote frames using standard IDs.
16#[derive(Debug, Copy, Clone, Eq, PartialEq)]
17#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
18pub struct ListEntry16(u16);
19
20/// A 32-bit filter list entry.
21///
22/// This can match data and remote frames using extended or standard IDs.
23#[derive(Debug, Copy, Clone, Eq, PartialEq)]
24#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
25pub struct ListEntry32(u32);
26
27/// A 16-bit identifier mask.
28#[derive(Debug, Copy, Clone)]
29#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
30pub struct Mask16 {
31    id: u16,
32    mask: u16,
33}
34
35/// A 32-bit identifier mask.
36#[derive(Debug, Copy, Clone)]
37#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
38pub struct Mask32 {
39    id: u32,
40    mask: u32,
41}
42
43impl ListEntry16 {
44    /// Creates a filter list entry that accepts data frames with the given standard ID.
45    ///
46    /// This entry will *not* accept remote frames with the same ID.
47    pub fn data_frames_with_id(id: StandardId) -> Self {
48        Self(id.as_raw() << 5)
49    }
50
51    /// Creates a filter list entry that accepts remote frames with the given standard ID.
52    pub fn remote_frames_with_id(id: StandardId) -> Self {
53        Self(id.as_raw() << 5 | F16_RTR)
54    }
55}
56
57impl ListEntry32 {
58    /// Creates a filter list entry that accepts data frames with the given ID.
59    ///
60    /// This entry will *not* accept remote frames with the same ID.
61    ///
62    /// The filter will only accept *either* standard *or* extended frames, depending on `id`.
63    pub fn data_frames_with_id(id: impl Into<Id>) -> Self {
64        match id.into() {
65            Id::Standard(id) => Self(u32::from(id.as_raw()) << 21),
66            Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE),
67        }
68    }
69
70    /// Creates a filter list entry that accepts remote frames with the given ID.
71    pub fn remote_frames_with_id(id: impl Into<Id>) -> Self {
72        match id.into() {
73            Id::Standard(id) => Self(u32::from(id.as_raw()) << 21 | F32_RTR),
74            Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE | F32_RTR),
75        }
76    }
77}
78
79impl Mask16 {
80    /// Creates a 16-bit identifier mask that accepts all frames.
81    ///
82    /// This will accept both standard and extended data and remote frames with any ID.
83    pub fn accept_all() -> Self {
84        Self { id: 0, mask: 0 }
85    }
86
87    /// Creates a 16-bit identifier mask that accepts all frames with the given standard
88    /// ID and mask combination.
89    ///
90    /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)`
91    ///
92    /// A mask of all all ones (`0x7FF`) matches an exact ID, a mask of 0 matches all IDs.
93    ///
94    /// Both data and remote frames with `id` will be accepted. Any extended frames will be
95    /// rejected.
96    pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self {
97        Self {
98            id: id.as_raw() << 5,
99            mask: mask.as_raw() << 5 | F16_IDE, // also require IDE = 0
100        }
101    }
102
103    /// Make the filter accept data frames only.
104    pub fn data_frames_only(&mut self) -> &mut Self {
105        self.id &= !F16_RTR; // RTR = 0
106        self.mask |= F16_RTR;
107        self
108    }
109
110    /// Make the filter accept remote frames only.
111    pub fn remote_frames_only(&mut self) -> &mut Self {
112        self.id |= F16_RTR; // RTR = 1
113        self.mask |= F16_RTR;
114        self
115    }
116}
117
118impl Mask32 {
119    /// Creates a 32-bit identifier mask that accepts all frames.
120    ///
121    /// This will accept both standard and extended data and remote frames with any ID.
122    pub fn accept_all() -> Self {
123        Self { id: 0, mask: 0 }
124    }
125
126    /// Creates a 32-bit identifier mask that accepts all frames with the given extended
127    /// ID and mask combination.
128    ///
129    /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)`
130    ///
131    /// A mask of all all ones (`0x1FFF_FFFF`) matches an exact ID, a mask of 0 matches all IDs.
132    ///
133    /// Both data and remote frames with `id` will be accepted. Standard frames will be rejected.
134    pub fn frames_with_ext_id(id: ExtendedId, mask: ExtendedId) -> Self {
135        Self {
136            id: id.as_raw() << 3 | F32_IDE,
137            mask: mask.as_raw() << 3 | F32_IDE, // also require IDE = 1
138        }
139    }
140
141    /// Creates a 32-bit identifier mask that accepts all frames with the given standard
142    /// ID and mask combination.
143    ///
144    /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)`
145    ///
146    /// A mask of all all ones (`0x7FF`) matches the exact ID, a mask of 0 matches all IDs.
147    ///
148    /// Both data and remote frames with `id` will be accepted. Extended frames will be rejected.
149    pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self {
150        Self {
151            id: u32::from(id.as_raw()) << 21,
152            mask: u32::from(mask.as_raw()) << 21 | F32_IDE, // also require IDE = 0
153        }
154    }
155
156    /// Make the filter accept data frames only.
157    pub fn data_frames_only(&mut self) -> &mut Self {
158        self.id &= !F32_RTR; // RTR = 0
159        self.mask |= F32_RTR;
160        self
161    }
162
163    /// Make the filter accept remote frames only.
164    pub fn remote_frames_only(&mut self) -> &mut Self {
165        self.id |= F32_RTR; // RTR = 1
166        self.mask |= F32_RTR;
167        self
168    }
169}
170
171/// The configuration of a filter bank.
172#[derive(Debug, Copy, Clone)]
173#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
174pub enum BankConfig {
175    List16([ListEntry16; 4]),
176    List32([ListEntry32; 2]),
177    Mask16([Mask16; 2]),
178    Mask32(Mask32),
179}
180
181impl From<[ListEntry16; 4]> for BankConfig {
182    #[inline]
183    fn from(entries: [ListEntry16; 4]) -> Self {
184        Self::List16(entries)
185    }
186}
187
188impl From<[ListEntry32; 2]> for BankConfig {
189    #[inline]
190    fn from(entries: [ListEntry32; 2]) -> Self {
191        Self::List32(entries)
192    }
193}
194
195impl From<[Mask16; 2]> for BankConfig {
196    #[inline]
197    fn from(entries: [Mask16; 2]) -> Self {
198        Self::Mask16(entries)
199    }
200}
201
202impl From<Mask32> for BankConfig {
203    #[inline]
204    fn from(filter: Mask32) -> Self {
205        Self::Mask32(filter)
206    }
207}
208
209/// Interface to the filter banks of a CAN peripheral.
210pub struct MasterFilters<'a, I: FilterOwner> {
211    /// Number of assigned filter banks.
212    ///
213    /// On chips with splittable filter banks, this value can be dynamic.
214    bank_count: u8,
215    _can: PhantomData<&'a mut I>,
216}
217
218// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it
219// exists.
220impl<I: FilterOwner> MasterFilters<'_, I> {
221    pub(crate) unsafe fn new() -> Self {
222        let can = &*I::REGISTERS;
223
224        // Enable initialization mode.
225        can.fmr.modify(|_, w| w.finit().set_bit());
226
227        // Read the filter split value.
228        let bank_count = can.fmr.read().can2sb().bits();
229
230        // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all
231        // of them to the master peripheral, and in devices with 28, assigns them 50/50 to
232        // master/slave instances)
233
234        Self {
235            bank_count,
236            _can: PhantomData,
237        }
238    }
239
240    fn registers(&self) -> &RegisterBlock {
241        unsafe { &*I::REGISTERS }
242    }
243
244    fn banks_imm(&self) -> FilterBanks<'_> {
245        FilterBanks {
246            start_idx: 0,
247            bank_count: self.bank_count,
248            can: self.registers(),
249        }
250    }
251
252    /// Returns the number of filter banks currently assigned to this instance.
253    ///
254    /// Chips with splittable filter banks may start out with some banks assigned to the master
255    /// instance and some assigned to the slave instance.
256    pub fn num_banks(&self) -> u8 {
257        self.bank_count
258    }
259
260    /// Disables all enabled filter banks.
261    ///
262    /// This causes all incoming frames to be disposed.
263    pub fn clear(&mut self) -> &mut Self {
264        self.banks_imm().clear();
265        self
266    }
267
268    /// Disables a filter bank.
269    ///
270    /// If `index` is out of bounds, this will panic.
271    pub fn disable_bank(&mut self, index: u8) -> &mut Self {
272        self.banks_imm().disable(index);
273        self
274    }
275
276    /// Configures a filter bank according to `config` and enables it.
277    ///
278    /// Each filter bank is associated with one of the two RX FIFOs, configured by the [`Fifo`]
279    /// passed to this function. In the event that both FIFOs are configured to accept an incoming
280    /// frame, the accepting filter bank with the lowest index wins. The FIFO state is ignored, so
281    /// if the FIFO is full, it will overflow, even if the other FIFO is also configured to accept
282    /// the frame.
283    ///
284    /// # Parameters
285    ///
286    /// - `index`: the filter index.
287    /// - `fifo`: the receive FIFO the filter should pass accepted messages to.
288    /// - `config`: the filter configuration.
289    pub fn enable_bank(
290        &mut self,
291        index: u8,
292        fifo: Fifo,
293        config: impl Into<BankConfig>,
294    ) -> &mut Self {
295        self.banks_imm().enable(index, fifo, config.into());
296        self
297    }
298}
299
300impl<I: MasterInstance> MasterFilters<'_, I> {
301    /// Sets the index at which the filter banks owned by the slave peripheral start.
302    pub fn set_split(&mut self, split_index: u8) -> &mut Self {
303        assert!(split_index <= I::NUM_FILTER_BANKS);
304        self.registers()
305            .fmr
306            .modify(|_, w| unsafe { w.can2sb().bits(split_index) });
307        self.bank_count = split_index;
308        self
309    }
310
311    /// Accesses the filters assigned to the slave peripheral.
312    pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> {
313        // NB: This mutably borrows `self`, so it has full access to the filter bank registers.
314        SlaveFilters {
315            start_idx: self.bank_count,
316            bank_count: I::NUM_FILTER_BANKS - self.bank_count,
317            _can: PhantomData,
318        }
319    }
320}
321
322impl<I: FilterOwner> Drop for MasterFilters<'_, I> {
323    #[inline]
324    fn drop(&mut self) {
325        let can = self.registers();
326
327        // Leave initialization mode.
328        can.fmr.modify(|_, w| w.finit().clear_bit());
329    }
330}
331
332/// Interface to the filter banks assigned to a slave peripheral.
333pub struct SlaveFilters<'a, I: Instance> {
334    start_idx: u8,
335    bank_count: u8,
336    _can: PhantomData<&'a mut I>,
337}
338
339impl<I: Instance> SlaveFilters<'_, I> {
340    fn registers(&self) -> &RegisterBlock {
341        unsafe { &*I::REGISTERS }
342    }
343
344    fn banks_imm(&self) -> FilterBanks<'_> {
345        FilterBanks {
346            start_idx: self.start_idx,
347            bank_count: self.bank_count,
348            can: self.registers(),
349        }
350    }
351
352    /// Returns the number of filter banks currently assigned to this instance.
353    ///
354    /// Chips with splittable filter banks may start out with some banks assigned to the master
355    /// instance and some assigned to the slave instance.
356    pub fn num_banks(&self) -> u8 {
357        self.bank_count
358    }
359
360    /// Disables all enabled filter banks.
361    ///
362    /// This causes all incoming frames to be disposed.
363    pub fn clear(&mut self) -> &mut Self {
364        self.banks_imm().clear();
365        self
366    }
367
368    /// Disables a filter bank.
369    ///
370    /// If `index` is out of bounds, this will panic.
371    pub fn disable_bank(&mut self, index: u8) -> &mut Self {
372        self.banks_imm().disable(index);
373        self
374    }
375
376    /// Configures a filter bank according to `config` and enables it.
377    ///
378    /// # Parameters
379    ///
380    /// - `index`: the filter index.
381    /// - `fifo`: the receive FIFO the filter should pass accepted messages to.
382    /// - `config`: the filter configuration.
383    pub fn enable_bank(
384        &mut self,
385        index: u8,
386        fifo: Fifo,
387        config: impl Into<BankConfig>,
388    ) -> &mut Self {
389        self.banks_imm().enable(index, fifo, config.into());
390        self
391    }
392}
393
394struct FilterBanks<'a> {
395    start_idx: u8,
396    bank_count: u8,
397    can: &'a RegisterBlock,
398}
399
400impl FilterBanks<'_> {
401    fn clear(&mut self) {
402        let mask = filter_bitmask(self.start_idx, self.bank_count);
403
404        self.can.fa1r.modify(|r, w| {
405            let bits = r.bits();
406            // Clear all bits in `mask`.
407            unsafe { w.bits(bits & !mask) }
408        });
409    }
410
411    fn assert_bank_index(&self, index: u8) {
412        assert!((self.start_idx..self.start_idx + self.bank_count).contains(&index));
413    }
414
415    fn disable(&mut self, index: u8) {
416        self.assert_bank_index(index);
417
418        self.can
419            .fa1r
420            .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << index)) })
421    }
422
423    fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) {
424        self.assert_bank_index(index);
425
426        // Configure mode.
427        let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_));
428        self.can.fm1r.modify(|r, w| {
429            let mut bits = r.bits();
430            if mode {
431                bits |= 1 << index;
432            } else {
433                bits &= !(1 << index);
434            }
435            unsafe { w.bits(bits) }
436        });
437
438        // Configure scale.
439        let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_));
440        self.can.fs1r.modify(|r, w| {
441            let mut bits = r.bits();
442            if scale {
443                bits |= 1 << index;
444            } else {
445                bits &= !(1 << index);
446            }
447            unsafe { w.bits(bits) }
448        });
449
450        // Configure filter register.
451        let (fxr1, fxr2);
452        match config {
453            BankConfig::List16([a, b, c, d]) => {
454                fxr1 = (u32::from(b.0) << 16) | u32::from(a.0);
455                fxr2 = (u32::from(d.0) << 16) | u32::from(c.0);
456            }
457            BankConfig::List32([a, b]) => {
458                fxr1 = a.0;
459                fxr2 = b.0;
460            }
461            BankConfig::Mask16([a, b]) => {
462                fxr1 = (u32::from(a.mask) << 16) | u32::from(a.id);
463                fxr2 = (u32::from(b.mask) << 16) | u32::from(b.id);
464            }
465            BankConfig::Mask32(a) => {
466                fxr1 = a.id;
467                fxr2 = a.mask;
468            }
469        };
470        let bank = &self.can.fb[usize::from(index)];
471        bank.fr1.write(|w| unsafe { w.bits(fxr1) });
472        bank.fr2.write(|w| unsafe { w.bits(fxr2) });
473
474        // Assign to the right FIFO
475        self.can.ffa1r.modify(|r, w| unsafe {
476            let mut bits = r.bits();
477            match fifo {
478                Fifo::Fifo0 => bits &= !(1 << index),
479                Fifo::Fifo1 => bits |= 1 << index,
480            }
481            w.bits(bits)
482        });
483
484        // Set active.
485        self.can
486            .fa1r
487            .modify(|r, w| unsafe { w.bits(r.bits() | (1 << index)) })
488    }
489}
490
491/// Computes a bitmask for per-filter-bank registers that only includes filters in the given range.
492fn filter_bitmask(start_idx: u8, bank_count: u8) -> u32 {
493    let count_mask = (1 << bank_count) - 1; // `bank_count` 1-bits
494    count_mask << start_idx
495}
496
497#[cfg(test)]
498mod tests {
499    use super::*;
500
501    #[test]
502    fn test_filter_bitmask() {
503        assert_eq!(filter_bitmask(0, 1), 0x1);
504        assert_eq!(filter_bitmask(1, 1), 0b10);
505        assert_eq!(filter_bitmask(0, 4), 0xf);
506        assert_eq!(filter_bitmask(1, 3), 0xe);
507        assert_eq!(filter_bitmask(8, 1), 0x100);
508        assert_eq!(filter_bitmask(8, 4), 0xf00);
509    }
510}