const CRC7_POLY: u8 = 0b1000_1001;
const CRC7_MASK: u8 = 0x7f;
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Crc7(u8);
impl Crc7 {
pub const fn new() -> Self {
Self(0)
}
pub const fn bits(&self) -> u8 {
self.0
}
pub const fn from_bits(val: u8) -> Self {
Self(val & CRC7_MASK)
}
pub const fn calculate(data: &[u8]) -> Self {
let mut crc = 0;
let mut i = 0;
let len = data.len();
while i < len {
crc = Self::crc_table((crc << 1) ^ data[i]);
i = i.saturating_add(1);
}
Self(crc)
}
#[inline(always)]
const fn crc_table(mut crc: u8) -> u8 {
crc ^= Self::crc_rem(crc);
let mut j = 1;
while j < 8 {
crc = (crc << 1) ^ Self::crc_rem(crc << 1);
j += 1;
}
crc
}
#[inline(always)]
const fn crc_rem(val: u8) -> u8 {
if val & 0x80 != 0 { CRC7_POLY } else { 0 }
}
}
impl Default for Crc7 {
fn default() -> Self {
Self::new()
}
}
impl From<u8> for Crc7 {
fn from(val: u8) -> Self {
Self::from_bits(val)
}
}
impl From<Crc7> for u8 {
fn from(val: Crc7) -> Self {
val.bits()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_crc7() {
[0b1001010, 0b0101010, 0b0110011]
.map(Crc7::from)
.into_iter()
.zip([
[0b0100_0000, 0x00, 0x00, 0x00, 0x00],
[0b0101_0001, 0x00, 0x00, 0x00, 0x00],
[0b0001_0001, 0x00, 0x00, 0b0000_1001, 0x00],
])
.for_each(|(exp_crc, data)| {
assert_eq!(Crc7::calculate(data.as_ref()), exp_crc);
});
}
}