1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/ecc/hamming256.c
2021-08-13 19:50:38 +02:00

318 lines
10 KiB
C

/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/**
* @file
*
* Implementation of the hamming code functions.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <stdint.h>
#define ENABLE_DEBUG 0
#include "debug.h"
#include "ecc/hamming256.h"
#include "bitarithm.h"
/*----------------------------------------------------------------------------
* Internal function
*----------------------------------------------------------------------------*/
/**
* @brief Counts and return the number of bits set to '1' in the given hamming code.
* @param code Hamming code.
*/
static uint8_t count_bits_in_code256(uint8_t *code)
{
return bitarithm_bits_set(code[0]) + bitarithm_bits_set(code[1]) + bitarithm_bits_set(code[2]);
}
/**
* @brief Calculates the 22-bit hamming code for a 256-bytes block of data.
* @param data Data buffer to calculate code for.
* @param code Pointer to a buffer where the code should be stored.
* @param padding Amount of zeroes to be appended to the data such that it sizes
* equals 256 bytes
*/
static void compute256(const uint8_t *data, uint8_t *code, uint8_t padding)
{
uint32_t i;
uint8_t columnSum = 0;
uint8_t evenLineCode = 0;
uint8_t oddLineCode = 0;
uint8_t evenColumnCode = 0;
uint8_t oddColumnCode = 0;
/*
* Xor all bytes together to get the column sum;
* At the same time, calculate the even and odd line codes
*/
for (i = 0; i < 256; i++) {
/* Allow non-multiples of 256 to be calculated by padding the data with zeroes */
uint8_t current = 0;
if (i < ((uint16_t)(256 - padding))) {
current = data[i];
}
columnSum ^= current;
/*
* If the xor sum of the byte is 0, then this byte has no incidence on
* the computed code; so check if the sum is 1.
*/
if ((bitarithm_bits_set(current) & 1) == 1) {
/*
* Parity groups are formed by forcing a particular index bit to 0
* (even) or 1 (odd).
* Example on one byte:
*
* bits (dec) 7 6 5 4 3 2 1 0
* (bin) 111 110 101 100 011 010 001 000
* '---'---'---'----------.
* |
* groups P4' ooooooooooooooo eeeeeeeeeeeeeee P4 |
* P2' ooooooo eeeeeee ooooooo eeeeeee P2 |
* P1' ooo eee ooo eee ooo eee ooo eee P1 |
* |
* We can see that: |
* - P4 -> bit 2 of index is 0 --------------------'
* - P4' -> bit 2 of index is 1.
* - P2 -> bit 1 of index if 0.
* - etc...
* We deduce that a bit position has an impact on all even Px if
* the log2(x)nth bit of its index is 0
* ex: log2(4) = 2, bit2 of the index must be 0 (-> 0 1 2 3)
* and on all odd Px' if the log2(x)nth bit of its index is 1
* ex: log2(2) = 1, bit1 of the index must be 1 (-> 0 1 4 5)
*
* As such, we calculate all the possible Px and Px' values at the
* same time in two variables, evenLineCode and oddLineCode, such as
* evenLineCode bits: P128 P64 P32 P16 P8 P4 P2 P1
* oddLineCode bits: P128' P64' P32' P16' P8' P4' P2' P1'
*/
evenLineCode ^= (255 - i);
oddLineCode ^= i;
}
}
/*
* At this point, we have the line parities, and the column sum. First, We
* must calculate the parity group values on the column sum.
*/
for (i = 0; i < 8; i++) {
if (columnSum & 1) {
evenColumnCode ^= (7 - i);
oddColumnCode ^= i;
}
columnSum >>= 1;
}
/*
* Now, we must interleave the parity values, to obtain the following layout:
* Code[0] = Line1
* Code[1] = Line2
* Code[2] = Column
* Line = Px' Px P(x-1)- P(x-1) ...
* Column = P4' P4 P2' P2 P1' P1 PadBit PadBit
*/
code[0] = 0;
code[1] = 0;
code[2] = 0;
for (i = 0; i < 4; i++) {
code[0] <<= 2;
code[1] <<= 2;
code[2] <<= 2;
/* Line 1 */
if ((oddLineCode & 0x80) != 0) {
code[0] |= 2;
}
if ((evenLineCode & 0x80) != 0) {
code[0] |= 1;
}
/* Line 2 */
if ((oddLineCode & 0x08) != 0) {
code[1] |= 2;
}
if ((evenLineCode & 0x08) != 0) {
code[1] |= 1;
}
/* Column */
if ((oddColumnCode & 0x04) != 0) {
code[2] |= 2;
}
if ((evenColumnCode & 0x04) != 0) {
code[2] |= 1;
}
oddLineCode <<= 1;
evenLineCode <<= 1;
oddColumnCode <<= 1;
evenColumnCode <<= 1;
}
/* Invert codes (linux compatibility) */
code[0] = (~(uint32_t)code[0]);
code[1] = (~(uint32_t)code[1]);
code[2] = (~(uint32_t)code[2]);
DEBUG("Computed code = %02X %02X %02X\n\r",
code[0], code[1], code[2]);
}
/**
* @brief Verifies and corrects a 256-bytes block of data using the given 22-bits
* hamming code.
*
* @param data Data buffer to check.
* @param originalCode Hamming code to use for verifying the data.
* @param padding Amount of zeroes to be appended to the data such that it sizes
* equals 256 bytes
*
* @return 0 if there is no error, otherwise returns a HAMMING_ERROR code.
*/
uint8_t verify256( uint8_t *pucData, const uint8_t *pucOriginalCode, uint8_t padding )
{
/* Calculate new code */
uint8_t computedCode[3];
uint8_t correctionCode[3];
compute256( pucData, computedCode, padding);
/* Xor both codes together */
correctionCode[0] = computedCode[0] ^ pucOriginalCode[0];
correctionCode[1] = computedCode[1] ^ pucOriginalCode[1];
correctionCode[2] = computedCode[2] ^ pucOriginalCode[2];
DEBUG( "Correction code = %02X %02X %02X\n\r", correctionCode[0], correctionCode[1], correctionCode[2] );
/* If all bytes are 0, there is no error */
if ((correctionCode[0] == 0) && (correctionCode[1] == 0) && (correctionCode[2] == 0)) {
return 0;
}
/* If there is a single bit error, there are 11 bits set to 1 */
if (count_bits_in_code256( correctionCode ) == 11) {
/* Get byte and bit indexes */
uint8_t byte;
uint8_t bit;
byte = correctionCode[0] & 0x80;
byte |= (correctionCode[0] << 1) & 0x40;
byte |= (correctionCode[0] << 2) & 0x20;
byte |= (correctionCode[0] << 3) & 0x10;
byte |= (correctionCode[1] >> 4) & 0x08;
byte |= (correctionCode[1] >> 3) & 0x04;
byte |= (correctionCode[1] >> 2) & 0x02;
byte |= (correctionCode[1] >> 1) & 0x01;
bit = (correctionCode[2] >> 5) & 0x04;
bit |= (correctionCode[2] >> 4) & 0x02;
bit |= (correctionCode[2] >> 3) & 0x01;
/* Correct bit */
DEBUG("Correcting byte #%d at bit %d\n\r", byte, bit );
pucData[byte] ^= (1 << bit);
return Hamming_ERROR_SINGLEBIT;
}
/* Check if ECC has been corrupted */
if (count_bits_in_code256( correctionCode ) == 1) {
return Hamming_ERROR_ECC;
}
/* Otherwise, this is a multi-bit error */
else {
return Hamming_ERROR_MULTIPLEBITS;
}
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void hamming_compute256x( const uint8_t *pucData, uint32_t dwSize, uint8_t *puCode )
{
DEBUG("hamming_compute256x()\n\r");
while (dwSize > 0) {
uint8_t padding = 0;
if (dwSize < 256) {
padding = 256 - dwSize;
}
compute256( pucData, puCode, padding );
pucData += 256;
puCode += 3;
dwSize -= (256 - padding);
}
}
uint8_t hamming_verify256x( uint8_t *pucData, uint32_t dwSize, const uint8_t *pucCode )
{
uint8_t result = 0;
DEBUG( "hamming_verify256x()\n\r" );
while (dwSize > 0) {
uint8_t error, padding = 0;
if (dwSize < 256) {
padding = 256 - dwSize;
}
error = verify256( pucData, pucCode, padding );
if (error == Hamming_ERROR_SINGLEBIT) {
result = Hamming_ERROR_SINGLEBIT;
}
else {
if (error) {
return error;
}
}
pucData += 256;
pucCode += 3;
dwSize -= (256 - padding);
}
return result;
}