testing hemming error correction logic

This commit is contained in:
2026-03-22 10:08:57 +01:00
parent 4e810cf704
commit 87bd3abaca
+107 -7
View File
@@ -163,7 +163,7 @@ fn calc_hemming(data_bits: u32) -> u8 {
^ (data_bits >> 21)
^ (data_bits >> 23)
^ (data_bits >> 25))
& 0x0001;
& 0x1;
let p2 = ((data_bits)
^ (data_bits >> 2)
^ (data_bits >> 3)
@@ -179,7 +179,7 @@ fn calc_hemming(data_bits: u32) -> u8 {
^ (data_bits >> 21)
^ (data_bits >> 24)
^ (data_bits >> 25))
& 0x0001;
& 0x1;
let p3 = ((data_bits >> 1)
^ (data_bits >> 2)
^ (data_bits >> 3)
@@ -195,7 +195,7 @@ fn calc_hemming(data_bits: u32) -> u8 {
^ (data_bits >> 23)
^ (data_bits >> 24)
^ (data_bits >> 25))
& 0x0001;
& 0x1;
let p4 = ((data_bits >> 4)
^ (data_bits >> 5)
^ (data_bits >> 6)
@@ -211,7 +211,7 @@ fn calc_hemming(data_bits: u32) -> u8 {
^ (data_bits >> 23)
^ (data_bits >> 24)
^ (data_bits >> 25))
& 0x001;
& 0x1;
let p5 = ((data_bits >> 11)
^ (data_bits >> 12)
^ (data_bits >> 13)
@@ -227,14 +227,56 @@ fn calc_hemming(data_bits: u32) -> u8 {
^ (data_bits >> 23)
^ (data_bits >> 24)
^ (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)]
mod base_type_tests {
use super::calc_hemming;
use std::println;
use super::{calc_hemming, check_hemming, U26_MAX_VALUE};
#[test]
fn hemming_code_generation() {
@@ -242,5 +284,63 @@ mod base_type_tests {
assert_eq!(calc_hemming(0x001), 0b00011);
assert_eq!(calc_hemming(0x002), 0b00101);
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);
}
}
}