testing hemming error correction logic
This commit is contained in:
@@ -163,7 +163,7 @@ fn calc_hemming(data_bits: u32) -> u8 {
|
|||||||
^ (data_bits >> 21)
|
^ (data_bits >> 21)
|
||||||
^ (data_bits >> 23)
|
^ (data_bits >> 23)
|
||||||
^ (data_bits >> 25))
|
^ (data_bits >> 25))
|
||||||
& 0x0001;
|
& 0x1;
|
||||||
let p2 = ((data_bits)
|
let p2 = ((data_bits)
|
||||||
^ (data_bits >> 2)
|
^ (data_bits >> 2)
|
||||||
^ (data_bits >> 3)
|
^ (data_bits >> 3)
|
||||||
@@ -179,7 +179,7 @@ fn calc_hemming(data_bits: u32) -> u8 {
|
|||||||
^ (data_bits >> 21)
|
^ (data_bits >> 21)
|
||||||
^ (data_bits >> 24)
|
^ (data_bits >> 24)
|
||||||
^ (data_bits >> 25))
|
^ (data_bits >> 25))
|
||||||
& 0x0001;
|
& 0x1;
|
||||||
let p3 = ((data_bits >> 1)
|
let p3 = ((data_bits >> 1)
|
||||||
^ (data_bits >> 2)
|
^ (data_bits >> 2)
|
||||||
^ (data_bits >> 3)
|
^ (data_bits >> 3)
|
||||||
@@ -195,7 +195,7 @@ fn calc_hemming(data_bits: u32) -> u8 {
|
|||||||
^ (data_bits >> 23)
|
^ (data_bits >> 23)
|
||||||
^ (data_bits >> 24)
|
^ (data_bits >> 24)
|
||||||
^ (data_bits >> 25))
|
^ (data_bits >> 25))
|
||||||
& 0x0001;
|
& 0x1;
|
||||||
let p4 = ((data_bits >> 4)
|
let p4 = ((data_bits >> 4)
|
||||||
^ (data_bits >> 5)
|
^ (data_bits >> 5)
|
||||||
^ (data_bits >> 6)
|
^ (data_bits >> 6)
|
||||||
@@ -211,7 +211,7 @@ fn calc_hemming(data_bits: u32) -> u8 {
|
|||||||
^ (data_bits >> 23)
|
^ (data_bits >> 23)
|
||||||
^ (data_bits >> 24)
|
^ (data_bits >> 24)
|
||||||
^ (data_bits >> 25))
|
^ (data_bits >> 25))
|
||||||
& 0x001;
|
& 0x1;
|
||||||
let p5 = ((data_bits >> 11)
|
let p5 = ((data_bits >> 11)
|
||||||
^ (data_bits >> 12)
|
^ (data_bits >> 12)
|
||||||
^ (data_bits >> 13)
|
^ (data_bits >> 13)
|
||||||
@@ -227,14 +227,56 @@ fn calc_hemming(data_bits: u32) -> u8 {
|
|||||||
^ (data_bits >> 23)
|
^ (data_bits >> 23)
|
||||||
^ (data_bits >> 24)
|
^ (data_bits >> 24)
|
||||||
^ (data_bits >> 25))
|
^ (data_bits >> 25))
|
||||||
& 0x0001;
|
& 0x1;
|
||||||
|
|
||||||
0x00 | (p1 as u8) << 0 | (p2 as u8) << 1 | (p3 as u8) << 2 | (p4 as u8) << 3 | (p5 as u8) << 5
|
0x00 | (p1 as u8) << 0 | (p2 as u8) << 1 | (p3 as u8) << 2 | (p4 as u8) << 3 | (p5 as u8) << 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// if the hemming code does not equal the expected stored hemming value it calculated
|
||||||
|
/// hemming code will indicate the position of the invalid bit, this type is used
|
||||||
|
/// to hold the logic to use this information for correcting the read data in case of
|
||||||
|
/// an error
|
||||||
|
pub struct HemmingCorrectionValue(u8);
|
||||||
|
|
||||||
|
impl HemmingCorrectionValue {
|
||||||
|
pub fn new(invalid_hemming: u8) -> Self {
|
||||||
|
HemmingCorrectionValue(invalid_hemming)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// calculate xor bit patterns to apply to the data or the stored hemming code
|
||||||
|
/// returns tuple -> (xor with data, xor with hemming code)
|
||||||
|
fn calc_correction_data(&self) -> (u32, u8) {
|
||||||
|
if [1, 2, 4, 8, 16].contains(&self.0) {
|
||||||
|
(0x00000000, 0x1 << self.0.ilog2())
|
||||||
|
} else {
|
||||||
|
if self.0 == 3 {
|
||||||
|
(0x1, 0x00)
|
||||||
|
} else if self.0 < 8 {
|
||||||
|
(0x1 << self.0 - 3 - 1, 0x00)
|
||||||
|
} else if self.0 < 16 {
|
||||||
|
(0x1 << self.0 - 4 - 1, 0x00)
|
||||||
|
} else {
|
||||||
|
(0x1 << self.0 - 5 - 1, 0x00)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check if hemming code matches the expected value for the provided data
|
||||||
|
pub fn check_hemming(data: u32, hemming: u8) -> Result<(), HemmingCorrectionValue> {
|
||||||
|
let h = calc_hemming(data);
|
||||||
|
if h == hemming {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(HemmingCorrectionValue::new(h^hemming))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod base_type_tests {
|
mod base_type_tests {
|
||||||
use super::calc_hemming;
|
use std::println;
|
||||||
|
|
||||||
|
use super::{calc_hemming, check_hemming, U26_MAX_VALUE};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hemming_code_generation() {
|
fn hemming_code_generation() {
|
||||||
@@ -242,5 +284,63 @@ mod base_type_tests {
|
|||||||
assert_eq!(calc_hemming(0x001), 0b00011);
|
assert_eq!(calc_hemming(0x001), 0b00011);
|
||||||
assert_eq!(calc_hemming(0x002), 0b00101);
|
assert_eq!(calc_hemming(0x002), 0b00101);
|
||||||
assert_eq!(calc_hemming(0x003), 0b00110);
|
assert_eq!(calc_hemming(0x003), 0b00110);
|
||||||
|
assert_eq!(calc_hemming(0x011), 0b01010);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hemming_failure() {
|
||||||
|
assert!(check_hemming(0x011, 0b00011).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hemming_correct_invalid_value() {
|
||||||
|
let invalid_data = 0x011;
|
||||||
|
let hemming = 0b00011;
|
||||||
|
let correction = check_hemming(invalid_data, hemming).unwrap_err();
|
||||||
|
let (data_correction, hemming_correction) = correction.calc_correction_data();
|
||||||
|
assert_eq!(hemming_correction, 0);
|
||||||
|
assert_eq!(data_correction, 0x10);
|
||||||
|
let valid_data = invalid_data ^ data_correction;
|
||||||
|
assert!(check_hemming(valid_data, hemming).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hemming_correct_invalid_hemming_code() {
|
||||||
|
let data = 0x001;
|
||||||
|
let invalid_hemming = 0b00001;
|
||||||
|
let correction = check_hemming(data, invalid_hemming).unwrap_err();
|
||||||
|
let (data_correction, hemming_correction) = correction.calc_correction_data();
|
||||||
|
assert_eq!(hemming_correction, 0b00010);
|
||||||
|
assert_eq!(data_correction, 0x00);
|
||||||
|
let valid_hemming = invalid_hemming ^ hemming_correction;
|
||||||
|
assert!(check_hemming(data, valid_hemming).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_onebit_value_correction_sweep() {
|
||||||
|
for val in 1..U26_MAX_VALUE {
|
||||||
|
let hemming = calc_hemming(val);
|
||||||
|
for i in 0..26 {
|
||||||
|
let bit_error = 0x1 << i;
|
||||||
|
let invalid_value = val ^ bit_error;
|
||||||
|
//println!("0x{val:x}, 0x{bit_error:x}, 0x{invalid_value:x}, 0b{hemming:b}, 0b{:b}", calc_hemming(invalid_value));
|
||||||
|
let correction = check_hemming(invalid_value, hemming).unwrap_err();
|
||||||
|
let (dc, _) = correction.calc_correction_data();
|
||||||
|
assert_eq!(invalid_value ^ dc, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_hemming_code_error_sweep() {
|
||||||
|
let data = 0x123456;
|
||||||
|
let hemming = calc_hemming(data);
|
||||||
|
for i in 0..5 {
|
||||||
|
let bit_error = 0x1 << i;
|
||||||
|
let invalid_hemming = hemming ^ bit_error;
|
||||||
|
let correction = check_hemming(data, invalid_hemming).unwrap_err();
|
||||||
|
let (_, hc) = correction.calc_correction_data();
|
||||||
|
assert_eq!(invalid_hemming^hc, hemming);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user