1
//! Two-wire Automotive Interface (TWAI) Filters
2
//!
3
//! ## Overview
4
//!
5
//! The TWAI controller contains a hardware acceptance filter which can be used
6
//! to filter messages of a particular ID. A node that filters out a message
7
//! does not receive the message, but will still acknowledge it. Acceptance
8
//! filters can make a node more efficient by filtering out messages sent over
9
//! the bus that are irrelevant to the node.
10
//!
11
//! ## Configuration
12
//!
13
//! The acceptance filters are configured using two 32-bit values known as the
14
//! acceptance code and the acceptance mask.
15

            
16
use super::{ExtendedId, StandardId};
17

            
18
8
#[derive(Debug, PartialEq, Eq)]
19
/// Represents the type of filtering to be applied to incoming TWAI frames.
20
pub enum FilterType {
21
    /// Uses the acceptance code and mask to define a single filter, which
22
    /// allows for the first two data bytes of a standard frame to be filtered,
23
    /// or the entirety of an extended frame's 29-bit ID.
24
    Single,
25
    /// Uses the acceptance code and mask to define two separate filters
26
    /// allowing for increased flexibility of ID's to accept, but does not allow
27
    /// for all 29-bits of an extended ID to be filtered.
28
    Dual,
29
}
30

            
31
/// Interface for interacting with Acceptance Filters.
32
///
33
/// The Acceptance Filter is a programmable message filtering unit that allows
34
/// the TWAI controller to accept or reject a received message based on the
35
/// message’s ID field.
36
///
37
/// Only accepted messages will be stored in the Receive FIFO.
38
///
39
/// The Acceptance Filter’s registers can be programmed to specify a single
40
/// filter, or two separate filters (dual filter mode).
41
pub trait Filter {
42
    /// The type of the filter.
43
    const FILTER_TYPE: FilterType;
44
    /// Returns filter type.
45
    fn filter_type(&self) -> FilterType {
46
        Self::FILTER_TYPE
47
    }
48

            
49
    /// Returns the register level representation of the filter.
50
    fn to_registers(&self) -> [u8; 8];
51
}
52

            
53
/// A type representing the bitmask used to filter incoming TWAI frames.
54
pub type BitFilter<const N: usize> = [u8; N];
55

            
56
// Convert a byte from a bytestring into a bit inside a given code and mask.
57
macro_rules! set_bit_from_byte {
58
    ($code:expr, $mask:expr, $byte:expr, $shift:expr) => {
59
3
        match $byte {
60
            b'0' => {
61
                // Code bit is already zero, no need to set it.
62
3
                $mask |= 1 << $shift;
63
            }
64
            b'1' => {
65
                $code |= 1 << $shift;
66
                $mask |= 1 << $shift;
67
            }
68
            b'x' => {}
69
            _ => ::core::panic!("BitFilter bits must be either '1', '0' or 'x'."),
70
        }
71
    };
72
}
73

            
74
// Convert a code and mask to the byte array needed at a register level.
75
//
76
// On the input mask, set bits (1) mean we care about the exact value of the
77
// corresponding bit in the code, reset bits (0) mean the bit could be any
78
// value.
79
const fn code_mask_to_register_array(code: u32, mask: u32) -> [u8; 8] {
80
    // Convert the filter code and mask into the full byte array needed for the
81
    // registers.
82
    let [code_3, code_2, code_1, code_0] = code.to_be_bytes();
83

            
84
    // At a register level, set bits in the mask mean we don't care about the value
85
    // of that bit. Therefore, we invert the mask.
86
    // https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf#subsubsection.29.4.6
87
3
    let [mask_3, mask_2, mask_1, mask_0] = (!mask).to_be_bytes();
88

            
89
    [
90
        code_3, code_2, code_1, code_0, mask_3, mask_2, mask_1, mask_0,
91
    ]
92
}
93

            
94
/// A filter that matches against a single 11 bit id, the RTR bit, and the first
95
/// two bytes of the payload.
96
///
97
/// Warning: This is not a perfect filter. Extended IDs that match the bit
98
/// layout of this filter will also be accepted.
99
pub struct SingleStandardFilter {
100
    /// The register representation of the filter.
101
    raw: [u8; 8],
102
}
103

            
104
impl SingleStandardFilter {
105
    #[procmacros::doc_replace]
106
    /// Creates a new filter that matches against a single 11-bit standard id.
107
    /// The filter can match against the packet's id, RTR bit, and first two
108
    /// bytes of the payload.
109
    ///
110
    /// Example matching only even IDs, allowing any rtr value and any payload
111
    /// data:
112
    /// ```rust, no_run
113
    /// # {before_snippet}
114
    /// # use esp_hal::twai::filter::SingleStandardFilter;
115
    /// const FILTER: SingleStandardFilter =
116
    ///     SingleStandardFilter::new(b"xxxxxxxxxx0", b"x", [b"xxxxxxxx", b"xxxxxxxx"]);
117
    /// # {after_snippet}
118
    /// ```
119
3
    pub const fn new(id: &BitFilter<11>, rtr: &BitFilter<1>, payload: [&BitFilter<8>; 2]) -> Self {
120
        // The bit values we desire to match against. This determines whether we want a
121
        // set bit (1) or a reset bit (0).
122
        let mut acceptance_code: u32 = 0;
123
        // The acceptance mask, set bits (1) mean we care about the exact value of the
124
        // corresponding bit in the code, reset bits (0) mean the bit could be any
125
        // value.
126
        let mut acceptance_mask: u32 = 0;
127

            
128
        // Convert the id filter into the code and mask bits.
129
        {
130
            let mut idx = 0;
131
            while idx < 11 {
132
                let shift = 31 - idx;
133
                set_bit_from_byte!(acceptance_code, acceptance_mask, id[idx], shift);
134
                idx += 1;
135
            }
136
        }
137
        // Convert the RTR bit filter into the code and mask bits.
138
        {
139
            let shift = 20;
140
            set_bit_from_byte!(acceptance_code, acceptance_mask, rtr[0], shift);
141
        }
142
        // Convert the payload byte filter into the code and mask bits.
143
        {
144
            let mut payload_index = 0;
145
            while payload_index < 2 {
146
                let mut idx = 0;
147
                while idx < 8 {
148
                    let shift = 15 - (8 * payload_index) - idx;
149
                    set_bit_from_byte!(
150
                        acceptance_code,
151
                        acceptance_mask,
152
                        payload[payload_index][idx],
153
                        shift
154
                    );
155
                    idx += 1;
156
                }
157
                payload_index += 1;
158
            }
159
        }
160

            
161
3
        Self {
162
            raw: code_mask_to_register_array(acceptance_code, acceptance_mask),
163
        }
164
3
    }
165

            
166
    /// The masks indicate which bits of the code the filter should match
167
    /// against. Set bits in the mask indicate that the corresponding bit in
168
    /// the code should match.
169
    ///
170
    ///
171
    /// # Examples
172
    ///
173
    /// A filter that matches every standard id that is even, is not an rtr
174
    /// frame, with any bytes for the first two payload bytes.
175
    /// ```rust, ignore
176
    /// let filter = twai::filter::SingleStandardFilter::new_from_code_mask(
177
    ///     StandardId::new(0x000)?,
178
    ///     StandardId::new(0x001)?,
179
    ///     false,
180
    ///     true,
181
    ///     [0x00, 0x00],
182
    /// );
183
    /// ```
184
    pub fn new_from_code_mask(
185
        id_code: StandardId,
186
        id_mask: StandardId,
187
        rtr_code: bool,
188
        rtr_mask: bool,
189
        payload_code: [u8; 2],
190
        payload_mask: [u8; 2],
191
    ) -> Self {
192
        // The bit values we desire to match against. This determines whether we want a
193
        // set bit (1) or a reset bit (0).
194
        let mut acceptance_code: u32 = 0;
195
        // The acceptance mask, set bits (1) mean we care about the exact value of the
196
        // corresponding bit in the code, reset bits (0) mean the bit could be any
197
        // value.
198
        let mut acceptance_mask: u32 = 0;
199

            
200
        // Pack the id into the full layout.
201
        acceptance_code |= (id_code.as_raw() as u32) << 21;
202
        acceptance_mask |= (id_mask.as_raw() as u32) << 21;
203

            
204
        // Pack the RTR bit into the full layout.
205
        acceptance_code |= (rtr_code as u32) << 20;
206
        acceptance_mask |= (rtr_mask as u32) << 20;
207

            
208
        // Pack the payload bytes into the full layout.
209
        acceptance_code |= ((payload_code[0] as u32) << 8) | (payload_code[1] as u32);
210
        acceptance_mask |= ((payload_mask[0] as u32) << 8) | (payload_mask[1] as u32);
211

            
212
        Self {
213
            raw: code_mask_to_register_array(acceptance_code, acceptance_mask),
214
        }
215
    }
216
}
217

            
218
impl Filter for SingleStandardFilter {
219
    const FILTER_TYPE: FilterType = FilterType::Single;
220
    fn to_registers(&self) -> [u8; 8] {
221
        self.raw
222
    }
223
}
224

            
225
/// Warning: This is not a perfect filter. Standard IDs that match the bit
226
/// layout of this filter will also be accepted.
227
pub struct SingleExtendedFilter {
228
    raw: [u8; 8],
229
}
230

            
231
impl SingleExtendedFilter {
232
    /// Creates a new filter that matches against a single 29-bit extended id.
233
    ///
234
    /// The filter can match against the packet's id and the RTR bit.
235
    ///
236
    /// # Examples
237
    /// A filter matching any odd extended IDs, with any rtr value.
238
    /// ```rust, ignore
239
    /// const FILTER: twai::filter::SingleExtendedFilter =
240
    ///     twai::filter::SingleExtendedFilter::new(b"xxxxxxxxxxxxxxxxxxxxxxxxxxxx1", b"x");
241
    /// ```
242
    pub const fn new(id: &BitFilter<29>, rtr: &BitFilter<1>) -> Self {
243
        // The bit values we desire to match against. This determines whether we want a
244
        // set bit (1) or a reset bit (0).
245
        let mut acceptance_code: u32 = 0;
246
        // The acceptance mask, set bits (1) mean we care about the exact value of the
247
        // corresponding bit in the code, reset bits (0) mean the bit could be any
248
        // value.
249
        let mut acceptance_mask: u32 = 0;
250

            
251
        // Convert the id filter into the code and mask bits.
252
        {
253
            let mut idx = 0;
254
            while idx < 29 {
255
                let shift = 31 - idx;
256
                set_bit_from_byte!(acceptance_code, acceptance_mask, id[idx], shift);
257
                idx += 1;
258
            }
259
        }
260
        // Convert the RTR bit filter into the code and mask bits.
261
        {
262
            let shift = 2;
263
            set_bit_from_byte!(acceptance_code, acceptance_mask, rtr[0], shift);
264
        }
265

            
266
        Self {
267
            raw: code_mask_to_register_array(acceptance_code, acceptance_mask),
268
        }
269
    }
270
    /// The masks indicate which bits of the code the filter should match
271
    /// against. Set bits in the mask indicate that the corresponding bit in
272
    /// the code should match.
273
    pub fn new_from_code_mask(
274
        id_code: ExtendedId,
275
        id_mask: ExtendedId,
276
        rtr_code: bool,
277
        rtr_mask: bool,
278
    ) -> Self {
279
        // The bit values we desire to match against. This determines whether we want a
280
        // set bit (1) or a reset bit (0).
281
        let mut acceptance_code: u32 = 0;
282
        // The acceptance mask, set bits (1) mean we care about the exact value of the
283
        // corresponding bit in the code, reset bits (0) mean the bit could be any
284
        // value.
285
        let mut acceptance_mask: u32 = 0;
286

            
287
        // Pack the id into the full layout.
288
        acceptance_code |= id_code.as_raw() << 3;
289
        acceptance_mask |= id_mask.as_raw() << 3;
290

            
291
        // Pack the RTR bit into the full layout.
292
        acceptance_code |= (rtr_code as u32) << 2;
293
        acceptance_mask |= (rtr_mask as u32) << 2;
294

            
295
        Self {
296
            raw: code_mask_to_register_array(acceptance_code, acceptance_mask),
297
        }
298
    }
299
}
300

            
301
impl Filter for SingleExtendedFilter {
302
    const FILTER_TYPE: FilterType = FilterType::Single;
303
    fn to_registers(&self) -> [u8; 8] {
304
        self.raw
305
    }
306
}
307

            
308
/// A filter that matches against two standard 11-bit standard IDs.
309
///
310
/// The first filter part can match a packet's id, RTR bit, and the first byte
311
/// of the payload. The second filter part can match a packet's id and RTR bit.
312
///
313
/// Warning: This is not a perfect filter. Extended IDs that match the bit
314
/// layout of this filter will also be accepted.
315
pub struct DualStandardFilter {
316
    raw: [u8; 8],
317
}
318

            
319
impl DualStandardFilter {
320
    /// Creates a new filter that matches against two standard 11-bit standard IDs.
321
    ///
322
    /// The first filter part can match a packet's id, RTR bit, and the first
323
    /// byte of the payload. The second filter part can match a packet's id
324
    /// and RTR bit.
325
    ///
326
    /// # Examples
327
    /// A filter that matches any standard id that ends with a 00 or a 11, with
328
    /// any RTR, and with any payload on the first filter.
329
    /// ```rust, ignore
330
    /// const FILTER: twai::filter::DualStandardFilter = twai::filter::DualStandardFilter::new(
331
    ///     b"xxxxxxxxx00",
332
    ///     b"x",
333
    ///     b"xxxxxxxx",
334
    ///     b"xxxxxxxxx11",
335
    ///     b"x",
336
    /// );
337
    /// ```
338
    pub const fn new(
339
        first_id: &BitFilter<11>,
340
        first_rtr: &BitFilter<1>,
341
        first_payload: &BitFilter<8>,
342
        second_id: &BitFilter<11>,
343
        second_rtr: &BitFilter<1>,
344
    ) -> Self {
345
        // The bit values we desire to match against. This determines whether we want a
346
        // set bit (1) or a reset bit (0).
347
        let mut acceptance_code: u32 = 0;
348
        // The acceptance mask, set bits (1) mean we care about the exact value of the
349
        // corresponding bit in the code, reset bits (0) mean the bit could be any
350
        // value.
351
        let mut acceptance_mask: u32 = 0;
352

            
353
        // Convert the first id filter into the code and mask bits.
354
        {
355
            let mut idx = 0;
356
            while idx < 11 {
357
                let shift = 31 - idx;
358
                set_bit_from_byte!(acceptance_code, acceptance_mask, first_id[idx], shift);
359
                idx += 1;
360
            }
361
        }
362
        // Convert the first RTR bit filter into the code and mask bits.
363
        {
364
            let shift = 20;
365
            set_bit_from_byte!(acceptance_code, acceptance_mask, first_rtr[0], shift);
366
        }
367
        // Convert the first payload byte filter into the code and mask bits.
368
        {
369
            let mut idx = 0;
370
            while idx < 4 {
371
                let shift = 19 - idx;
372
                set_bit_from_byte!(acceptance_code, acceptance_mask, first_payload[idx], shift);
373
                idx += 1;
374
            }
375
            while idx < 8 {
376
                let shift = 3 + 4 - idx;
377
                set_bit_from_byte!(acceptance_code, acceptance_mask, first_payload[idx], shift);
378
                idx += 1;
379
            }
380
        }
381
        // Convert the second id filter into the code and mask bits.
382
        {
383
            let mut idx = 0;
384
            while idx < 11 {
385
                let shift = 15 - idx;
386
                set_bit_from_byte!(acceptance_code, acceptance_mask, second_id[idx], shift);
387
                idx += 1;
388
            }
389
        }
390
        // Convert the second RTR bit filter into the code and mask bits.
391
        {
392
            let shift = 4;
393
            set_bit_from_byte!(acceptance_code, acceptance_mask, second_rtr[0], shift);
394
        }
395

            
396
        Self {
397
            raw: code_mask_to_register_array(acceptance_code, acceptance_mask),
398
        }
399
    }
400
    /// The masks indicate which bits of the code the filter should match
401
    /// against. Set bits in the mask indicate that the corresponding bit in
402
    /// the code should match.
403
    #[expect(clippy::too_many_arguments)]
404
    pub fn new_from_code_mask(
405
        first_id_code: StandardId,
406
        first_id_mask: StandardId,
407
        first_rtr_code: bool,
408
        first_rtr_mask: bool,
409
        first_payload_code: u8,
410
        first_payload_mask: u8,
411
        second_id_code: StandardId,
412
        second_id_mask: StandardId,
413
        second_rtr_code: bool,
414
        second_rtr_mask: bool,
415
    ) -> Self {
416
        // The bit values we desire to match against. This determines whether we want a
417
        // set bit (1) or a reset bit (0).
418
        let mut acceptance_code: u32 = 0;
419
        // The acceptance mask, set bits (1) mean we care about the exact value of the
420
        // corresponding bit in the code, reset bits (0) mean the bit could be any
421
        // value.
422
        let mut acceptance_mask: u32 = 0;
423

            
424
        // Pack the first id into the full layout.
425
        acceptance_code |= (first_id_code.as_raw() as u32) << 21;
426
        acceptance_mask |= (first_id_mask.as_raw() as u32) << 21;
427

            
428
        // Pack the RTR bit into the full layout.
429
        acceptance_code |= (first_rtr_code as u32) << 20;
430
        acceptance_mask |= (first_rtr_mask as u32) << 20;
431

            
432
        // Pack the first payload into the full layout.
433
        acceptance_code |= ((first_payload_code & 0xF0) as u32) << 12;
434
        acceptance_mask |= ((first_payload_mask & 0xF0) as u32) << 12;
435
        acceptance_code |= (first_payload_code & 0x0F) as u32;
436
        acceptance_mask |= (first_payload_mask & 0x0F) as u32;
437

            
438
        // Pack the second id into the full layout.
439
        acceptance_code |= (second_id_code.as_raw() as u32) << 5;
440
        acceptance_mask |= (second_id_mask.as_raw() as u32) << 5;
441

            
442
        // Pack the second RTR bit into the full layout.
443
        acceptance_code |= (second_rtr_code as u32) << 4;
444
        acceptance_mask |= (second_rtr_mask as u32) << 4;
445

            
446
        Self {
447
            raw: code_mask_to_register_array(acceptance_code, acceptance_mask),
448
        }
449
    }
450
}
451

            
452
impl Filter for DualStandardFilter {
453
    const FILTER_TYPE: FilterType = FilterType::Dual;
454
    fn to_registers(&self) -> [u8; 8] {
455
        self.raw
456
    }
457
}
458

            
459
/// Warning: This is not a perfect filter. Standard IDs that match the bit
460
/// layout of this filter will also be accepted.
461
///
462
/// NOTE: The dual extended id acceptance filters can only match "the first 16
463
/// bits of the 29-bit ID".
464
pub struct DualExtendedFilter {
465
    raw: [u8; 8],
466
}
467

            
468
impl DualExtendedFilter {
469
    /// Creates a new filter that matches the first 16 bits of two 29-bit extended
470
    /// IDs.
471
    ///
472
    /// # Examples
473
    /// A filter that matches IDs with 4 bits either set or reset in the higher
474
    /// part of the id. For example this id matches: 0x000f000f, 0x000f000a,
475
    /// 0x0000000a, 0x0000000b.
476
    /// But it does not match: 0x000a000a
477
    /// ```rust, ignore
478
    /// const FILTER: twai::filter::DualExtendedFilter =
479
    ///     twai::filter::DualExtendedFilter::new([b"xxxxxxxxx0000xxx", b"xxxxxxxxx1111xxx"]);
480
    /// ```
481
    pub const fn new(ids: [&BitFilter<16>; 2]) -> Self {
482
        // The bit values we desire to match against. This determines whether we want a
483
        // set bit (1) or a reset bit (0).
484
        let mut acceptance_code: u32 = 0;
485
        // The acceptance mask, set bits (1) mean we care about the exact value of the
486
        // corresponding bit in the code, reset bits (0) mean the bit could be any
487
        // value.
488
        let mut acceptance_mask: u32 = 0;
489

            
490
        // Convert the id filters into the code and mask bits.
491
        {
492
            let mut filter_idx = 0;
493
            while filter_idx < 2 {
494
                let mut idx = 0;
495
                while idx < 16 {
496
                    let shift = 31 - (filter_idx * 16) - idx;
497
                    set_bit_from_byte!(
498
                        acceptance_code,
499
                        acceptance_mask,
500
                        ids[filter_idx][idx],
501
                        shift
502
                    );
503
                    idx += 1;
504
                }
505
                filter_idx += 1;
506
            }
507
        }
508

            
509
        Self {
510
            raw: code_mask_to_register_array(acceptance_code, acceptance_mask),
511
        }
512
    }
513
    /// Creates a new filter matching the first 16 bits of two 29-bit IDs.
514
    ///
515
    /// The masks indicate which bits of the code the filter should match
516
    /// against. Set bits in the mask indicate that the corresponding bit in
517
    /// the code should match.
518
    pub fn new_from_code_mask(ids_code: [u16; 2], ids_mask: [u16; 2]) -> Self {
519
        // The bit values we desire to match against. This determines whether we want a
520
        // set bit (1) or a reset bit (0).
521
        let mut acceptance_code: u32 = 0;
522
        // The acceptance mask, set bits (1) mean we care about the exact value of the
523
        // corresponding bit in the code, reset bits (0) mean the bit could be any
524
        // value.
525
        let mut acceptance_mask: u32 = 0;
526

            
527
        // Pack the first partial id into the full layout.
528
        acceptance_code |= (ids_code[0] as u32) << 16;
529
        acceptance_mask |= (ids_mask[0] as u32) << 16;
530

            
531
        // Pack the second partial id into the full layout.
532
        acceptance_code |= ids_code[1] as u32;
533
        acceptance_mask |= ids_mask[1] as u32;
534

            
535
        Self {
536
            raw: code_mask_to_register_array(acceptance_code, acceptance_mask),
537
        }
538
    }
539
}
540

            
541
impl Filter for DualExtendedFilter {
542
    const FILTER_TYPE: FilterType = FilterType::Dual;
543
    fn to_registers(&self) -> [u8; 8] {
544
        self.raw
545
    }
546
}