#[derive(Default)]
pub struct Crc7(u8);
#[derive(Default)]
pub struct Crc16(u16);
pub trait Crc: Default {
type Output;
fn add_byte(&mut self, byte: u8);
fn value(&self) -> Self::Output;
fn from_bytes(bytes: &[u8]) -> Self {
let mut crc = Self::default();
for &byte in bytes {
crc.add_byte(byte);
}
crc
}
}
impl Crc for Crc7 {
type Output = u8;
fn add_byte(&mut self, byte: u8) {
const G: u8 = 0x89;
self.0 ^= byte;
for _ in 0..8 {
if self.0 & 0x80 != 0 {
self.0 ^= G;
}
self.0 <<= 1;
}
}
fn value(&self) -> u8 {
self.0
}
}
impl Crc for Crc16 {
type Output = u16;
fn add_byte(&mut self, byte: u8) {
self.0 = self.0 >> 8 | self.0 << 8;
self.0 ^= u16::from(byte);
self.0 ^= (self.0 & 0xFF) >> 4;
self.0 ^= self.0 << 8 << 4;
self.0 ^= (self.0 & 0xFF) << 4 << 1;
}
fn value(&self) -> u16 {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cmd0() {
let mut crc = Crc7::default();
crc.add_byte(0x40);
crc.add_byte(0x0);
crc.add_byte(0x0);
crc.add_byte(0x0);
crc.add_byte(0x0);
assert_eq!(crc.value(), 0b10010100);
}
#[test]
fn cmd17() {
let mut crc = Crc7::default();
crc.add_byte(0x40 | 17);
crc.add_byte(0x0);
crc.add_byte(0x0);
crc.add_byte(0x0);
crc.add_byte(0x0);
assert_eq!(crc.value(), 0b01010100);
}
#[test]
fn cmd17_response() {
let mut crc = Crc7::default();
crc.add_byte(17);
crc.add_byte(0x0);
crc.add_byte(0x0);
crc.add_byte(0x9);
crc.add_byte(0x0);
assert_eq!(crc.value(), 0b01100110);
}
#[test]
fn all_ones() {
let mut crc = Crc16::default();
for _ in 0..512 {
crc.add_byte(0xFF);
}
assert_eq!(crc.value(), 0x7FA1);
}
}