sdmmc_core/crc/crc7.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
const CRC7_POLY: u8 = 0b1000_1001;
const CRC7_MASK: u8 = 0x7f;
/// Represents the 7-bit CRC used to protect SD memory card commands, responses, and data transfer messages.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Crc7(u8);
impl Crc7 {
/// Creates a new [Crc7].
pub const fn new() -> Self {
Self(0)
}
/// Gets the inner representation of the [Crc7] bits.
pub const fn bits(&self) -> u8 {
self.0
}
/// Converts a [`u8`] into a [Crc7].
pub const fn from_bits(val: u8) -> Self {
Self(val & CRC7_MASK)
}
/// Calculates the CRC7 value according the algorithm defined in the simplified physical specification.
/// See section "4.5 Cyclic Redundancy Code" for details.
///
/// ```no_build,no_run
/// Generator Polynomial: G(x) = x^7 + x^3 + 1
/// M(x) = (first bit) * x^n + (second bit) * x^n-1 + ... + (last bit) * x^0
/// CRC[6..0] = Remainder[(M(x) * x^7) / G(x)]
/// ```
///
/// Implementation based on the lookup table algorithm from: [hazelnusse/crc7](https://github.com/hazelnusse/crc7).
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)
}
// Calculates the CRC-7 lookup value based on the `crc` value.
#[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
}
// Used to clear leading bit from CRC value.
//
// If the leading bit is set, adds the CRC-7 polynomial to correct the value.
#[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);
});
}
}