#![deny(missing_docs)]
use crate::pac::CRC;
use crate::rcc::{Enable, Rcc};
use core::hash::Hasher;
pub trait CrcExt {
fn constrain(self, rcc: &mut Rcc) -> Config;
}
impl CrcExt for CRC {
fn constrain(self, rcc: &mut Rcc) -> Config {
CRC::enable(rcc);
Config {
initial_value: 0xffff_ffff,
polynomial: Polynomial::L32(0x04c1_1db7),
input_bit_reversal: None,
output_bit_reversal: false,
}
}
}
pub enum Polynomial {
L7(u8),
L8(u8),
L16(u16),
L32(u32),
}
pub enum BitReversal {
ByByte,
ByHalfWord,
ByWord,
}
pub struct Config {
initial_value: u32,
polynomial: Polynomial,
input_bit_reversal: Option<BitReversal>,
output_bit_reversal: bool,
}
impl Config {
pub fn initial_value(mut self, init: u32) -> Self {
self.initial_value = init;
self
}
pub fn polynomial(mut self, polynomial: Polynomial) -> Self {
self.polynomial = polynomial;
self
}
pub fn input_bit_reversal(mut self, rev: BitReversal) -> Self {
self.input_bit_reversal = Some(rev);
self
}
pub fn output_bit_reversal(mut self, rev: bool) -> Self {
self.output_bit_reversal = rev;
self
}
pub fn freeze(self) -> Crc {
let crc = unsafe { &(*CRC::ptr()) };
let (poly, poly_bits, init) = match self.polynomial {
Polynomial::L7(val) => ((val & 0x7f) as u32, 0b11, self.initial_value & 0x7f),
Polynomial::L8(val) => (val as u32, 0b10, self.initial_value & 0xff),
Polynomial::L16(val) => (val as u32, 0b01, self.initial_value & 0xffff),
Polynomial::L32(val) => (val, 0b00, self.initial_value),
};
let in_rev_bits = match self.input_bit_reversal {
None => 0b00,
Some(BitReversal::ByByte) => 0b01,
Some(BitReversal::ByHalfWord) => 0b10,
Some(BitReversal::ByWord) => 0b11,
};
crc.init.write(|w| w.bits(init));
crc.pol.write(|w| w.bits(poly));
crc.cr.write(|w| {
w.rev_in()
.bits(in_rev_bits)
.polysize()
.bits(poly_bits)
.reset()
.set_bit();
if self.output_bit_reversal {
w.rev_out().set_bit()
} else {
w.rev_out().clear_bit()
}
});
Crc {}
}
}
pub struct Crc {}
impl Crc {
#[inline]
pub fn reset(&mut self) {
let crc = unsafe { &(*CRC::ptr()) };
crc.cr.modify(|_, w| w.reset().set_bit());
}
#[inline]
pub fn reset_with_inital_value(&mut self, initial_value: u32) {
let crc = unsafe { &(*CRC::ptr()) };
crc.init.write(|w| w.bits(initial_value));
crc.cr.modify(|_, w| w.reset().set_bit());
}
#[inline]
pub fn feed(&mut self, data: &[u8]) {
let crc = unsafe { &(*CRC::ptr()) };
for &byte in data {
crc.dr8().write(|w| w.bits(byte));
}
}
#[inline]
pub fn result(&mut self) -> u32 {
let ret = self.peek_result();
self.reset();
ret
}
#[inline]
pub fn peek_result(&self) -> u32 {
let crc = unsafe { &(*CRC::ptr()) };
crc.dr().read().bits()
}
}
impl Hasher for Crc {
#[inline]
fn finish(&self) -> u64 {
self.peek_result() as u64
}
#[inline]
fn write(&mut self, data: &[u8]) {
self.feed(data);
}
}