diff --git a/lib-bms-protocol/src/types.rs b/lib-bms-protocol/src/types.rs index c9c325e..48df79a 100644 --- a/lib-bms-protocol/src/types.rs +++ b/lib-bms-protocol/src/types.rs @@ -46,12 +46,16 @@ const U26_VALUE_MASK: u32 = 0xFFFFFFc0; const U26_MAX_VALUE: u32 = 0x03FFFFFF; +const U26_HEMMING_MASK: u32 = 0x0000003e; +#[derive(Debug, PartialEq)] pub enum U26Error { + InvalidCodeWord, + IncorrectibleError, Overflow, } -#[derive(Debug)] +#[derive(Debug, PartialEq)] /// this type is used for storing data on memory devices the concern here is mostly protecting against memory corruption /// du to faulty memory cells. Here one bit errors are the most probabl cause of errors so this types uses a build in /// hemming code for one mit error correction. @@ -68,6 +72,38 @@ impl Stored_U26 { let hemming_code = calc_hemming(value); Self((value << 6) | ((hemming_code & 0x3F) << 1) as u32) } + + pub fn to_be_bytes(&self) -> [u8; 4] { + self.0.to_be_bytes() + } + + pub fn from_be_bytes(bytes: [u8;4]) -> Result { + let raw_u32 = u32::from_be_bytes(bytes); + // the last bit is expetced to be 0 + if raw_u32 & 0x1 != 0x0 { + return Err(U26Error::InvalidCodeWord); + } + let value = (raw_u32 & U26_VALUE_MASK) >> 6; + let hemming = ((raw_u32 & U26_HEMMING_MASK) >> 1) as u8; + match check_hemming(value, hemming) { + Ok(()) => Ok( + Stored_U26(raw_u32) + ), + Err(correction_data) => { + let (dc, hc) = correction_data.calc_correction_data(); + if check_hemming(value ^ dc, hemming ^ hc).is_err() { + // this case will not occur in our case because + // or codeword length corresponds to 31 and thus a perfect hemming + // code, flipping the correct bit will always produce a valid + // codeword even though the data was not the orginal stored data, + // to secure against this a crc is required + Err(U26Error::IncorrectibleError) + } else { + Ok(Self::new(value ^ dc)) + } + }, + } + } } impl From for u32 { @@ -276,7 +312,9 @@ pub fn check_hemming(data: u32, hemming: u8) -> Result<(), HemmingCorrectionValu mod base_type_tests { use std::println; - use super::{calc_hemming, check_hemming, U26_MAX_VALUE}; + use crate::types::U26Error; + + use super::{calc_hemming, check_hemming, Stored_U26, U26_MAX_VALUE}; #[test] fn hemming_code_generation() { @@ -345,12 +383,12 @@ mod base_type_tests { } #[test] - fn hemming_dual_bit_error_detection() { - let data = 0x123456; - let hemming = calc_hemming(data); - let bit_error = 0x101; - let correction = check_hemming(data ^ bit_error, hemming).unwrap_err(); - let (dc, hc) = correction.calc_correction_data(); - assert!(check_hemming(data ^ dc, hemming ^ hc).is_err()) + fn stored_u26_to_from_bytes() { + let data: Stored_U26 = 0x123456.try_into().unwrap(); + let mut bytes = data.to_be_bytes(); + assert_eq!(Stored_U26::from_be_bytes(bytes).unwrap(), data); + // introduce 1 bit error + bytes[2] = bytes[2] ^ 0x01; + assert_eq!(Stored_U26::from_be_bytes(bytes).unwrap(), data); } }