mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
318 lines
10 KiB
C
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;
|
|
}
|