109 lines
3.3 KiB
C
109 lines
3.3 KiB
C
#include "hamming.h"
|
||
|
||
/**
|
||
* @brief 计算一个字节中1的个数
|
||
* @param byte 输入字节
|
||
* @return 返回字节中1的个数
|
||
*/
|
||
static inline int countOnes(unsigned char byte) {
|
||
static const unsigned char ones[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
|
||
return ones[byte & 0x0F] + ones[byte >> 4];
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief 计算汉明码的校验位
|
||
* @param data 输入数据数组
|
||
* @param size 数据大小
|
||
* @param parity 输出的校验位数组(3字节)
|
||
* @note 校验位计算包括:
|
||
* - 对每个数据位进行异或运算生成校验位
|
||
* - 最后一个校验字节的最高位用于总体奇偶校验
|
||
*/
|
||
void calculateParity(const unsigned char *data, int size, unsigned char *parity) {
|
||
// 初始化校验位数组
|
||
memset(parity, 0, PARITY_BYTES);
|
||
int totalOnes = 0;
|
||
|
||
// 对每个数据字节
|
||
for(int i = 0; i < size; i++) {
|
||
unsigned char byte = data[i];
|
||
totalOnes += countOnes(byte);
|
||
|
||
// 对字节中的每一位
|
||
for(int j = 0; j < 8; j++) {
|
||
if(byte & (1 << j)) {
|
||
// 计算该位在整个数据中的位置
|
||
int bitPos = i * 8 + j;
|
||
|
||
// 更新相应的校验位
|
||
for(int k = 0; k < 20; k++) {
|
||
if(bitPos & (1 << k)) {
|
||
if(k < 8)
|
||
parity[0] ^= (1 << k);
|
||
else if(k < 16)
|
||
parity[1] ^= (1 << (k - 8));
|
||
else
|
||
parity[2] ^= (1 << (k - 16));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加总体奇偶校验
|
||
if(totalOnes % 2) {
|
||
parity[2] |= 0x08; // 设置最高位
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 检测并纠正数据中的错误
|
||
* @param data 需要检查的数据
|
||
* @param size 数据大小
|
||
* @param parity 原始校验位
|
||
* @return 返回检测结果:
|
||
* 0 - 无错误
|
||
* 1 - 检测到并纠正了单比特错误
|
||
* -1 - 校验位错误
|
||
* -2 - 检测到多位错误
|
||
*/
|
||
int detectAndCorrect(unsigned char *data, int size, const unsigned char *parity) {
|
||
unsigned char currentParity[PARITY_BYTES];
|
||
calculateParity(data, size, currentParity);
|
||
// printf("parity: %02X %02X %02X\n", parity[2], parity[1], parity[0]);
|
||
// printf("currentParity: %02X %02X %02X\n", currentParity[2], currentParity[1], currentParity[0]);
|
||
|
||
// 计算syndrome
|
||
unsigned int syndrome = 0;
|
||
syndrome |= (currentParity[0] ^ parity[0]);
|
||
syndrome |= (currentParity[1] ^ parity[1]) << 8;
|
||
syndrome |= ((currentParity[2] ^ parity[2]) & 0x07) << 16;
|
||
|
||
// 检查总体奇偶校验
|
||
int parityError = ((currentParity[2] ^ parity[2]) & 0x08) ? 1 : 0;
|
||
|
||
if(syndrome == 0) {
|
||
if(parityError) {
|
||
return -2; // 检测到多位错误
|
||
}
|
||
return 0; // 无错误
|
||
}
|
||
|
||
if(!parityError) {
|
||
return -1; // 校验位错误(syndrome不为0但奇偶校验正确)
|
||
}
|
||
|
||
// 单比特错误
|
||
int bitPos = syndrome;
|
||
int bytePos = bitPos / 8;
|
||
int bitInByte = bitPos % 8;
|
||
|
||
if(bytePos < size) {
|
||
data[bytePos] ^= (1 << bitInByte);
|
||
// printf("纠正位置:字节 %d,位 %d\n", bytePos, bitInByte);
|
||
return 1;
|
||
}
|
||
|
||
return -2; // 检测到多位错误
|
||
} |