demo3/demo/hamming.c
2024-11-30 10:15:30 +08:00

109 lines
3.3 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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; // 检测到多位错误
}