File
Blob: firmware/vendor/str0m/src/util/bit_pattern.rs
| 1 | /// One byte bit pattern to allow matching against specific bits. |
| 2 | #[derive(Copy, Clone)] |
| 3 | pub(crate) struct BitPattern { |
| 4 | mask: u8, |
| 5 | masked_value: u8, |
| 6 | } |
| 7 | |
| 8 | impl BitPattern { |
| 9 | pub(crate) fn matches(&self, profile_iop: u8) -> bool { |
| 10 | ((profile_iop ^ self.masked_value) & self.mask) == 0x0 |
| 11 | } |
| 12 | |
| 13 | /// Create a bit pattern. Use `1` for bits that must be set, `0` for bits that must not be |
| 14 | /// set, and `x` for bits that can take any value. |
| 15 | /// |
| 16 | /// Panics if any other byte values than ASCII `1`, `0`, or `x` is used. |
| 17 | pub(crate) const fn new(pattern: [u8; 8]) -> Self { |
| 18 | const fn bit_to_mask_bit(pattern: [u8; 8], i: usize) -> u8 { |
| 19 | let bit = pattern[7 - i]; |
| 20 | match bit { |
| 21 | b'1' | b'0' => 0x1 << i, |
| 22 | b'x' => 0x0 << i, |
| 23 | _ => panic!("Invalid bit pattern in IOPPattern only ASCII 1, 0, and x are allowed"), |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | const fn to_mask(pattern: [u8; 8]) -> u8 { |
| 28 | bit_to_mask_bit(pattern, 7) |
| 29 | | bit_to_mask_bit(pattern, 6) |
| 30 | | bit_to_mask_bit(pattern, 5) |
| 31 | | bit_to_mask_bit(pattern, 4) |
| 32 | | bit_to_mask_bit(pattern, 3) |
| 33 | | bit_to_mask_bit(pattern, 2) |
| 34 | | bit_to_mask_bit(pattern, 1) |
| 35 | | bit_to_mask_bit(pattern, 0) |
| 36 | } |
| 37 | |
| 38 | const fn bit_to_mask_value_bit(pattern: [u8; 8], i: usize) -> u8 { |
| 39 | let bit = pattern[7 - i]; |
| 40 | match bit { |
| 41 | b'1' => 0x1 << i, |
| 42 | b'x' | b'0' => 0x0 << i, |
| 43 | _ => panic!("Invalid bit pattern in IOPPattern only ASCII 1, 0, and x are allowed"), |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | const fn to_mask_value(pattern: [u8; 8]) -> u8 { |
| 48 | bit_to_mask_value_bit(pattern, 7) |
| 49 | | bit_to_mask_value_bit(pattern, 6) |
| 50 | | bit_to_mask_value_bit(pattern, 5) |
| 51 | | bit_to_mask_value_bit(pattern, 4) |
| 52 | | bit_to_mask_value_bit(pattern, 3) |
| 53 | | bit_to_mask_value_bit(pattern, 2) |
| 54 | | bit_to_mask_value_bit(pattern, 1) |
| 55 | | bit_to_mask_value_bit(pattern, 0) |
| 56 | } |
| 57 | let mask = to_mask(pattern); |
| 58 | let masked_value = to_mask_value(pattern); |
| 59 | |
| 60 | Self { mask, masked_value } |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | #[cfg(test)] |
| 65 | mod test { |
| 66 | use super::*; |
| 67 | |
| 68 | #[test] |
| 69 | fn test_iop_pattern_matching() { |
| 70 | let all_any = BitPattern::new(*b"xxxxxxxx"); |
| 71 | for x in 0..255 { |
| 72 | assert!(all_any.matches(x)); |
| 73 | } |
| 74 | |
| 75 | let stripes = BitPattern::new(*b"10101010"); |
| 76 | assert!(stripes.matches(0b1010_1010)); |
| 77 | assert!(!stripes.matches(0b1011_1010)); |
| 78 | |
| 79 | let inverse_stripes = BitPattern::new(*b"01010101"); |
| 80 | assert!(inverse_stripes.matches(0b0101_0101)); |
| 81 | assert!(!inverse_stripes.matches(0b0111_0001)); |
| 82 | |
| 83 | let high_bits = BitPattern::new(*b"1101xxxx"); |
| 84 | assert!(high_bits.matches(0b1101_0101)); |
| 85 | assert!(!high_bits.matches(0b1001_0101)); |
| 86 | |
| 87 | let mid_bits = BitPattern::new(*b"xx0110xx"); |
| 88 | assert!(mid_bits.matches(0b0101_1001)); |
| 89 | assert!(!mid_bits.matches(0b1000_1001)); |
| 90 | |
| 91 | let only_ones = BitPattern::new(*b"11111111"); |
| 92 | assert!(only_ones.matches(0b1111_1111)); |
| 93 | assert!(!only_ones.matches(0b1110_1111)); |
| 94 | |
| 95 | let only_zeros = BitPattern::new(*b"00000000"); |
| 96 | assert!(only_zeros.matches(0b0000_0000)); |
| 97 | assert!(!only_zeros.matches(0b0000_0010)); |
| 98 | |
| 99 | let mixed_pattern = BitPattern::new(*b"1x0x1x01"); |
| 100 | assert!(mixed_pattern.matches(0b11011001)); |
| 101 | assert!(!mixed_pattern.matches(0b11011011)); |
| 102 | |
| 103 | let complex_pattern = BitPattern::new(*b"1xx01x0x"); |
| 104 | assert!(complex_pattern.matches(0b10001001)); |
| 105 | assert!(!complex_pattern.matches(0b10101010)); |
| 106 | } |
| 107 | } |