Commit d867dbde authored by bradomyn's avatar bradomyn

Imported the hamming/reed solomon from the wr-switch-sw repo, authors: Wesley,Maceij and Cesar

parent 1406bc93
#Makefile for Hamming Code
CC = g++
CFLAGS = -g3 -O0 -lm -w -Wall
TESTER = test
DECODER = decoder
ifdef TEST
OBJS = test-driver.o code.o fec.o crc.o hamming.o
OUTPUT= $(TESTER)
else
OBJS = fec_decoder.o code.o fec.o crc.o hamming.o
OUTPUT= $(DECODER)
endif
all : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(OUTPUT)
clean:
rm -f $(OBJS) $(TESTER) $(DECODER)
/* 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);
const GF256 GF256::g(3);
/* 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
#ifdef __cplusplus
extern "C" {
#endif
void crcInit(void);
crc crcSlow(unsigned char const message[], int nBytes);
crc crcFast(unsigned char const message[], int nBytes);
#ifdef __cplusplus
}
#endif
#endif /* _crc_h */
This diff is collapsed.
#ifndef FEC_H
#define FEC_H
#ifdef __cplusplus
extern "C" {
#endif
//#define DBG_SHOW_CHUNKS
//#define DBG_SHOW_PARAMETERS
//#define DBG_SHOW_HEADER
typedef struct {
unsigned int schemaID; // 4 bits
unsigned int fragmentID; // 4 bits
unsigned int msgID; // 16 bits
unsigned int etherType; // 16 bits
unsigned int originSize; // 13 bits
unsigned int framgentSize; // 8 bits
} fec_header_t;
typedef struct {
unsigned int receivedOrderNumber; //received as which in turn
unsigned int sentOrderNumber; //fragmentID
unsigned int recoveredBitsNumber; //how many bits where recovered using Hamming
unsigned int duplicatesReceived; //number of duplicates
unsigned int framgentSize;
bool fragmentRecovered; //was the fragment recovered in the end
bool fragmentUsed; //was the fragment used
bool errorInHeader; //was the error in FEC header
} fec_decoder_fragment_raport_t;
typedef struct {
fec_decoder_fragment_raport_t fragments[8];
unsigned int bitsRecovered;
unsigned int fragmentsLost;
unsigned int fragmentsReceived;
unsigned int duplicatesReceived;
bool msgRecovered;
bool tooManyFragments;
} fec_decoder_msg_raport_t;
/* 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 fragSize,
int* origMsgSize, unsigned int* origEtherType);
/* 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);
int fec_encoder(const unsigned char* origMsg, unsigned int origMsgLen,
unsigned int origEtherType, const unsigned char** encodedMsgs,
unsigned int* encodedMsgLen, unsigned int* msg_number);
int erasure_channel(const unsigned char** errorMsgs, const unsigned char** encodedMsgs,
unsigned int encodedMsgLen[], unsigned int msg_number) ;
int fec_decoder_report();
#ifdef __cplusplus
}
#endif
#endif
/*
* ===============================================================================
* Project: FEC decoder @ SW
*
* Filename: fec_decoder.cpp
*
* Description: Reads FEC frames (recognized by EtherType) from the socket
* Recognizes FEC header
* Does de-hamming (based on Cesar's with corrected table)
* Hamming parity bytes at the end of each chunk (not at the
* end of the frame )
*
* Version: 1.0
* Created: 04/09/2011
* Revision: none
* Compiler: gcc
*
* Author: Maciej Lipinski (based on test-drive.c by C.Prados)
* Company: CERN
*
* ============================================================================
*/
#include "fec.h"
#include "fec_decoder.h"
my_socket *create_socket(wr_sockaddr_t *bind_addr)
{
struct sockaddr_ll sll;
struct my_socket *s;
struct ifreq f;
int fd;
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(fd < 0)
{
perror("socket()");
return NULL;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
// Put the controller in promiscious mode, so it receives everything
strcpy(f.ifr_name, bind_addr->if_name);
if(ioctl(fd, SIOCGIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
f.ifr_flags |= IFF_PROMISC;
if(ioctl(fd, SIOCSIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
// Find the inteface index
strcpy(f.ifr_name, bind_addr->if_name);
ioctl(fd, SIOCGIFINDEX, &f);
sll.sll_ifindex = f.ifr_ifindex;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(bind_addr->ethertype);
sll.sll_halen = 6;
memcpy(sll.sll_addr, bind_addr->mac, 6);
if(bind(fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) < 0)
{
close(fd);
perror("bind()");
return NULL;
}
s=(struct my_socket*)calloc(sizeof(struct my_socket), 1);
s->if_index = f.ifr_ifindex;
memcpy(s->local_mac, f.ifr_hwaddr.sa_data, 6);
memcpy(&s->bind_addr, bind_addr, sizeof(wr_sockaddr_t));
s->fd = fd;
return (my_socket*)s;
}
int recvfrom(my_socket *sock, wr_sockaddr_t *from, void *data, size_t data_length)
{
struct my_socket *s = (struct my_socket *)sock;
struct etherpacket pkt;
struct msghdr msg;
struct iovec entry;
struct sockaddr_ll from_addr;
struct {
struct cmsghdr cm;
char control[1024];
} control;
struct cmsghdr *cmsg;
size_t len = data_length + sizeof(struct ethhdr);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
msg.msg_iovlen = 1;
entry.iov_base = &pkt;
entry.iov_len = len;
msg.msg_name = (caddr_t)&from_addr;
msg.msg_namelen = sizeof(from_addr);
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
int ret = recvmsg(s->fd, &msg, MSG_DONTWAIT);
if(ret < 0 && errno==EAGAIN) return 0; // would be blocking
if(ret == -EAGAIN) return 0;