Commit 9825b31a authored by Alessandro Rubini's avatar Alessandro Rubini

robustness/ from svn 1116

parent 460d5556
Hamming Code implements the Hamming coding scheme for all the lengths
from (7,4) up to (12000, 11986).
Cesar Prados, GSI
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This folder contain the Hamming code and Hamming Matrix
HAMMING MATRIX
generate a matrix for a hamming code, the size must be define in the source.
hamming_matrix.c
make matrix
HAMMIN CODE
encode and decode according to the rate define (m,n)
bit_counter
bit_operation
bit_operation
define
hamming
make
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
/*
* =====================================================================================
*
* Filename: bit_counter.c
*
* Description:
*
* Version: 1.0
* Created: 18.03.2011 21:44:37
* Revision: none
* Compiler: gcc
*
* Author: YOUR NAME (),
* Company:
*
* =====================================================================================
*/
#define TWO(c) (0x1u << (c))
#define MASK(c) (((unsigned int)(-1)) / (TWO(TWO(c)) + 1u))
#define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c))
int bitcount(unsigned int );
int bitcount_1(unsigned int );
int bitcount_2(int);
int bitcount_3(unsigned int);
int bitcount (unsigned int n) {
n = COUNT(n, 1);
n = COUNT(n, 1);
n = COUNT(n, 2);
n = COUNT(n, 3);
n = COUNT(n, 4);
/* n = COUNT(n, 5) ; for 64-bit integers */
return n ;
}
int bitcount_1 (unsigned int n) {
int count = 8 * sizeof(int);
n ^= (unsigned int) - 1;
while (n)
{
count--;
n &= (n - 1);
}
return count ;
}
int bitcount_2(int n)
{
unsigned int uCount;
uCount = n
- ((n >> 1) & 033333333333)
- ((n >> 2) & 011111111111);
return (int) (((uCount + (uCount >> 3))& 030707070707) % 63);
}
int bitcount_3(unsigned int v)
{
unsigned int c=0;
while(v > 0)
// for (c = 0; v; v >>= 1)
{
c++;
v = v >> 1;
}
return c;
}
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int
main ( int argc, char *argv[] )
{
int number_bits;
number_bits = bitcount_3(00000000000000);
printf("Numero de bits %d \n",number_bits);
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */
/*
* =====================================================================================
*
* Filename: bit_operation.c
*
* Description:
*
* Version: 1.0
* Created: 03/24/2011 03:20:53 PM
* Revision: none
* Compiler: gcc
*
* Author: Cesar Prados Boda (cp), c.prados@gsi.de
* Company: GSI
*
* =====================================================================================
*/
#include "bit_operation.h"
/*
* =====================================================================================
*
* Filename: bit_counter.c
*
* Description:
*
* Version: 1.0
* Created: 18.03.2011 21:44:37
* Revision: none
* Compiler: gcc
*
* Author: YOUR NAME (),
* Company:
*
* =====================================================================================
*/
int bitcount (unsigned int n) {
n = COUNT(n, 1);
n = COUNT(n, 1);
n = COUNT(n, 2);
n = COUNT(n, 3);
n = COUNT(n, 4);
/* n = COUNT(n, 5) ; for 64-bit integers */
return n ;
}
int bitcount_1 (unsigned int n) {
int count = 8 * sizeof(int);
n ^= (unsigned int) - 1;
while (n)
{
count--;
n &= (n - 1);
}
return count ;
}
int bitcount_2(int n)
{
unsigned int uCount;
uCount = n
- ((n >> 1) & 033333333333)
- ((n >> 2) & 011111111111);
return (int) (((uCount + (uCount >> 3))& 030707070707) % 63);
}
/*
* =====================================================================================
*
* Filename: bit_operation.h
*
* Description:
*
* Version: 1.0
* Created: 03/24/2011 03:16:43 PM
* Revision: none
* Compiler: gcc
*
* Author: Cesar Prados Boda (cp), c.prados@gsi.de
* Company: GSI
*
* =====================================================================================
*/
#include <ctype.h>
#define TWO(c) (0x1u << (c))
#define MASK(c) (((unsigned int)(-1)) / (TWO(TWO(c)) + 1u))
#define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c))
int bitcount(unsigned int );
int bitcount_1(unsigned int );
int bitcount_2(int);
/*
* =============================================================================
*
* Filename: define.h
*
* Description: define
*
* Version: 1.0
* Created: 03/24/2011 02:13:27 PM
* Revision: none
* Compiler: gcc
*
* Author: Cesar Prados Boda (cp), c.prados@gsi.de
* Company: GSI
*
* ==============================================================================*/
//#define PARIiTY_CHECK_1 0x55B // 10101011011
//#define PARITY_CHECK_2 0x66D // 11001101101
//#define PARITY_CHECK_4 0x78E // 11110001110
//#define PARITY_CHECK_8 0x7F0 // 11111110000
#define BITS_VECTOR 32
#define LOG_2_32 5
#define MOD_BIT_32 31
//parity check vectors for 64 bits words,
#define PARITY_CHECK_1 0xfdfff80e
#define PARITY_CHECK_2 0x56aaaff4
#define PARITY_CHECK_4 0x1222266f
#define PARITY_CHECK_8 0x202060e
#define PARITY_CHECK_16 0x2000600
#define PARITY_CHECK_32 0xfdffffff
#define PARITY_CHECK_64 0xfe000000
#define RATE_3_1 2
#define RATE_7_4 3
#define RATE_15_11 4
#define RATE_31_26 5
#define RATE_63_57 6
#define RATE_127_120 7
#define RATE_255_247 8
#define RATE_511_502 9
#define RATE_1023_1013 10
#define RATE_2047_2036 11
#define RATE_4095_4083 12
#define RATE_8191_8178 13
#define RATE_12000_11986 14
//TO DO define the rest of the legnth
#define FRAME_4 1
#define FRAME_12000 375
// In a payload of 1500
#define MAX_LENGTH_PAYLOAD 12000
#define READ_DFILTER 6
#define READ_DVECTOR 5
#define READ_FILTER 4
#define READ_VECTOR 3
#define CLEAN 2
#define WRITE 1
#define READ 0
#define ERROR 1
#define OK 0
// will be 21 encoded words with 7 parity check bits
// thus, 1344 bits are information 147 bit parity check bits
#define CODE_WORD 64
#define ENCODED_WORD 71
#define BIT_MASK 0x1
#define NUM_PARITY_BITS 4
#ifdef DBG
#define dbg(x, ...) fprintf(stderr, "(debug) " x, ##__VA_ARGS__)
#else
#define dbg(x, ...)
#endif
#include "hamming.h"
/* =================================================================
*
* Filename: hamming.c
*
* Description: main functions that creates a
*
* Version: 1.0 Created: 03/17/2011 07:12:29 PM Revision: none
* Compiler: gcc
*
* Author: César Prados Boda (cp), c.prados@gsi.de Company: GSI
*
* ==================================================================
*/
uint32_t *hamming_encoder (uint32_t *payload, uint16_t length)
{
uint8_t num_parity_bits;
hamming_vector *parity_check_vector;
hamming_vector *filter;
uint32_t *dPayload;
uint32_t i,j;
uint16_t vector_l;
uint16_t filter_n, numero_filt;
uint32_t distance2parityBits, parity_bit_pos;
uint8_t parity_bit;
uint16_t wordsINpayload; //words of 32 bits
uint32_t n_int,b_int, n_int_p;
dPayload = (uint32_t *)malloc(length*sizeof(uint32_t));
// number of parity bits for a given word of length l
num_parity_bits = hamming_init(0,READ);
dbg("NUM PARITY BITS %d \n",num_parity_bits);
// number of word in the vector
vector_l = vector_length(num_parity_bits);
// number of filter for a given rate
filter_n = filter_number(num_parity_bits);
// gets the parity vector
parity_check_vector = vector_generator(READ_VECTOR);
// gets the filter vector
filter = vector_generator(READ_FILTER);
// gets the length of the word of the payload
wordsINpayload = (LOG_2_32 >> length) +1;
for(i=0;i<num_parity_bits;i++)
{
dbg("***** Vector for Parity Bit %d ***** \n",i);
for(j=0;j<=(LOG_2_32 >> num_parity_bits);j++)
{
printf("%x",*((parity_check_vector+i)->pvector+j));
}
printf("\n");
}
dbg("%d parity bits for a given string %d bits \n ",num_parity_bits,length);
distance2parityBits = 0;
numero_filt=0;
/**************************************** PARITY BITS **********************************/
for(i=0;i<num_parity_bits;i++)
{
parity_bit=parity_check(payload, (parity_check_vector+i)->pvector,length,vector_l);
parity_bit_pos = (BIT_MASK << i);
//n_int = LOG_2_32 >> (BIT_MASK << i); // Int division of Number / 32
n_int_p = (int) parity_bit_pos / BITS_VECTOR;
*(dPayload + n_int_p) ^= (BIT_MASK & parity_bit) << (parity_bit_pos-1);//adds parity bit to the positions 0,1,2,4,8,16 etc...
/**************************************** FRAMES BITS **********************************/
if(i>0) // the bit 0 is out of this counts since the p2 is consecutive to p1 and doesn't
// follow the algorithm.
{
//calculates the distance between the current parity bit and the next
//to insert the original bits in the payload
distance2parityBits += (BIT_MASK << (i-1) )-1; // 0, 1, 3 etc
//n_int = LOG_2_32 >> distance2parityBits;
n_int = (int) distance2parityBits / BITS_VECTOR;
//b_int = distance2parityBits & MOD_BIT_32;
b_int = distance2parityBits % BITS_VECTOR;
for(j=0;(j<= n_int) && (numero_filt <= filter_n) ; j++)
{
dbg("Distance %d pvector %x payload %x \n",distance2parityBits,*(filter+numero_filt)->pvector+j,*(payload+j));
*(dPayload + n_int_p) |= ((*(payload+n_int) & *((filter+numero_filt)->pvector+j)) >> (b_int)) << (BIT_MASK << i);
numero_filt++;
}
}
}
/******************************************************************************************/
for(i=0;i<payload_length(num_parity_bits);i++)
{
printf("%d ", (*dPayload >> i ) & 0x1);
}
printf("\n");
for(i=0;i<payload_length(num_parity_bits);i++)
{
printf("%d ", (*payload >> i ) & 0x1);
}
printf("\n");
return dPayload;
} /* ----- end of function h amming_encoder ----- */
/*
*===================================================================
* parity_check
* input --> uint_8t pointer to payload, uint16_t parity word
* output --> uint8_t parity of the word
* ==================================================================
* */
uint8_t parity_check(uint32_t *payload,uint32_t *parity_check_mask, uint16_t length, uint16_t vector_l)
{
uint16_t parity=0;
uint32_t i;
// the payload is AND against the mask of the parity bit
// from this result the numbers of bits in the string is counted
// if it's ODD --> 1 parity bit
// if it's EVEN --> 0 parity bit
// the word is divided in code word of 64 bits
//payload
//
for(i=0; i <= vector_l; i++)
parity ^= (0x1 & bitcount(*(parity_check_mask+i) & (*payload+i))) ? 1 : 0;
// dbg("Result Parity %d \n",parity);
// dbg("FAST PARITY %d \n", parity);
return parity;
}
uint16_t find_num_parity_bits(uint16_t length_word)
{
uint16_t num_parity_bits = 0;
dbg("LENGTH %d \n", length_word);
if(length_word<=4)
num_parity_bits = 3;
else if(length_word<=11)
num_parity_bits = 4;
else if(length_word<=32)
num_parity_bits = 5;
else if(length_word<=64)
num_parity_bits = 6;
else if(length_word<=128)
num_parity_bits = 7;
else if(length_word<=336)
num_parity_bits = 8;
else if(length_word<=672)
num_parity_bits = 9;
else if(length_word<=1344)
num_parity_bits = 10;
else if(length_word<=2688)
num_parity_bits = 11;
else if(length_word<=5376)
num_parity_bits = 12;
else if(length_word<=10752)
num_parity_bits = 13;
else
num_parity_bits = 14;
return num_parity_bits;
}
/*
*===================================================================
* bitcout
* input
* output
* ==================================================================
* */
uint16_t bitcount(uint16_t n)
{
uint16_t uCount;
uCount = n
- ((n >> 1) & 033333333333)
- ((n >> 2) & 011111111111);
return (uint16_t) (((uCount + (uCount >> 3))& 030707070707) % 63);
}
/*
*===================================================================
* hamming_decoder
* input
* output
* ==================================================================
* */
uint32_t *hamming_decoder (uint32_t *payload, uint16_t length)
{
uint8_t num_parity_bits;
hamming_vector *parity_check_vector;
hamming_vector *filter;
uint32_t *ePayload;
uint32_t i,j;
uint16_t vector_l;
uint16_t filter_n, numero_filt;
uint32_t distance2parityBits, parity_bit_pos;
uint32_t parity_bit_rx,parity_bit;
uint32_t n_int,b_int,error_check;
ePayload = (uint32_t *)malloc(length*sizeof(uint32_t));
parity_bit = (uint32_t *)malloc(num_parity_bits*sizeof(uint32_t));
parity_bit_rx = (uint32_t *)malloc(num_parity_bits*sizeof(uint32_t));
// number of parity bits for a given word of length l
num_parity_bits = hamming_init(0,READ);
dbg("NUM PARITY BITS IN ENCODED PACKET %d \n",num_parity_bits);
// number of word in the vector
vector_l = vector_length(num_parity_bits);
// number of filter for a given rate
filter_n = filter_number(num_parity_bits);
// gets the parity vector
parity_check_vector = vector_generator(READ_VECTOR);
filter = vector_generator(READ_DFILTER);
numero_filt = 0;
parity_bit_rx = 0;
parity_bit = 0;
//******************************************PARITY BITS RECEIVED ***********************/
parity_bit_rx ^= *(payload) & BIT_MASK ;
for(i=1;i<num_parity_bits;i++)
{
n_int = (BIT_MASK << i) / BITS_VECTOR; //todo change to the faster bitwise operation
b_int = (BIT_MASK << i) & MOD_BIT_32; // 2,4,8 ...
parity_bit_rx ^= ((*(payload + n_int) & (BIT_MASK << b_int-1)) >> (b_int - 1) ) << i;
/**************************************** FRAMES BITS **********************************/
*(ePayload + n_int) |= ((*(payload+n_int) & *((filter+numero_filt)->pvector+n_int))>>(i+1));
// dbg("Filter %d i %d payload %x \n",*((filter+numero_filt)->pvector+n_int), (i+1),*(payload+n_int));
numero_filt++;
}
/********************************************PARITY BITS*********************/
for(i=0;i<num_parity_bits;i++)
{
parity_bit ^= parity_check(ePayload, (parity_check_vector+i)->pvector,length,vector_l) << i;
}
/******************************************** CHECK THE PARITY BITS AND FIX***********/
dbg("PARIT BIT RX %x PARITY BIT %x \n", parity_bit, parity_bit_rx);
error_check = parity_bit ^ parity_bit_rx;
dbg("CHECK %d \n",error_check);
if(error_check != 0)
{
n_int = error_check / BITS_VECTOR;
b_int = error_check & BITS_VECTOR;
// *(ePayload+n_int) ^= (BIT_MASK << b_int); // Fix the bit
}
for(i=0;i<payload_length(num_parity_bits);i++)
{
printf("%d ", (*ePayload >> i ) & 0x1);
}
printf("\n");
return ePayload;
} /* ----- end of function hamming_decoder ----- */
/*
* === FUNCTION ====================================================
* Name: vector genarator
* Description: creates the vectors of the hamming matrix
* and the filter for the encoded word.
* in ->
* code_rate -> value of the code rate
* multi_tag -> 1, write 0, value
* out -> NULL in case of error, and if in:
* WRITE hamming vector
* READ_VECTOR hamming vector
* FREE NULL
* READ_FILTER filter vector
* =================================================================
* */
hamming_vector *vector_generator(uint16_t multitag)
{
static hamming_vector *vector; //Pointer to array of pointer, that points to the parity check vector for encoding
static hamming_vector *filter; //Pointer to array of poiinter, that points to the filter vectors
static hamming_vector *dFilter; //Pointer to array of poiinter, that points to the filter vectors
static hamming_vector *dVector; //Pointer to array of pointer, that points to the parity check vector for decoding
uint16_t code_rate;
uint16_t vector_l;
uint16_t payload_l;
uint16_t filter_n;
uint16_t i;
// gets the code rate setted
code_rate = hamming_init(0,READ);
// gets the length of the parity check vector for a given code_rate
vector_l = vector_length(code_rate);
// gets the length of the maximum payload for a given code_rate
payload_l = payload_length(code_rate);
// gets the number of filter needed for a given code rate
filter_n = filter_number(code_rate);
if(multitag == WRITE) //if write
{
// allocation of code_rate PARITY CHECK VECTORS vector_l length
if( func_malloc(&vector,code_rate,vector_l))
return NULL;
//allocation of N filter vector
if(func_malloc(&filter,filter_n,vector_l)) //TODO calculate the length of the vector correctly
return NULL;
//allocation of N filter vector
if(func_malloc(&dFilter,filter_n,vector_l)) //TODO calculate the length of the vector correctly
return NULL;
//allocation of N filter vector
//allocation of N filter vector
if(func_malloc(&dVector,code_rate,vector_l)) //TODO calculate the length of the vector correctly
return NULL;
// The vector are calculated
if(generator(vector,payload_l))
{
dbg("Error Hamming Vector Encoder");
return NULL;
}
dbg("Vector generated \n");
// the filters are calculated
if(filter_generator(filter,filter_n))
{
dbg("Error Filter Vector");
return NULL;
}
// the filters are calculated
if(dFilter_generator(dFilter,filter_n))
{
dbg("Error Filter Vector");
return NULL;
}
// the vector for decoding is calculated
if(dGenerator(dVector,payload_l))
{
dbg("Error Hamming Vector Decoder");
return NULL;
}
return vector;
}else if(multitag == CLEAN) //if clean
{
dbg("Pointer Vector freeded");
free(vector);
return NULL;
}else if(multitag == READ_VECTOR)
{
return vector;
}else if(multitag == READ_FILTER)
{
return filter;
}else if(multitag == READ_DFILTER)
{
return dFilter;
}
else if(multitag == READ_DVECTOR)
{
return dVector;
}
return NULL;
}
/*
* === FUNCTION ====================================================
* Name: generator
* Description: creates the vector
* in -> hamming_vector *
*
* out -> hamming_vector *
* =================================================================
* */
uint16_t dFilter_generator(hamming_vector *filter,uint16_t filter_n )
{
uint32_t i, distance=1,distance_r, j,bit_shift;
uint16_t filter_number=0;
bool power_2;
for(i=3;(i<MAX_LENGTH_PAYLOAD)&&(filter_number<filter_n);i++)
{
power_2 = ((i & (i - 1)) == 0);
if(power_2)
{
filter_number++;
}
else
{
// position of the bit in uint32_t type
// bit_shift = (uint32_t)(i / BITS_VECTOR);
bit_shift = LOG_2_32 >> i;
// Modulo of a division in bitwise, X % Y == X & (Y-1)
distance_r = i & MOD_BIT_32;
*((filter+(filter_number))->pvector+bit_shift) ^= (BIT_MASK << distance_r-1);
}
}
for(i=0;i<filter_number;i++)
{
dbg("***** Vector for Filter Deco %d ***** \n",i);
for(j=0;j<= (int)(j/BITS_VECTOR) ;j++)
{
printf("%x",*((filter+i)->pvector+j));
}
printf("\n");
}
return OK;
}
/*
* === FUNCTION ====================================================
* Name: generator
* Description: creates the vector
* in -> hamming_vector *
*
* out -> hamming_vector *
* =================================================================
* */
uint16_t filter_generator(hamming_vector *filter,uint16_t filter_n )
{
uint32_t i, distance=1,distance_r, j,bit_shift;
uint16_t filter_number=0;
bool power_2;
for(i=3;(i<MAX_LENGTH_PAYLOAD)&&(filter_number<filter_n);i++)
{
power_2 = ((i & (i - 1)) == 0);
if(power_2)
{
filter_number++;
}
else
{
// position of the bit in uint32_t type
// bit_shift = (uint32_t)(i / BITS_VECTOR);
bit_shift = LOG_2_32 >> i;
// Modulo of a division in bitwise, X % Y == X & (Y-1)
distance_r = distance & MOD_BIT_32;
*((filter+(filter_number))->pvector+bit_shift) ^= (BIT_MASK << distance_r-1);
// *((filter+(filter_number))->pvector+bit_shift) ^= (BIT_MASK << (i-1));
distance++;
}
}
for(i=0;i<filter_number;i++)
{
dbg("***** Vector for Filter %d ***** \n",i);
for(j=0;j<= (int)(j/BITS_VECTOR) ;j++)
{
printf("%x",*((filter+i)->pvector+j));
}
printf("\n");
}
return OK;
}
/*
* * === FUNCTION ====================================================
* Name: generator
* Description: creates the vector to encode a word
* in -> hamming_vector *
*
* out -> hamming_vector *
* =================================================================
* */
uint16_t generator(hamming_vector *vector, uint16_t payload_l)
{
int index_matrix,position_bit;
int i,j,parity_bits=0;
int index_n,bit_shift;
bool power_2;
for(i=1 ; i<= payload_l ; i++)
{
index_matrix = 0;
//check if the bit position is power of 2, bitwise
power_2 = ((i & (i - 1)) == 0);
if(power_2)
{
// calculation of the first bit of the bit position
position_bit = ffs(i)-1;
for(j=1;j<=payload_l ;j++)
{
// if the bit position j has a bit in the bit position i is a
// parity check
if((0x1 & (j>>position_bit)) && !((j & (j - 1))==0))
{
// position of the bit in uint32_t type
bit_shift = index_matrix % BITS_VECTOR;
//bit_shift = index_matrix & MOD_BIT_32;
// position in the array of uint32_t words
index_n = (int)(index_matrix/BITS_VECTOR);
//index_n = LOG_2_32 >> index_matrix;
*((vector+parity_bits)->pvector+index_n) ^= (BIT_MASK << bit_shift);
index_matrix++; // keep the track of the position in the vector/matrix
}
else if(!((j & (j - 1))==0) && !(0x1 & (j>>position_bit)) )
{
index_matrix++;
}
}
parity_bits++; // keep the track of the number of parity check bit generated
}
}
for(i=0;i<parity_bits;i++)
{
dbg("***** Vector for Parity Bit %d ***** \n",i);
for(j=2;j>=0;j--)// (int)(index_matrix/BITS_VECTOR);j++)
{
printf("%x",*((vector+i)->pvector+j));
}
printf("\n");
}
return OK;
}
/*
* === FUNCTION ====================================================
* Name: dGenerator
* Description: creates the vector to decode a word
* in -> hamming_vector *
*
* out -> hamming_vector *
* =================================================================
* */
uint16_t dGenerator(hamming_vector *dVector, uint16_t payload_l)
{
uint32_t position_bit;
uint32_t i,j,b,parity_bits=0;
uint32_t index_n,bit_shift;
bool power_2;
for(i=1 ; i<= payload_l ; i++)
{
//check if the bit position is power of 2, bitwise
power_2 = ((i & (i - 1)) == 0);
if(power_2)
{
// calculation of the first bit of the bit position
position_bit = ffs(i)-1;
for(j=i+1;j<payload_l ;j++)
{
power_2 = ((j & (j - 1))==0 );
// if the bit position j has a bit in the bit position i is a
// parity check
if((0x1 & (j>>position_bit)) && !(power_2))
{
// position of the bit in uint32_t type
bit_shift = j % BITS_VECTOR;
//bit_shift = index_matrix & MOD_BIT_32;
// position in the array of uint32_t words
index_n = (int)(j/BITS_VECTOR);
//index_n = LOG_2_32 >> index_matrix;
//printf("***Bit %d bit_shift %d j %d \n ",i,bit_shift,j);
*((dVector+parity_bits)->pvector+index_n) ^= (BIT_MASK << (bit_shift-1));
// *((dVector+parity_bits)->pvector+index_n) ^= 0;
}
}
parity_bits++; // keep the track of the number of parity check bit generated
}
}
for(b=0;b<parity_bits;b++)
{
dbg("***** Vector for Parity Decoder Bit %d ***** \n",b);
for(j=0;j<1;j++)
{
printf("%x",*((dVector+b)->pvector+j));
}
printf("\n");
}
return OK;
}
/*
* === FUNCTION ====================================================
* Name: func_allocate for the structure hamming_vector
* Description: set/return the value of the code write
* in ->
* pointer and length to allocate
* out -> 0-> OK 1-> Error
* =================================================================
* */
uint16_t func_malloc(hamming_vector **vector,uint32_t row, uint32_t column)
{
uint32_t i;
if((*vector = (hamming_vector *)malloc(row*sizeof(hamming_vector)))==NULL)
{
dbg("Error malloc vector \n");
return ERROR;
}
// for every PARITY CHECK VECTOR FRAME_N bytes
for(i=0;i<row;i++)
{
if(((*vector+i)->pvector = (uint32_t *)malloc(column*sizeof(uint32_t)))==NULL)
{
dbg("Error Malloc vector of vector");
return ERROR;
}
}
//memset(&*vector,'\0',sizeof(hamming_vector)*row);
return OK;
}
/*
* === FUNCTION ====================================================
* Name: hamming_int
* Description: set/return the value of the code write
* in ->
* conf_code_rate -> value of the code rate
* write_read -> 1, write 0, value
* out -> code rate
* =================================================================
* */
uint16_t hamming_init(uint16_t conf_code_rate,uint16_t write_read)
{
static uint16_t code_rate;
if(write_read)
code_rate = conf_code_rate;
return code_rate;
}
/*
* === FUNCTION ====================================================
* Name: vector_length
* Description: return the length of the parity check vector for a given
* code rate, note it's a uint32_t vector, indeed return the
* number of uint32_t
* in ->
* code_rate -> value of the code rate
* out -> length of the vector
* =================================================================
* */
uint16_t filter_number(uint16_t code_rate)
{
uint16_t filter_n;
if(code_rate == RATE_7_4)
filter_n = 2;
else if(code_rate == RATE_15_11)
filter_n = 3;
else if(code_rate == RATE_31_26)
filter_n = 4;
else if(code_rate == RATE_63_57)
filter_n = 5;
else if(code_rate == RATE_127_120)
filter_n = 6;
else if(code_rate == RATE_255_247)
filter_n = 7;
else if(code_rate == RATE_1023_1013)
filter_n = 8;
else if(code_rate == RATE_2047_2036)
filter_n = 8;
else if(code_rate == RATE_4095_4083)
filter_n = 10;
else if(code_rate == RATE_8191_8178)
filter_n = 11;
else if(code_rate == RATE_12000_11986)
filter_n = 12;
return filter_n;
}
/*
* === FUNCTION ====================================================
* Name: vector_length
* Description: return the length of the parity check vector for a given
* code rate, note it's a uint32_t vector, indeed return the
* number of uint32_t
* in ->
* code_rate -> value of the code rate
* out -> length of the vector
* =================================================================
* */
uint16_t vector_length(uint16_t code_rate)
{
uint16_t vector_l;
if((code_rate == RATE_7_4) ||
(code_rate == RATE_15_11) ||
(code_rate == RATE_31_26))
vector_l = 1;
else if(code_rate == RATE_63_57)
vector_l = 2;
else if(code_rate == RATE_127_120)
vector_l = 4;
else if(code_rate == RATE_255_247)
vector_l = 8;
else if(code_rate == RATE_1023_1013)
vector_l = 32;
else if(code_rate == RATE_2047_2036)
vector_l = 64;
else if(code_rate == RATE_4095_4083)
vector_l = 128;
else if(code_rate == RATE_8191_8178)
vector_l = 256;
else if(code_rate == RATE_12000_11986)
vector_l = 512;
return vector_l;
}
/*
* === FUNCTION ====================================================
* Name: payload_length
* Description: return the max length of the payload for a given
* code rate
* in ->
* code_rate -> value of the code rate
* out -> length of the payload
* =================================================================
* */
uint16_t payload_length(uint16_t code_rate)
{
uint16_t payload_l;
if(code_rate == RATE_7_4)
payload_l = 7;
else if(code_rate == RATE_15_11)
payload_l = 15;
else if(code_rate == RATE_31_26)
payload_l = 31;
else if(code_rate == RATE_63_57)
payload_l = 63;
else if(code_rate == RATE_127_120)
payload_l = 127;
else if(code_rate == RATE_255_247)
payload_l = 255;
else if(code_rate == RATE_1023_1013)
payload_l = 1023;
else if(code_rate == RATE_2047_2036)
payload_l = 2047;
else if(code_rate == RATE_4095_4083)
payload_l = 4095;
else if(code_rate == RATE_8191_8178)
payload_l = 8191;
else if(code_rate == RATE_12000_11986)
payload_l = 16383;
return payload_l;
}
/*
* === FUNCTION ====================================================
* Name: random_error
* Description: introduces a random error in the encoded packet
* in -> encoded packet
* out -> encoded packet with one error
* =================================================================
* */
uint16_t random_error(uint32_t *encoded)
{
uint32_t bit_error;
bit_error = rand() % 10;
*encoded ^= (BIT_MASK << bit_error);
return OK;
}
//*******************************************************************
#ifdef EXE
int main ( int argc, char *argv[] )
{
uint32_t *payload,i;
uint16_t length;
uint32_t rate = RATE_127_120;
uint32_t *encoded;
uint32_t *decoded;
uint8_t *string;
if (( payload = (uint32_t *)malloc(1500*sizeof(uint8_t))) == NULL)
{
printf("Malloc in SendMsg \n");
}
if (( encoded = (uint32_t *)malloc(1500*sizeof(uint8_t))) == NULL)
{
printf("Malloc in SendMsg \n");
}
if (( decoded = (uint32_t *)malloc(1500*sizeof(uint8_t))) == NULL)
{
printf("Malloc in SendMsg \n");
}
if (( string= (uint32_t *)malloc(1500*sizeof(uint8_t))) == NULL)
{
printf("Malloc in SendMsg \n");
}
string = "HEY";
length = strlen(string);
memcpy((void *)payload,(const void *)string,length*7);
dbg("payload value %d length %d \n",*payload,length*7);
if(hamming_init(rate,WRITE) != rate)
dbg("Error setting rate");
vector_generator(WRITE);
*payload=0xFFFF;
encoded = hamming_encoder(payload, 11);
for(i=0;i<32;i++)
{
printf("%d ", (*encoded >> i ) & 0x1);
}
printf("\n");
random_error(encoded);
decoded = hamming_decoder(encoded,11);
for(i=0;i<32;i++)
{
printf("%d ", (*decoded >> i ) & 0x1);
}
printf("\n");
free(payload);
vector_generator(CLEAN);
return EXIT_SUCCESS;
}
#endif
#include "define.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include <string.h>
/*
* =====================================================================================
*
* Filename: hamming.h
*
* Description: header of hamming code
*
* Version: 1.0
* Created: 03/17/2011 07:13:27 PM
* Revision: none
* Compiler: gcc
*
* Author: Cesar Prados Boda (cp), c.prados@gsi.de
* Company: GSI
*
* =====================================================================================
*/
typedef struct {
uint32_t *pvector;
}hamming_vector;
typedef struct {
uint32_t *mask;
}filter_vector;
uint32_t *hamming_encoder (uint32_t *, uint16_t );
uint32_t *hamming_decoder(uint32_t *, uint16_t);
uint8_t parity_check(uint32_t * , uint32_t *,uint16_t, uint16_t );
uint16_t bitcount(uint16_t);
uint16_t find_num_parity_bits(uint16_t );
hamming_vector *vector_generator(uint16_t);
uint16_t generator(hamming_vector *, uint16_t);
uint16_t dGenerator(hamming_vector *, uint16_t);
uint16_t hamming_init(uint16_t, uint16_t );
uint16_t vector_length(uint16_t);
uint16_t payload_length(uint16_t);
uint16_t func_malloc(hamming_vector ** , uint32_t, uint32_t);
uint16_t filter_number(uint16_t);
uint16_t random_error(uint32_t *);
uint16_t filter_generator(hamming_vector *,uint16_t );
uint16_t dFilter_generator(hamming_vector *,uint16_t );
/*************************************
hamming_matrix.c
Cesar Prados
this source generates either the vector
of the parity checks bits for a given
(64,) with m as the numbers bits of the word
**************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <strings.h>
#include <string.h>
#include <stdint.h>
#define BIT_MASK 0x1
#define LENGTH 71
typedef struct {
uint8_t b : 1;
} bit;
int main ( void )
{
int i=0,j=0;
int position_bit;
bool power_2;
bit *parity_check_mask;
int position_matrix=0;
uint64_t *h_parity_check_mask;
parity_check_mask = (bit *)malloc(LENGTH*sizeof(bit));
h_parity_check_mask = (uint64_t *)malloc(sizeof(uint64_t));
for(i=1;i<=LENGTH;i++)
{
position_matrix = 0;
power_2= ((i & (i - 1)) == 0);
memset(parity_check_mask, '0', LENGTH *sizeof(bit));
memset(h_parity_check_mask, '\0',sizeof(uint64_t));
if(power_2)
{
printf("****Mask for Parity bit %d ******\n",i);
position_bit = ffsl(i)-1;
for(j=1;j<=LENGTH;j++)
{
if((0x1 & (j>>position_bit)) && !((j & (j - 1))==0))
{
(parity_check_mask+position_matrix)->b ^= BIT_MASK;
*h_parity_check_mask ^= ( BIT_MASK << position_matrix );
if((*h_parity_check_mask & 0x1) != 0x1){
printf("change %d \n",j);
printf("VALUE %llx ",*h_parity_check_mask);
}
position_matrix++;
}
else if(!((j & (j - 1))==0) && !(0x1 & (j>>position_bit)) )
{
position_matrix++;
}
}
printf("%llx \n",*h_parity_check_mask);
printf("%d \n",position_matrix);
for(j=0;j<position_matrix;j++)
{
printf("%d ",(parity_check_mask+j)->b);
}
printf("\n");
}
}
free(parity_check_mask);
free(h_parity_check_mask);
return 0;
}
#Makefile for Hamming Code
CC = gcc
CFLAGS = -g -O2 -lm -w -DEXE -DDBG #-Wall
OBJS = hamming.o
OBJS_M = hamming_matrix.o
OUTPUT= hamming
OUTPUT_M = hamming_matrix
all : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(OUTPUT)
matrix: $(OBJS_M)
$(CC) $(CFLAGS) $(OBJS_M) -o $(OUTPUT_M)
%.o : %.c
${CC} -c $^ $(CFLAGS)
install:
clean:
rm -f $(OBJS) $(OBJS_M)
CC = g++
CFLAGS = -Wall -O2 -g -fPIC -shared
OBJS = hamming.o
all: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o hamming.so
clean:
rm -f *.o *.so
%.o : %.cpp
$(CC) $(CFLAGS) -c $^
Hamming Code implements the Hamming coding plus parity bit (64,72).
Cesar Prados, GSI
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Makefile creates a library.
CALLING FUNCTIONS
Hamming_decode
**************
This function decode word of 64 bits with a 8 bits redundancy, 7 parity checks
bits and 1 complete parity of the word.
INPUT
std::payload
unsigned int chunk2encode .- Pointer to the beginning of the words
unsigned int num_chunks.- Position in Chunk2encode of the redundancy
unsigned int *nBytep.- Position in Bytes of the error
unsigned int *nBitP.- Position in Bits of the error
OUTPUT
unsigned int result .- return if the chunk has one error, two errors and more
than two erros.
Hamming_encode
**************
This function encode words of of 64 into 72 bits, 7 parity checks bits and 1 bit
for the parity of the complete word.
INPUT
const char *frame .- payload to encode
OUTPUT
std::string with the 8 bits parity bits.
#include "hamming.h"
/*
* =====================================================================================
*
* Filename: hamming code plus parity bit 64 72
*
* Description:
*
* Version: 1.0
* Created: 04/07/2011 01:48:23 PM
* Revision: none
* Compiler: gcc
*
* Author: Cesar Prados Boda (cp), c.prados@gsi.de
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*
* =====================================================================================*/
#define NUM_CHECK_BITS 7 // plus parity bit
#define BIT_MASK 0x1
#define SIZE 8 // 8 words 64 bits
unsigned int pbits0[NUM_CHECK_BITS][SIZE] ={ {0x5B, 0xAD, 0xAA, 0x56, 0x55, 0x55, 0x55, 0xAB}, // check vector 1
{0x6D, 0x36, 0x33, 0x99, 0x99, 0x99, 0xD9, 0x0C}, // check vector 2
{0x8E, 0xC7, 0xC3, 0xE3, 0xE1, 0xE1, 0xE1, 0xF1}, // check vector 3
{0xF0, 0x07, 0xFC, 0xE3, 0x1F, 0xE0, 0x1F, 0xFF}, // check vector 4
{0x00, 0xF8, 0xFF, 0x03, 0xE0, 0xFF, 0x1F, 0x00}, // check vector 5
{0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x01}, // check vector 6
{0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF} // check vector 7
};
unsigned int hamming_decode(std::string frame,unsigned int ichunk, unsigned int chunks, unsigned int *nBytep, unsigned int *nBitP)
{
unsigned char parity[]="";
unsigned int checkBitResult=0;
unsigned result;
for(int i=0; i<NUM_CHECK_BITS; ++i) { // parity vector x
int temp=0;
for(int j=0 ; j<SIZE ; j++) // byte by byte the frame
{
temp = ((bitset<8>(static_cast<unsigned char>(frame[ichunk + j])) & bitset<8>(pbits0[i][j])).count());
parity[0] ^= (unsigned char)((((bitset<8>((uint8_t)(frame[ichunk + j])) & bitset<8>(pbits0[i][j])).count() & 0x1 ?
1 : 0)
<< (i+1)));
}
}
// Parity bit, XOR of all the bits and the party bits
unsigned numBits=0;
for(int j=0 ; j<SIZE ; j++) // byte by byte the frame and the parity vector
{
numBits += (bitset<8>(static_cast<unsigned char>(frame[ichunk+j])).count());
}
parity[0] ^= (unsigned char)(numBits & 0x1 ?
1 : 0); // Postion 0 is for the parity bit */
unsigned int parityBit = 0;
if((parity[0] & 0x1) == (static_cast<unsigned char>(frame[chunks]) & 0x1))
parityBit = 1; // No error or double error
checkBitResult = 0;
for(int i=1;i<NUM_CHECK_BITS;i++)
checkBitResult ^= (((parity[0] >> (i)) ^ (static_cast<unsigned char >(frame[chunks]) >> (i))) & (BIT_MASK))<< (i-1);
if((checkBitResult!=0) && (parityBit == 1 ))
{
result = 2; // Double Error;
}
else if(checkBitResult != 0 )// single error, we can repair it
{
checkBitResult = postionInfraeme(checkBitResult);
unsigned int nByte = checkBitResult / SIZE;
unsigned int nBit = checkBitResult % SIZE;
*nBitP = nBit;
*nBytep = nByte;
//cout << "************ERROR IN BYTE " << nByte << " BIT " << nBit << "************" << endl;
result = 1 ;
}
else // No errors
{
result = 0;
}
return result ;
}
int postionInfraeme(int postion)
{
int postionDiff;
if((postion >4) && (postion <=7)) postionDiff = postion - 3;
else if((postion >8)&& (postion <=15)) postionDiff = postion - 4;
else if((postion >16)&& (postion <=31)) postionDiff = postion - 5;
else if(postion >32) postionDiff = postion - 6;
// the error is in the parity checks
return postionDiff;
}
std::string hamming_encode(const char *frame)
{
unsigned char parity[]="";
for(int i=0; i<NUM_CHECK_BITS; ++i) {// parity vector x
for(int j=0 ; j<SIZE ; j++) // byte by byte the frame and the parity vector
{
parity[0] ^= (unsigned char)((((bitset<8>(frame[j]) & bitset<8>(pbits0[i][j])).count() & 0x1 ?
1 : 0)
<< (i+1)));
}
}
// Parity bit, XOR of all the bits and the party bits
int numBits=0;
for(int j=0 ; j<SIZE ; j++) // byte by byte the frame and the parity vector
{
numBits += (bitset<8>(frame[j]).count());
}
parity[0] ^= (unsigned char)(numBits & 0x1 ?
1 : 0); // Postion 0 is for the parity bit */
string eFrame;
eFrame.resize(1);
if(parity[0]== 0) // if the parity check is 0
eFrame[0] = 0; // set to 0000000
else eFrame[0]= parity[0]; // in the last byte parity word
return eFrame;
}
#include <iterator>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <iostream>
#include <bitset>
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
std::string hamming_encode(const char *);
unsigned int hamming_decode(std::string frame,unsigned int , unsigned int , unsigned int *, unsigned int *);
int postionInfraeme(int );
#ifdef __cplusplus
}
#endif
/* A hardware-like C++ implementation of a Reed-Solomon erasure code.
* Copyright (C) 2010-2011 GSI GmbH.
* Author: Wesley W. Terpstra
*/
#include "gf256.h"
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <assert.h>
const GF256 GF256::zero(0);
const GF256 GF256::one(1);
const GF256 GF256::g(2);
/* The hard-coded number of losses this code is designed to recover.
* Presumably a parameter for a VHDL generic.
*/
#define K 2
/* This Reed-Solomon code uses systematic encoding, which means that the
* codewords include as a prefix the original message.
*
* Each codeword c(x) is defined to be a multiple of product_i (x-g^i)
* for i=0..(K-1). The encoder and decoder are implemented with the same
* circuit. Given n symbols of which K are unknown (and set to 0), the
* missing K values are recovered.
*/
/* This circuit precomputes the lambda values needed by the (en|de)coder.
* It should be run once after all the packets have been received.
*
* The output polynomial the lowest order polynomial with roots on the
* generator; ie: lambda(x) := (x - g^i0)*(x - g^i1)*...
*
* Input:
* The indices of the lost packets.
* Output:
* The coefficients of lambda(x).
* The roots of lambda(x).
*/
void precompute(int i[K], GF256 gi[K], GF256 lambda[K+1])
{
GF256 g2; /* Register for the expression g^2^clock */
int is[K]; /* Bit-shift register for the indices */
/* Initial values of the registers */
g2 = GF256::g;
lambda[0] = GF256::one;
for (int j = 0; j < K; ++j) {
gi[j] = GF256::one;
is[j] = i[j];
lambda[j+1] = GF256::zero;
}
/* Step 1 is to compute the values gi */
for (int clock = 0; clock < 8; ++clock) {
/* Look at the low bit of the shift registers */
for (int j = 0; j < K; ++j) {
gi[j] = gi[j] * ((is[j]&1)?g2:GF256::one);
is[j] = is[j] >> 1;
}
g2 = g2*g2;
}
/* Step 2 is to compute the polynomial product */
for (int clock = 0; clock < K; ++clock) {
/* A K-wide "shift" register composed of bytes */
for (int j = K; j > 0; --j)
lambda[j] = lambda[j]*gi[clock] + lambda[j-1];
lambda[0] = lambda[0] * gi[clock];
}
}
/* Input:
* The number of symbols in the codeword (n > K)
* The indices of the codeword which are missing.
* The result of precompute on those indices.
* Output:
* Fills in the missing values of c.
*/
void code(int n, GF256 c[], int i[K], GF256 gi[K], GF256 lambda[K+1])
{
/* Registers */
GF256 lg[K+1]; /* lambda[i]*g^(i*clock) */
GF256 a[K]; /* Accumulator for the missing symbols */
GF256 dli[K]; /* (d/dx lambda)(g^i) */
GF256 gic[K]; /* g^i*g^-c */
/* Hard-wired constants */
GF256 gj1[K+1]; /* g^(j-1) */
/* Clear the unknown symbols to zero */
// for (int j = 0; j < K; ++j)
// c[i[j]] = GF256::zero;
/* Initialize the registers and constants */
for (int j = 0; j < K; ++j) {
lg[j] = lambda[j];
gic[j] = gi[j];
a[j] = GF256::zero;
dli[j] = GF256::zero;
gj1[j] = GF256::g^(j-1);
}
lg[K] = lambda[K];
gj1[K] = GF256::g^(K-1);
/* In each step, we read c[clock] from memory */
for (int clock = 0; clock < n; ++clock) {
/* This circuit feeds l1c and dlc into the decoders */
GF256 dlc = GF256::zero, l1c = GF256::zero;
for (int j = 0; j < K+1; ++j) {
l1c += lg[j]; /* XOR all the lg[j] together */
dlc += (j&1)?lg[j]:GF256::zero; /* XOR the odd lg[j] together */
lg[j] = lg[j] * gj1[j]; /* Hard-wired multiplier */
}
/* Load from main memory: */
GF256 cc = c[clock];
GF256 product = cc * l1c;
/* Replicate this circuit for each K */
for (int j = 0; j < K; ++j) {
GF256 divisor = GF256::one - gic[j];
gic[j] *= GF256::g.inverse(); /* Hard-wired multiplier */
a[j] = a[j] + (product / divisor);
/* Record dlc if it's our index */
//if (clock == i[j])
if (divisor == GF256::zero) dli[j] = dlc;
}
}
/* Implement multiplicative inverse using a lookup table */
for (int j = 0; j < K; ++j)
c[i[j]] = a[j] * dli[j].inverse();
}
#define MAX_FRAG_SIZE 1500
static unsigned char result[K][MAX_FRAG_SIZE];
/* Command-line driven test-cases */
void RS_code(unsigned int fragLen, std::vector<const unsigned char*>& fragments) {
int missing[K];
int missing_index;
assert (fragLen < MAX_FRAG_SIZE);
assert (fragments.size() > K);
missing_index = 0;
for (unsigned int i = 0; i < fragments.size(); ++i) {
if (fragments[i] == 0) {
assert (missing_index < K);
missing[missing_index++] = i;
}
}
GF256 c[fragments.size()]; //code word
GF256 gi[K];
GF256 lambda[K+1];
precompute(missing, gi, lambda);
for (unsigned int i = 0; i < fragLen; ++i) { // stripe by stripe
for (unsigned int j = 0; j < fragments.size(); ++j) { // code by code word
if (fragments[j])
c[j] = GF256::embed(fragments[j][i]);
else
c[j] = GF256::zero;
}
code(fragments.size(), c, missing, gi, lambda); // fills in 0 values
for (unsigned j = 0; j < K; ++j)
result[j][i] = c[missing[j]].project();
}
for (unsigned int j = 0; j < K; ++j)
fragments[missing[j]] = result[j];
}
/**********************************************************************
*
* Filename: crc.c
*
* Description: Slow and fast implementations of the CRC standards.
*
* Notes: The parameters for each supported CRC standard are
* defined in the header file crc.h. The implementations
* here should stand up to further additions to that list.
*
*
* Copyright (c) 2000 by Michael Barr. This software is placed into
* the public domain and may be used for any purpose. However, this
* notice must not be changed or removed and no warranty is either
* expressed or implied by its publication or distribution.
**********************************************************************/
#include "crc.h"
/*
* Derive parameters from the standard-specific parameters in crc.h.
*/
#define WIDTH (8 * sizeof(crc))
#define TOPBIT (1 << (WIDTH - 1))
#if (REFLECT_DATA == TRUE)
#undef REFLECT_DATA
#define REFLECT_DATA(X) ((unsigned char) reflect((X), 8))
#else
#undef REFLECT_DATA
#define REFLECT_DATA(X) (X)
#endif
#if (REFLECT_REMAINDER == TRUE)
#undef REFLECT_REMAINDER
#define REFLECT_REMAINDER(X) ((crc) reflect((X), WIDTH))
#else
#undef REFLECT_REMAINDER
#define REFLECT_REMAINDER(X) (X)
#endif
/*********************************************************************
*
* Function: reflect()
*
* Description: Reorder the bits of a binary sequence, by reflecting
* them about the middle position.
*
* Notes: No checking is done that nBits <= 32.
*
* Returns: The reflection of the original data.
*
*********************************************************************/
static unsigned long
reflect(unsigned long data, unsigned char nBits)
{
unsigned long reflection = 0x00000000;
unsigned char bit;
/*
* Reflect the data about the center bit.
*/
for (bit = 0; bit < nBits; ++bit)
{
/*
* If the LSB bit is set, set the reflection of it.
*/
if (data & 0x01)
{
reflection |= (1 << ((nBits - 1) - bit));
}
data = (data >> 1);
}
return (reflection);
} /* reflect() */
/*********************************************************************
*
* Function: crcSlow()
*
* Description: Compute the CRC of a given message.
*
* Notes:
*
* Returns: The CRC of the message.
*
*********************************************************************/
crc
crcSlow(unsigned char const message[], int nBytes)
{
crc remainder = INITIAL_REMAINDER;
int byte;
unsigned char bit;
/*
* Perform modulo-2 division, a byte at a time.
*/
for (byte = 0; byte < nBytes; ++byte)
{
/*
* Bring the next byte into the remainder.
*/
remainder ^= (REFLECT_DATA(message[byte]) << (WIDTH - 8));
/*
* Perform modulo-2 division, a bit at a time.
*/
for (bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
}
/*
* The final remainder is the CRC result.
*/
return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
} /* crcSlow() */
crc crcTable[256];
/*********************************************************************
*
* Function: crcInit()
*
* Description: Populate the partial CRC lookup table.
*
* Notes: This function must be rerun any time the CRC standard
* is changed. If desired, it can be run "offline" and
* the table results stored in an embedded system's ROM.
*
* Returns: None defined.
*
*********************************************************************/
void
crcInit(void)
{
crc remainder;
int dividend;
unsigned char bit;
/*
* Compute the remainder of each possible dividend.
*/
for (dividend = 0; dividend < 256; ++dividend)
{
/*
* Start with the dividend followed by zeros.
*/
remainder = dividend << (WIDTH - 8);
/*
* Perform modulo-2 division, a bit at a time.
*/
for (bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
/*
* Store the result into the table.
*/
crcTable[dividend] = remainder;
}
} /* crcInit() */
/*********************************************************************
*
* Function: crcFast()
*
* Description: Compute the CRC of a given message.
*
* Notes: crcInit() must be called first.
*
* Returns: The CRC of the message.
*
*********************************************************************/
crc
crcFast(unsigned char const message[], int nBytes)
{
crc remainder = INITIAL_REMAINDER;
unsigned char data;
int byte;
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (byte = 0; byte < nBytes; ++byte)
{
data = REFLECT_DATA(message[byte]) ^ (remainder >> (WIDTH - 8));
remainder = crcTable[data] ^ (remainder << 8);
}
/*
* The final remainder is the CRC.
*/
return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
} /* crcFast() */
/**********************************************************************
*
* Filename: crc.h
*
* Description: A header file describing the various CRC standards.
*
* Notes:
*
*
* Copyright (c) 2000 by Michael Barr. This software is placed into
* the public domain and may be used for any purpose. However, this
* notice must not be changed or removed and no warranty is either
* expressed or implied by its publication or distribution.
**********************************************************************/
#ifndef _crc_h
#define _crc_h
#define FALSE 0
#define TRUE !FALSE
/*
* Select the CRC standard from the list that follows.
*/
#define CRC_CCITT
#if defined(CRC_CCITT)
typedef unsigned short crc;
#define CRC_NAME "CRC-CCITT"
#define POLYNOMIAL 0x1021
#define INITIAL_REMAINDER 0xFFFF
#define FINAL_XOR_VALUE 0x0000
#define REFLECT_DATA FALSE
#define REFLECT_REMAINDER FALSE
#define CHECK_VALUE 0x29B1
#elif defined(CRC16)
typedef unsigned short crc;
#define CRC_NAME "CRC-16"
#define POLYNOMIAL 0x8005
#define INITIAL_REMAINDER 0x0000
#define FINAL_XOR_VALUE 0x0000
#define REFLECT_DATA TRUE
#define REFLECT_REMAINDER TRUE
#define CHECK_VALUE 0xBB3D
#elif defined(CRC32)
typedef unsigned long crc;
#define CRC_NAME "CRC-32"
#define POLYNOMIAL 0x04C11DB7
#define INITIAL_REMAINDER 0xFFFFFFFF
#define FINAL_XOR_VALUE 0xFFFFFFFF
#define REFLECT_DATA TRUE
#define REFLECT_REMAINDER TRUE
#define CHECK_VALUE 0xCBF43926
#else
#error "One of CRC_CCITT, CRC16, or CRC32 must be #define'd."
#endif
void crcInit(void);
crc crcSlow(unsigned char const message[], int nBytes);
crc crcFast(unsigned char const message[], int nBytes);
#endif /* _crc_h */
\ No newline at end of file
#include "fec.h"
#include "hamming.h"
#include <vector>
#include <string>
#include <map>
#include <queue>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include "crc.c"
//#define DEMO__ // makes a binary for the demo
#ifdef DEMO_PRINT__
#define dbg(x, ...) fprintf(stderr, "(debug) " x, ##__VA_ARGS__)
#else
#define dbg(x, ...)
#endif
#define K 2 // Configuration parmamiter
#define MAX_output_messages 1024
extern void RS_code(unsigned int fragLen, std::vector<const unsigned char*>& fragments);
/*
* ====================================================================================
*
* Filename: fec.cpp
*
* Description:
*
* Version: 1.0
* Created: 04/07/2011 12:58:52 PM
* Revision: none
* Compiler: gcc
*
* Author: Cesar Prados Boda (cp), c.prados@gsi.de
* Wesley Terpstra w.terpstra@gsi.de
* Company: GSI
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
* =====================================================================================
*/
static uint32_t outgoing_msgID = 0;
void fec_open()
{
srand(time(0));
outgoing_msgID = rand();
}
void fec_close()
{
}
static unsigned int fec_chopchop(unsigned int msize) {
// !!! Do something intelligent!
return 2;
}
struct State
{
unsigned int msize;
unsigned int divsize;
unsigned int fragments_received;
std::vector<std::string> received;
};
typedef std::map<uint32_t, State> Map;
typedef std::queue<uint32_t> Queue;
static Map cache;
static Queue inCache;
static std::string result;
const unsigned char* fec_decode(const unsigned char* chunk, unsigned int* len)
{
unsigned int length = *len;
unsigned int chunks = length / 9;
if (length % 9 != 0 || length < 18) return 0;
std::string eChunk(reinterpret_cast<const char*>(chunk));
unsigned short crc1 = crcSlow(reinterpret_cast<const unsigned char*>(eChunk.substr(8,8).c_str()),8);
#ifdef DEMO__
cout << "************************START DECODING CONTROL MESSAGE************************ " << endl;
system("sleep 1");
#endif
for (unsigned int i = 0; i < chunks; ++i) {
#ifdef DEMO__
cout << endl;
cout << "---------------------ENCODED HAMMING WORD RX-----------------" << endl;
cout << "------------------------------------------------------" << endl;
cout << "ENCODED MESSAGE " << eChunk.substr(i*8,8) << endl;
cout << "PARITY BITS " << eChunk.substr((chunks*8)+i,8) << endl;
#endif
unsigned int nByte;
unsigned int nBit;
int decodeResult = hamming_decode(eChunk, i*8, (chunks*8)+i,&nByte,&nBit); //c
if(decodeResult == 0) cout << "NO ERRORS" << endl;
else if(decodeResult == 1) // One error o more than 2 errors
{
// CRC after fix the bit
unsigned short crc2 = crcSlow(reinterpret_cast<const unsigned char*>(eChunk.substr(12,8).c_str()),8);
if(crc1 == crc2) // One error and is going to be fixed
{
eChunk[i*8+nByte] ^= (char)(0x1 << (nBit-1)); // THe bit is fixed
#ifdef DEMO__
cout << "FIXED MESSAGE " << eChunk.substr(i*8,8) << endl;
cout << "CRC RX " << crc1 << " CRC FIXED " << crc2 << endl;
#endif
}
else // More than 2 errros
{
#ifdef DEMO__
cout << "FIXED MESSAGE ??????????" << endl;
system("sleep 1");
cout << eChunk.substr(i*8,8) << endl;
cout << "I DON'T THINK SO..." << endl;
cout << "CRC ORIGINAL " << crc1 << " CRC RX " << crc2 << endl;
cout << "MORE THAN TWO ERROR" << endl;
cout << "************************NO CORRECTION FRAME LOST************************ " << endl<< endl;
#endif
return 0;
}
} // Two errors!!!
else if(decodeResult == 2){
cout << "DOUBLE ERROR" << endl;
cout << "************************NO CORRECTION FRAME LOST************************ " << endl<< endl;
return 0;
}
cout << "-----------------------------------------------------" << endl;
#ifdef DEMO__
system("sleep 0.5");
#endif
}
#ifdef DEMO__
cout << "************************END DECODING CONTROL MESSAGE************************ " << endl;
#endif
uint64_t header = 0;
for (int i = 0; i < 8; ++i)
{
header <<= 8;
header |= static_cast<uint8_t> (eChunk[i]);
}
uint32_t mID = (header >> 32) & 0xFFFFFFFF;
unsigned int msize = (header >> 20) & 0xFFF;
unsigned int fragLen = (header >> 8) & 0xFFF;
unsigned int index = (header >> 0) & 0xFF;
unsigned int output_messages = fec_chopchop(msize);
unsigned int divsize = (msize+output_messages-1) / output_messages;
unsigned int rsinsize = (divsize+7) & ~7;
if (fragLen != length) return 0;
if (fragLen != (rsinsize+8)/8*9) return 0;
if (index > output_messages+K) return 0;
Map::iterator state = cache.find(mID);
if (state == cache.end())
{
if (inCache.size() > MAX_output_messages)
{
uint32_t kill = inCache.front();
inCache.pop();
cache.erase(cache.find(kill));
}
inCache.push(mID);
State& newState = cache[mID]; // add it
state = cache.find(mID);
newState.msize = msize;
newState.fragments_received = 0;
newState.divsize = (msize + output_messages-1) / output_messages;
newState.received.resize(output_messages + K);
}
if (state->second.msize != msize) return 0; // Doesn't fit with other packets
if (!state->second.received[index].empty()) return 0; // Duplicated packet
// Grab the data portion of the buffer
state->second.received[index] = eChunk.substr(8, (chunks-1)*8);
//state->second.received[index] = std::string(reinterpret_cast<const char*>(chunk)+8, (chunks-1)*8);
//If we don't have enough packets yet (or already decode), stop now
if (++state->second.fragments_received != output_messages) return 0;
// DECODING TIME!
std::vector<const unsigned char*> fragments;
fragments.resize(state->second.received.size());
for (unsigned int i = 0; i < fragments.size(); ++i)
if (state->second.received[i].empty())
fragments[i] = 0;
else
fragments[i] = reinterpret_cast<const unsigned char*>(state->second.received[i].data());
// Do the work
RS_code(divsize, fragments);
// Reassemble the packet
result.clear();
result.reserve(divsize*output_messages);
for (unsigned int i = 0; i < output_messages; ++i)
for (unsigned int j = 0; j < divsize; ++j)
result.push_back(fragments[i][j]);
result.resize(msize); // clip the padding and done
*len = result.size();
return reinterpret_cast<const unsigned char*>(result.data());
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
static std::vector<std::string> output_messages;
static void fec_setup(const unsigned char* chunk, unsigned int len)
{
unsigned int msize = len;
output_messages.clear();
output_messages.resize(fec_chopchop(msize));
unsigned int divsize = (msize+output_messages.size()-1) / output_messages.size();
unsigned int rsinsize = (divsize+7) & ~7;
// Make a -id
uint32_t msgID = ++outgoing_msgID;
std::string buf(reinterpret_cast<const char*>(chunk), msize);
buf.resize(divsize*output_messages.size()); // Pad with 0 to a multiple of output_messages
std::vector<const unsigned char*> fragments;
fragments.reserve(output_messages.size()+K);
for (unsigned int i = 0; i < output_messages.size(); ++i)
fragments.push_back(reinterpret_cast<const unsigned char*>(buf.data() + i*divsize));
for (unsigned int i = 0; i < K; ++i)
fragments.push_back(0);
// Do the actual RS-encoding
RS_code(divsize, fragments);
output_messages.resize(output_messages.size() + K);
#ifdef DEMO__
cout << "************************START ENCODING CONTROL MESSAGE************************ " << endl;
#endif
for (unsigned int i = 0; i < output_messages.size(); ++i)
{
std::string msg(8, 'x');
unsigned int fragLen = (rsinsize + 8)/8*9;
uint64_t header =
((uint64_t)msgID << 32) |
((uint64_t)msize << 20) |
((uint64_t)fragLen << 8) |
((uint64_t)i << 0);
for (int j = 7; j > 0; --j) {
uint8_t low = header & 0xFF;
header >>= 8;
msg[j] = static_cast<char>(low);
}
msg += std::string(reinterpret_cast<const char*>(fragments[i]), divsize);
msg.resize(rsinsize + 8); // Pad with 0 to a multiple of 8
unsigned int chunks = msg.size() / 8; // SEC-DED(72,64) is 8 bytes at once
#ifdef DEMO__
cout << "---------------------CHUNK " << i << "--------------------------" << endl;
cout << "-----------------------------------------------------" << endl;
#endif
for (unsigned int j = 0; j < chunks; ++j)
{
#ifdef DEMO__
cout << " STRING TO ENCODE " << msg.substr(j*8,8) << endl;
cout << "-----------------------------------------------------" << endl;
#endif
std::string parityBits = hamming_encode(msg.substr(j*8,8).c_str());
msg.push_back(parityBits[0]); // !!! result of hamming code
#ifdef DEMO__
system("sleep 0.5");
#endif
parityBits.clear();
}
output_messages[i] = msg;
#ifdef DEMO__
cout << "-----------------------------------------------------" << endl;
cout << " HAMMING WORD ENCODED " << msg << endl;
cout << "-----------------------------------------------------" << endl;
system("sleep 1");
#endif
}
#ifdef DEMO__
cout << "************************END ENCODING CONTROL MESSAGE************************ " << endl;
cout << endl << endl << endl;
cout << "........................TRANSMISSION........................... " << endl;
cout << "........................TRANSMISSION........................... " << endl;
cout << "........................TRANSMISSION........................... " << endl;
cout << "........................TRANSMISSION........................... " << endl;
cout << "........................TRANSMISSION........................... " << endl;
cout << "........................TRANSMISSION........................... " << endl;
cout << "........................TRANSMISSION........................... " << endl;
cout << endl << endl << endl;
#endif
}
const unsigned char* fec_encode(const unsigned char* chunk, unsigned int* len, int index)
{
if (index == 0) fec_setup(chunk, *len);
if (index == (int)output_messages.size()) return 0;
*len = output_messages[index].size();
return reinterpret_cast<const unsigned char*>(output_messages[index].data());
}
#ifndef FEC_H
#define FEC_H
#ifdef __cplusplus
extern "C" {
#endif
/* Initialize any buffers / state needed to encode/decode packets */
void fec_open();
/* Free any resources used by the encoder/decoder */
void fec_close();
/* Input: data received from ethernet payload [chunk, chunk+*len)
* Output:
* If cannot (yet) decode, returns 0
* Otherwise, returns pointer to decoded message and modifies *len
*
* Note: inside be buffers
*/
const unsigned char* fec_decode(const unsigned char* chunk, unsigned int* len);
const unsigned char* fec_decode_no(const unsigned char* chunk, unsigned int* len);
/* Input: ethernet payload to send [chunk, chunk+*len)
* index, starts at 0 and incremented each call until done
* Output:
* If no more chunks follow, returns 0
* Returns encoded packet and modifies *len
*/
const unsigned char* fec_encode(const unsigned char* chunk, unsigned int* len, int index);
#ifdef __cplusplus
}
#endif
#endif
#include "hamming.h"
/*
* =====================================================================================
*
* Filename: hamming code plus parity bit 64 72
*
* Description:
*
* Version: 1.0
* Created: 04/07/2011 01:48:23 PM
* Revision: none
* Compiler: gcc
*
* Author: Cesar Prados Boda (cp), c.prados@gsi.de
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*
* =====================================================================================*/
#define NUM_CHECK_BITS 7 // plus parity bit
#define BIT_MASK 0x1
#define SIZE 8 // 8 words 64 bits
unsigned int pbits0[NUM_CHECK_BITS][SIZE] ={ {0x5B, 0xAD, 0xAA, 0x56, 0x55, 0x55, 0x55, 0xAB}, // check vector 1
{0x6D, 0x36, 0x33, 0x99, 0x99, 0x99, 0xD9, 0x0C}, // check vector 2
{0x8E, 0xC7, 0xC3, 0xE3, 0xE1, 0xE1, 0xE1, 0xF1}, // check vector 3
{0xF0, 0x07, 0xFC, 0xE3, 0x1F, 0xE0, 0x1F, 0xFF}, // check vector 4
{0x00, 0xF8, 0xFF, 0x03, 0xE0, 0xFF, 0x1F, 0x00}, // check vector 5
{0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x01}, // check vector 6
{0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF} // check vector 7
};
unsigned int hamming_decode(std::string frame,unsigned int ichunk, unsigned int chunks, unsigned int *nBytep, unsigned int *nBitP)
{
unsigned char parity[]="";
unsigned int checkBitResult=0;
unsigned result;
for(int i=0; i<NUM_CHECK_BITS; ++i) { // parity vector x
int temp=0;
for(int j=0 ; j<SIZE ; j++) // byte by byte the frame
{
temp = ((bitset<8>(static_cast<unsigned char>(frame[ichunk + j])) & bitset<8>(pbits0[i][j])).count());
parity[0] ^= (unsigned char)((((bitset<8>((uint8_t)(frame[ichunk + j])) & bitset<8>(pbits0[i][j])).count() & 0x1 ?
1 : 0)
<< (i+1)));
}
}
// Parity bit, XOR of all the bits and the party bits
unsigned numBits=0;
for(int j=0 ; j<SIZE ; j++) // byte by byte the frame and the parity vector
{
numBits += (bitset<8>(static_cast<unsigned char>(frame[ichunk+j])).count());
}
parity[0] ^= (unsigned char)(numBits & 0x1 ?
1 : 0); // Postion 0 is for the parity bit */
unsigned int parityBit = 0;
if((parity[0] & 0x1) == (static_cast<unsigned char>(frame[chunks]) & 0x1))
parityBit = 1; // No error or double error
checkBitResult = 0;
for(int i=1;i<NUM_CHECK_BITS;i++)
checkBitResult ^= (((parity[0] >> (i)) ^ (static_cast<unsigned char >(frame[chunks]) >> (i))) & (BIT_MASK))<< (i-1);
if((checkBitResult!=0) && (parityBit == 1 ))
{
result = 2; // Double Error;
}
else if(checkBitResult != 0 )// single error, we can repair it
{
checkBitResult = postionInfraeme(checkBitResult);
unsigned int nByte = checkBitResult / SIZE;
unsigned int nBit = checkBitResult % SIZE;
*nBitP = nBit;
*nBytep = nByte;
//cout << "************ERROR IN BYTE " << nByte << " BIT " << nBit << "************" << endl;
result = 1 ;
}
else // No errors
{
result = 0;
}
return result ;
}
int postionInfraeme(int postion)
{
int postionDiff;
if((postion >4) && (postion <=7)) postionDiff = postion - 3;
else if((postion >8)&& (postion <=15)) postionDiff = postion - 4;
else if((postion >16)&& (postion <=31)) postionDiff = postion - 5;
else if(postion >32) postionDiff = postion - 6;
// the error is in the parity checks
return postionDiff;
}
std::string hamming_encode(const char *frame)
{
unsigned char parity[]="";
for(int i=0; i<NUM_CHECK_BITS; ++i) {// parity vector x
for(int j=0 ; j<SIZE ; j++) // byte by byte the frame and the parity vector
{
parity[0] ^= (unsigned char)((((bitset<8>(frame[j]) & bitset<8>(pbits0[i][j])).count() & 0x1 ?
1 : 0)
<< (i+1)));
}
}
// Parity bit, XOR of all the bits and the party bits
int numBits=0;
for(int j=0 ; j<SIZE ; j++) // byte by byte the frame and the parity vector
{
numBits += (bitset<8>(frame[j]).count());
}
parity[0] ^= (unsigned char)(numBits & 0x1 ?
1 : 0); // Postion 0 is for the parity bit */
string eFrame;
eFrame.resize(1);
if(parity[0]== 0) // if the parity check is 0
eFrame[0] = 0; // set to 0000000
else eFrame[0]= parity[0]; // in the last byte parity word
return eFrame;
}
#include <iterator>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <iostream>
#include <bitset>
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
std::string hamming_encode(const char *);
unsigned int hamming_decode(std::string frame,unsigned int , unsigned int , unsigned int *, unsigned int *);
int postionInfraeme(int );
#ifdef __cplusplus
}
#endif
/*
* =====================================================================================
*
* Filename: test-driver.cpp
*
* Description:
*
* Version: 1.0
* Created: 04/07/2011 01:48:23 PM
* Revision: none
* Compiler: gcc
*
* Author: Cesar Prados Boda (cp), c.prados@gsi.de
* Wesley Terpstra w.terpstra@gsi.de
*
* This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*
* =====================================================================================
*/
#include "fec.h"
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
//#define DEMO__ // makes a binary for the demo
int main()
{
unsigned char msg[] = "PAYLOAD1"
"PAYLOAD2"
"PAYLOAD3"
"PAYLOAD4";
// unsigned char msg[] = "Nel mezzo del "
// "camin di nostra "
// "vita mi ritrovai"
// " per una selva "
// "oscura,ché la "
// "diritta via era "
// "smarrita........";
int c;
const unsigned char* buf;
const unsigned char* cbuf;
unsigned int i, len,len_temp;
unsigned char *temp;
printf("\n \n \n");
printf("*************************************************************\n");
printf(" WE WANT TO ENCODE: \n");
printf("");
for (i = 0; i < sizeof(msg)-1; ++i)
{
printf("%c", msg[i]);
}
printf("\n");
printf("*************************************************************\n");
printf("\n \n \n");
#ifdef DEMO__
system("sleep 1");
#endif
fec_open();
for (c = 0; len = sizeof(msg)-1, (buf = fec_encode(msg, &len, c)) != 0; ++c)
{
//for (i = 0; i < len; ++i)
//printf("%c(%02x)", isprint(buf[i])?buf[i]:"x", buf[i]);
//printf("\n");
}
// fflush(stdout);
len = sizeof(msg)-1;
buf = fec_encode(msg, &len, 0);
cbuf = fec_decode(buf, &len);
len = sizeof(msg)-1;
buf = fec_encode(msg, &len, 1);
cbuf = fec_decode(buf, &len);
len = sizeof(msg)-1;
buf = fec_encode(msg, &len, 3);
if (cbuf != 0) {
printf("\n \n \n");
printf("******************************************************************\n");
printf("!!!!!!!!!!!!!!!!!THE CONTROL MESSAGE IS DECODED!!!!!!!!!!!!!!!!!\n");
printf("******************************************************************\n");
printf("");
for (i = 0; i < len; ++i)
{
printf("%c", cbuf[i]);
}
printf("\n");
}
else
{
printf("\n \n \n");
printf("******************************************************************\n");
printf("!!!!!!!!!!!!!!!!!THE CONTROL MESSAGE IS NOT DECODED!!!!!!!!!!!!!!!!!\n");
printf("******************************************************************\n");
}
fec_close();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment