This commit is contained in:
Kurt Moraw 2020-11-05 19:34:31 +01:00
parent 7047f17eba
commit e93019cfac
46 changed files with 0 additions and 12006 deletions

View File

@ -1,16 +0,0 @@
# Makefile for qo100modem
# =======================
CFLAGS=-O3 -Wall
LDLIBS= -L. -lpthread -lfftw3 -lm -lzip -lfftw3_threads -lsndfile -lasound -lbass -lliquid
CC=c++
PROGNAME=qo100modem
OBJ=qo100modem.o main_helper.o udp.o frame_packer.o scrambler.o crc16.o fec.o fft.o constellation.o arraysend.o audio.o liquid_if.o
all: qo100modem
qo100modem: $(OBJ)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LDLIBS)
clean:
rm -f *.o qo100modem

View File

@ -1,230 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
int AddHeader(uint8_t *data, int len, char *filename);
uint8_t *zipArray(uint8_t *data, int length, int *ziplen);
#define ZIPPED
#define TXMAXSIZE 200000
uint8_t TXarray[TXMAXSIZE];
int txlen; // total length of TXarray
int txpos; // current position in TXarray
uint8_t txtype = 0; // file type (from GUI)
uint8_t filestat = 0; // 0=first frame, 1=next frame, 2=last frame
/*
* start sending a named byte array
* data ... contents of the Byte array
* length ... length of the Byte array
* type ... type of the file (see statics)
* filename ... description of the file or its name which is send with the data
*/
int arraySend(uint8_t *data, int length, uint8_t type, char *filename)
{
if((length+55) >= TXMAXSIZE)
{
printf("file TOO long. Max is %d byte\n",TXMAXSIZE);
return 0;
}
txtype = type;
txpos = 0;
filestat = 0;
// if it is an ASCII, HTML or binary file, zip it
if(type == 3 || type == 4 || type == 5)
{
#ifdef ZIPPED
int ziplen = 0;
printf("orig len:%d\n",length);
uint8_t *zipdata = zipArray(data,length,&ziplen);
if(zipdata==NULL) return 0;
printf("zipped len:%d\n",ziplen);
// add a file header and copy to txdata for transmission
txlen = AddHeader(zipdata,ziplen,filename);
#else
txlen = AddHeader(data,length,filename);
#endif
printf("txlen:%d\n",txlen);
}
else
{
// add a file header and copy to txdata for transmission
txlen = AddHeader(data,length,filename);
}
// marker, we are sending
setSending(1);
return 1;
}
int AddHeader(uint8_t *data, int len, char *filename)
{
// make a unique ID number for this file
// we simply calc the CRC16 of the filename
uint16_t fncrc = Crc16_messagecalc(CRC16FILE, (uint8_t *)filename,strlen(filename));
// create the file header
// 50 bytes ... Filename (or first 50 chars of the filename)
// 2 bytes .... CRC16 od the filename, this is used as a file ID
// 3 bytes .... size of file
int flen = strlen(filename);
if (flen > 50) flen = 50;
memcpy(TXarray,filename,flen);
TXarray[50] = (uint8_t)((fncrc >> 8)&0xff);
TXarray[51] = (uint8_t)(fncrc&0xff);
TXarray[52] = len >> 16;
TXarray[53] = len >> 8;
TXarray[54] = len;
memcpy(TXarray+55,data,len);
return len+55;
}
// called from main() in a loop
// sends an array if specified by arraySend(..)
void doArraySend()
{
if(getSending() == 0) return;
if(filestat == 0)
{
// send first frame
printf("Start Array Send %d\n",getSending());
// preamble
int numframespreamble = 3* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1;
for(int i=0; i<numframespreamble; i++)
toGR_sendData(TXarray, txtype, filestat);
if(txlen <= PAYLOADLEN)
{
// we just need to send one frame
printf("send last frame only\n");
toGR_sendData(TXarray, txtype, 3);
toGR_sendData(TXarray, txtype, 3);
setSending(0);
}
else
{
printf("send first frame\n");
// data is longer than one PAYLOAD
toGR_sendData(TXarray, txtype, filestat);
txpos += PAYLOADLEN;
filestat = 1;
}
return;
}
if(filestat == 1)
{
// check if this is the last frame
int restlen = txlen - txpos;
if(restlen <= PAYLOADLEN)
{
// send as the last frame
printf("send last frame\n");
toGR_sendData(TXarray+txpos, txtype, 2);
toGR_sendData(TXarray+txpos, txtype, 2);
setSending(0); // transmission complete
}
else
{
// additional frame follows
printf("send next frame\n");
// from txdata send one chunk of length PAYLOADLEN
toGR_sendData(TXarray+txpos, txtype, filestat);
txpos += PAYLOADLEN;
}
return;
}
}
// make _arraySending flag thread safe
// it is called from main() and from udp-RX
pthread_mutex_t as_crit_sec;
#define AS_LOCK pthread_mutex_lock(&as_crit_sec)
#define AS_UNLOCK pthread_mutex_unlock(&as_crit_sec)
int __arraySending = 0; // 1 ... Array transmission in progress
void setSending(uint8_t onoff)
{
AS_LOCK;
__arraySending = onoff;
AS_UNLOCK;
}
int getSending()
{
int as;
AS_LOCK;
if(__arraySending != 0)
printf("__arraySending: %d\n",__arraySending);
as = __arraySending;
AS_UNLOCK;
return as;
}
#define defaultTXzipFN "tmp.zip"
uint8_t *zipArray(uint8_t *data, int length, int *ziplen)
{
int err = 0;
unlink(defaultTXzipFN); // delete existing zip file
struct zip *zp = zip_open(defaultTXzipFN, ZIP_CREATE, &err);
zip_source_t *s;
if ((s=zip_source_buffer(zp, data, length, 0)) == NULL ||
zip_file_add(zp, "my2databuffer", s, ZIP_FL_ENC_UTF_8) < 0)
{
zip_source_free(s);
printf("error adding file: %s\n", zip_strerror(zp));
return NULL;
}
zip_close(zp);
// zip file is done
// now read the file and return the buffer
#define TXMAXSIZE 200000
static uint8_t ZIPdata[TXMAXSIZE];
FILE *fp=fopen(defaultTXzipFN,"rb");
if(fp)
{
*ziplen = fread(ZIPdata,1,TXMAXSIZE,fp);
fclose(fp);
return ZIPdata;
}
return NULL;
}

View File

@ -1,245 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* audio.c ... functions to handle audio in/out via a soundcard
* uses the "BASS" library
*
* captures samples from the sound card.
* Samples are 32-bit floats in a range of -1 to +1
* get these samples from the thread safe fifo: cap_read_fifo(&floatvariable)
*
* plays samples to the sound card
* Samples are 32-bit floats in a range of -1 to +1
* play the samples by calling the thread save function: pb_write_fifo(floatsample)
*
*/
#include "qo100modem.h"
//BOOL CALLBACK RecordingCallback(HRECORD handle, const void *buffer, DWORD length, void *user);
DWORD CALLBACK WriteStream(HSTREAM handle, float *buffer, DWORD length, void *user);
int pb_read_fifo(float *data, int elements);
void close_audio();
#define CHANNELS 1 // no of channels used
HRECORD rchan = 0; // recording channel
BASS_INFO info;
HSTREAM stream = 0;
int init_audio()
{
close_audio();
printf("init audio, caprate:%d\n",caprate);
// check the correct BASS was loaded
if (HIWORD(BASS_GetVersion()) != BASSVERSION)
{
printf("An incorrect version of BASS was loaded\n");
return -1;
}
/*
// initalize default recording device
if (!BASS_RecordInit(-1))
{
printf("Can't initialize recording device\n");
return -1;
}
*/
// initialize default output device
if (!BASS_Init(-1, caprate, 0, NULL, NULL))
{
printf("Can't initialize output device\n");
return -1;
}
/*
// set capture callback
rchan = BASS_RecordStart(caprate, CHANNELS, BASS_SAMPLE_FLOAT, RecordingCallback, 0);
if (!rchan) {
printf("Can't start capturing\n");
return -1;
}
*/
// set play callback
BASS_GetInfo(&info);
stream = BASS_StreamCreate(info.freq, CHANNELS, BASS_SAMPLE_FLOAT, (STREAMPROC*)WriteStream, 0); // sample: 32 bit float
BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, 0); // no buffering for minimum latency
BASS_ChannelPlay(stream, FALSE); // start it
return 0;
}
void close_audio()
{
if(stream != 0)
{
//BASS_RecordFree();
int r = BASS_Free();
if(!r)
printf("Bass_free error: %d\n", BASS_ErrorGetCode());
stream = 0;
}
}
/*
// capture callback
// length: bytes. short=2byte, 2channels, so it requests samples*4
BOOL CALLBACK RecordingCallback(HRECORD handle, const void *buffer, DWORD length, void *user)
{
//printf("captured %ld samples\n",length/sizeof(float));
float *fbuffer = (float *)buffer;
//printf("w:%ld ",length/sizeof(float));
for(int i=0; i<(length/sizeof(float)); i+=CHANNELS)
{
//printf("%f\n",fbuffer[i]);
cap_write_fifo(fbuffer[i]);
}
return TRUE; // continue recording
}
*/
// play callback
// length: bytes. float=4byte, 2channels, so it requests samples*8
DWORD CALLBACK WriteStream(HSTREAM handle, float *buffer, DWORD length, void *user)
{
int ret = pb_read_fifo(buffer,length/sizeof(float));
if(ret == 0)
{
// fifo empty, send 00
memset(buffer,0,length);
}
return length;
}
// ================ thread safe fifo for audio callback routines ===============
pthread_mutex_t cap_crit_sec;
pthread_mutex_t pb_crit_sec;
#define CAP_LOCK pthread_mutex_lock(&cap_crit_sec)
#define CAP_UNLOCK pthread_mutex_unlock(&cap_crit_sec)
#define PB_LOCK pthread_mutex_lock(&pb_crit_sec)
#define PB_UNLOCK pthread_mutex_unlock(&pb_crit_sec)
#define AUDIO_BUFFERMAXTIME 2 // fifo can buffer this time in [s]
#define AUDIO_PLAYBACK_BUFLEN (48000 * 10) // space for 10 seconds of samples
/*#define AUDIO_CAPTURE_BUFLEN (48000*CHANNELS*AUDIO_BUFFERMAXTIME*UPSAMPLING)
int cap_wridx=0;
int cap_rdidx=0;
float cap_buffer[AUDIO_CAPTURE_BUFLEN];
*/
int pb_wridx=0;
int pb_rdidx=0;
float pb_buffer[AUDIO_PLAYBACK_BUFLEN];
/*
// write one sample into the fifo
// overwrite old data if the fifo is full
void cap_write_fifo(float sample)
{
CAP_LOCK;
cap_buffer[cap_wridx] = sample;
if(++cap_wridx >= AUDIO_CAPTURE_BUFLEN) cap_wridx = 0;
CAP_UNLOCK;
}
int cap_read_fifo(float *data)
{
CAP_LOCK;
if (cap_rdidx == cap_wridx)
{
// Fifo empty, no data available
CAP_UNLOCK;
return 0;
}
*data = cap_buffer[cap_rdidx];
if(++cap_rdidx >= AUDIO_CAPTURE_BUFLEN) cap_rdidx = 0;
CAP_UNLOCK;
return 1;
}
*/
void pb_write_fifo(float sample)
{
PB_LOCK;
// check if there is free space in fifo
if(pb_fifo_freespace(1) == 0)
{
PB_UNLOCK;
printf("************* pb fifo full\n");
return;
}
pb_buffer[pb_wridx] = sample;
if(++pb_wridx >= AUDIO_PLAYBACK_BUFLEN) pb_wridx = 0;
PB_UNLOCK;
//printf("write: pbw:%d pbr:%d\n",pb_wridx,pb_rdidx);
}
int pb_fifo_freespace(int nolock)
{
int freebuf = 0;
if(nolock == 0) PB_LOCK;
/*freebuf = AUDIO_PLAYBACK_BUFLEN - ((pb_wridx+AUDIO_PLAYBACK_BUFLEN+1 - pb_rdidx)%AUDIO_PLAYBACK_BUFLEN);
freebuf %= AUDIO_PLAYBACK_BUFLEN;*/
int elemInFifo = (pb_wridx + AUDIO_PLAYBACK_BUFLEN - pb_rdidx) % AUDIO_PLAYBACK_BUFLEN;
freebuf = AUDIO_PLAYBACK_BUFLEN - elemInFifo;
if(nolock == 0) PB_UNLOCK;
//printf("fifolen:%d check: pbw:%d pbr:%d freebuf:%d\n",AUDIO_PLAYBACK_BUFLEN,pb_wridx,pb_rdidx,freebuf);
return freebuf;
}
// read elements floats from fifo or return 0 if not enough floats are available
int pb_read_fifo(float *data, int elements)
{
//printf("pb read fifo: %d\n",elements);
PB_LOCK;
int e = AUDIO_PLAYBACK_BUFLEN - pb_fifo_freespace(1);
//if (pb_rdidx == pb_wridx)
if(e < elements)
{
// Fifo empty, no data available
PB_UNLOCK;
//printf("pb fifo empty, need:%d have:%d size:%d\n",elements,e,AUDIO_PLAYBACK_BUFLEN);
return 0;
}
for(int i=0; i<elements; i++)
{
data[i] = pb_buffer[pb_rdidx];
if(++pb_rdidx >= AUDIO_PLAYBACK_BUFLEN) pb_rdidx = 0;
}
//printf("read %d floats\n",elements);
PB_UNLOCK;
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
// functions for non-differential QPSK
// depending on the phase shift rotate a data blocks constellation
//uint8_t headerbytes[HEADERLEN] = {0x53, 0xe1, 0xa6};
// corresponds to these QPSK symbols:
// bits: 01010011 11100001 10100110
// syms: 1 1 0 3 3 2 0 1 2 2 1 2
uint8_t rxbytebuf[UDPBLOCKLEN+100]; // +100 ... reserve, just to be sure
uint8_t *convertQPSKSymToBytes(uint8_t *rxsymbols)
{
int sidx = 0;
for(int i=0; i<UDPBLOCKLEN; i++)
{
rxbytebuf[i] = rxsymbols[sidx++] << (bitsPerSymbol*3);
rxbytebuf[i] |= rxsymbols[sidx++] << (bitsPerSymbol*2);
rxbytebuf[i] |= rxsymbols[sidx++] << (bitsPerSymbol*1);
rxbytebuf[i] |= rxsymbols[sidx++] << (bitsPerSymbol*0);
}
return rxbytebuf;
}
void convertBytesToSyms_QPSK(uint8_t *bytes, uint8_t *syms, int bytenum)
{
unsigned int symidx = 0;
for(int i=0; i<bytenum; i++)
{
syms[symidx++] = (bytes[i] >> 6) & 3;
syms[symidx++] = (bytes[i] >> 4) & 3;
syms[symidx++] = (bytes[i] >> 2) & 3;
syms[symidx++] = (bytes[i] >> 0) & 3;
}
}
void rotateQPSKsyms(uint8_t *src, uint8_t *dst, int len)
{
for(int i=0; i<len; i++)
{
dst[i] = src[i] + 4;
dst[i]++;
dst[i] %= 4;
}
}
uint8_t QPSK_backbuf[UDPBLOCKLEN*8/2];
uint8_t *rotateBackQPSK(uint8_t *buf, int len, int rotations)
{
memcpy(QPSK_backbuf,buf,len);
for(unsigned int i=0; i<(unsigned int)len; i++)
{
for(int r=0; r<rotations; r++)
{
QPSK_backbuf[i] += 4;
QPSK_backbuf[i]--;
QPSK_backbuf[i] %= 4;
}
}
return QPSK_backbuf;
}
// works ONLY if number of bytes is a multiple of 3 !!!
void convertBytesToSyms_8PSK(uint8_t *bytes, uint8_t *syms, int bytenum)
{
unsigned int symidx = 0;
for(int i=0; i<bytenum; i+=3)
{
// convert next 3 bytes to 8 syms
syms[symidx++] = (bytes[0+i] >> 5) & 7;
syms[symidx++] = (bytes[0+i] >> 2) & 7;
syms[symidx++] = ((bytes[0+i] & 3) << 1) | ((bytes[1+i] >> 7) & 1);
syms[symidx++] = (bytes[1+i] >> 4) & 7;
syms[symidx++] = (bytes[1+i] >> 1) & 7;
syms[symidx++] = ((bytes[1+i] & 1) << 2) | ((bytes[2+i] >> 6) & 3);
syms[symidx++] = (bytes[2+i] >> 3) & 7;
syms[symidx++] = bytes[2+i] & 7;
}
}
void rotate8PSKsyms(uint8_t *src, uint8_t *dst, int len)
{
for(int i=0; i<len; i++)
{
dst[i] = src[i] + 8;
dst[i]++;
dst[i] %= 8;
}
}
uint8_t _8PSK_backbuf[UDPBLOCKLEN*8/3];
uint8_t *rotateBack8PSK(uint8_t *buf, int len, int rotations)
{
memcpy(_8PSK_backbuf,buf,len);
for(int i=0; i<len; i++)
{
for(int r=0; r<rotations; r++)
{
_8PSK_backbuf[i] += 8;
_8PSK_backbuf[i]--;
_8PSK_backbuf[i] %= 8;
}
}
return _8PSK_backbuf;
}
uint8_t *convert8PSKSymToBytes(uint8_t *rxsymbols, int len)
{
int sidx = 0;
// works ONLY if total frame length is a multiple of 3 !
for(int i=0; i<len; i+=3)
{
rxbytebuf[i] = rxsymbols[sidx++] << 5;
rxbytebuf[i] |= rxsymbols[sidx++] << 2;
rxbytebuf[i] |= rxsymbols[sidx] >> 1;
rxbytebuf[i+1] = rxsymbols[sidx++] << 7;
rxbytebuf[i+1] |= rxsymbols[sidx++] << 4;
rxbytebuf[i+1] |= rxsymbols[sidx++] << 1;
rxbytebuf[i+1] |= rxsymbols[sidx] >> 2;
rxbytebuf[i+2] = rxsymbols[sidx++] << 6;
rxbytebuf[i+2] |= rxsymbols[sidx++] << 3;
rxbytebuf[i+2] |= rxsymbols[sidx++];
}
return rxbytebuf;
}
void shiftleft(uint8_t *data, int shiftnum, int len)
{
for(int j=0; j<shiftnum; j++)
{
int b1=0,b2=0;
for(int i=len-1; i>=0; i--)
{
b1 = (data[i] & 0x80)>>7;
data[i] <<= 1;
data[i] |= b2;
b2 = b1;
}
}
}

View File

@ -1,83 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
// since we use a static crc register we need TWO separated registers
// for RX and TX to get it thread safe, no.2 is for file ID generation
uint16_t reg16[3] = {0xffff,0xffff}; // shift register
uint16_t Crc16_bytecalc(int rxtx, uint8_t byt)
{
uint16_t polynom = 0x8408; // generator polynom
for (int i = 0; i < 8; ++i)
{
if ((reg16[rxtx] & 1) != (byt & 1))
reg16[rxtx] = (uint16_t)((reg16[rxtx] >> 1) ^ polynom);
else
reg16[rxtx] >>= 1;
byt >>= 1;
}
return reg16[rxtx];
}
uint16_t Crc16_messagecalc(int rxtx, uint8_t *data,int len)
{
reg16[rxtx] = 0xffff;
for (int i = 0; i < len; i++)
reg16[rxtx] = Crc16_bytecalc(rxtx,data[i]);
return reg16[rxtx];
}
// =================================================================
uint32_t reg32[2] = {0xffffffff,0xffffffff}; // Shiftregister
void crc32_bytecalc(int rxtx, unsigned char byte)
{
int i;
uint32_t polynom = 0xEDB88320; // Generatorpolynom
for (i=0; i<8; ++i)
{
if ((reg32[rxtx]&1) != (byte&1))
reg32[rxtx] = (reg32[rxtx]>>1)^polynom;
else
reg32[rxtx] >>= 1;
byte >>= 1;
}
}
uint32_t crc32_messagecalc(int rxtx, unsigned char *data, int len)
{
int i;
reg32[rxtx] = 0xffffffff;
for(i=0; i<len; i++) {
crc32_bytecalc(rxtx,data[i]);
}
return reg32[rxtx] ^ 0xffffffff;
}

View File

@ -1,116 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
#include <cstddef>
#include <iostream>
#include <string>
#include "fec/schifra_galois_field.hpp"
#include "fec/schifra_galois_field_polynomial.hpp"
#include "fec/schifra_sequential_root_generator_polynomial_creator.hpp"
#include "fec/schifra_reed_solomon_encoder.hpp"
#include "fec/schifra_reed_solomon_decoder.hpp"
#include "fec/schifra_reed_solomon_block.hpp"
#include "fec/schifra_error_processes.hpp"
/* Finite Field Parameters */
const std::size_t field_descriptor = 8;
const std::size_t generator_polynomial_index = 120;
const std::size_t generator_polynomial_root_count = FECLEN;
/* Reed Solomon Code Parameters */
const std::size_t code_length = FECBLOCKLEN;
const std::size_t fec_length = FECLEN;
const std::size_t data_length = code_length - fec_length;
/* Instantiate Finite Field and Generator Polynomials */
const schifra::galois::field field(field_descriptor,
schifra::galois::primitive_polynomial_size06,
schifra::galois::primitive_polynomial06);
schifra::galois::field_polynomial generator_polynomial(field);
/* Instantiate Encoder and Decoder (Codec) */
typedef schifra::reed_solomon::encoder<code_length,fec_length,data_length> encoder_t;
typedef schifra::reed_solomon::decoder<code_length,fec_length,data_length> decoder_t;
int cfec_Reconstruct(uint8_t *darr, uint8_t *destination)
{
schifra::reed_solomon::block<code_length,fec_length> rxblock;
for(std::size_t i=0; i<code_length; i++)
rxblock.data[i] = darr[i];
const decoder_t decoder(field, generator_polynomial_index);
if (!decoder.decode(rxblock))
{
// FEC decoding not possible
return 0;
}
for(std::size_t i=0; i<data_length; i++)
destination[i] = rxblock[i];
return 1;
}
void GetFEC(uint8_t *txblock, int len, uint8_t *destArray)
{
schifra::reed_solomon::block<code_length,fec_length> block;
// fill payload into an FEC-block
for(std::size_t i=0; i<data_length; i++)
block.data[i] = txblock[i];
/* Transform message into Reed-Solomon encoded codeword */
const encoder_t encoder(field, generator_polynomial);
if (!encoder.encode(block))
{
// encoding not possible, should never happen
return;
}
// get result out of the FEC block
for(std::size_t i=0; i<code_length; i++)
destArray[i] = block[i];
}
void initFEC()
{
if (!schifra::make_sequential_root_generator_polynomial( field,
generator_polynomial_index,
generator_polynomial_root_count,
generator_polynomial))
{
std::cout << "Error - Failed to create sequential root generator!" << std::endl;
return;
}
}

View File

@ -1,115 +0,0 @@
#pragma once
/**
* zfec -- fast forward error correction library with Python interface
* https://tahoe-lafs.org/trac/zfec/
This package implements an "erasure code", or "forward error correction code".
You may use this package under the GNU General Public License, version 2 or, at your option, any later version.
*/
#include <stddef.h>
typedef unsigned char gf;
typedef struct {
unsigned long magic;
unsigned short k, n; /* parameters of the code */
gf* enc_matrix;
} fec_t;
#if defined(_MSC_VER)
// actually, some of the flavors (i.e. Enterprise) do support restrict
//#define restrict __restrict
#define restrict
#endif
/**
* param k the number of blocks required to reconstruct
* param m the total number of blocks created
*/
fec_t* fec_new(unsigned short k, unsigned short m);
void fec_free(fec_t* p);
/**
* @param inpkts the "primary blocks" i.e. the chunks of the input data
* @param fecs buffers into which the secondary blocks will be written
* @param block_nums the numbers of the desired check blocks (the id >= k) which fec_encode() will produce and store into the buffers of the fecs parameter
* @param num_block_nums the length of the block_nums array
* @param sz size of a packet in bytes
*/
void fec_encode(const fec_t* code, const gf** src, gf** fecs, size_t sz);
/**
* @param inpkts an array of packets (size k); If a primary block, i, is present then it must be at index i. Secondary blocks can appear anywhere.
* @param outpkts an array of buffers into which the reconstructed output packets will be written (only packets which are not present in the inpkts input will be reconstructed and written to outpkts)
* @param index an array of the blocknums of the packets in inpkts
* @param sz size of a packet in bytes
*/
void fec_decode(const fec_t* code, const gf** inpkts, gf** outpkts, const unsigned* index, size_t sz);
#if defined(_MSC_VER)
#define alloca _alloca
#else
#ifdef __GNUC__
#ifndef alloca
#define alloca(x) __builtin_alloca(x)
#endif
#else
#include <alloca.h>
#endif
#endif
/**
* zfec -- fast forward error correction library with Python interface
*
* Copyright (C) 2007-2008 Allmydata, Inc.
* Author: Zooko Wilcox-O'Hearn
*
* This file is part of zfec.
*
* See README.rst for licensing information.
*/
/*
* Much of this work is derived from the "fec" software by Luigi Rizzo, et
* al., the copyright notice and licence terms of which are included below
* for reference.
*
* fec.h -- forward error correction based on Vandermonde matrices
* 980614
* (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
*
* Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
* Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
*
* Modifications by Dan Rubenstein (see Modifications.txt for
* their description.
* Modifications (C) 1998 Dan Rubenstein (drubenst@cs.umass.edu)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
* 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.
*/

View File

@ -1,172 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_CRC_HPP
#define INCLUDE_SCHIFRA_CRC_HPP
#include <iostream>
#include <string>
namespace schifra
{
class crc32
{
public:
typedef std::size_t crc32_t;
crc32(const crc32_t& _key, const crc32_t& _state = 0x00)
: key(_key),
state(_state),
initial_state(_state)
{
initialize_crc32_table();
}
void reset()
{
state = initial_state;
}
void update_1byte(const unsigned char data)
{
state = (state >> 8) ^ table[data];
}
void update(const unsigned char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(data[i]);
}
}
void update(char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::string& data)
{
for (std::size_t i = 0; i < data.size(); ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::size_t& data)
{
update_1byte(static_cast<unsigned char>((data ) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 8) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 16) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 24) & 0xFF));
}
crc32_t crc()
{
return state;
}
private:
crc32& operator=(const crc32&);
void initialize_crc32_table()
{
for (std::size_t i = 0; i < 0xFF; ++i)
{
crc32_t reg = i;
for (int j = 0; j < 0x08; ++j)
{
reg = ((reg & 1) ? (reg >> 1) ^ key : reg >> 1);
}
table[i] = reg;
}
}
protected:
crc32_t key;
crc32_t state;
const crc32_t initial_state;
crc32_t table[256];
};
class schifra_crc : public crc32
{
public:
schifra_crc(const crc32_t _key)
: crc32(_key,0xAAAAAAAA)
{}
void update(const unsigned char& data)
{
state = ((state >> 8) ^ table[data]) ^ ((state << 8) ^ table[~data]);
}
void update(const unsigned char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(data[i]);
}
}
void update(const char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::string& data)
{
for (std::size_t i = 0; i < data.size(); ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::size_t& data)
{
update_1byte(static_cast<unsigned char>((data ) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 8) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 16) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 24) & 0xFF));
}
};
} // namespace schifra
#endif

View File

@ -1,109 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ECC_TRAITS_HPP
#define INCLUDE_SCHIFRA_ECC_TRAITS_HPP
namespace schifra
{
namespace traits
{
template <std::size_t code_length> struct symbol;
/* bits per symbol */
template <> struct symbol< 3> { enum {size = 2}; };
template <> struct symbol< 7> { enum {size = 3}; };
template <> struct symbol< 15> { enum {size = 4}; };
template <> struct symbol< 31> { enum {size = 5}; };
template <> struct symbol< 63> { enum {size = 6}; };
template <> struct symbol< 127> { enum {size = 7}; };
template <> struct symbol< 255> { enum {size = 8}; };
template <> struct symbol< 511> { enum {size = 9}; };
template <> struct symbol< 1023> { enum {size = 10}; };
template <> struct symbol< 2047> { enum {size = 11}; };
template <> struct symbol< 4195> { enum {size = 12}; };
template <> struct symbol< 8191> { enum {size = 13}; };
template <> struct symbol<16383> { enum {size = 14}; };
template <> struct symbol<32768> { enum {size = 15}; };
template <> struct symbol<65535> { enum {size = 16}; };
/* Credits: Modern C++ Design - Andrei Alexandrescu */
template <bool> class __static_assert__
{
public:
__static_assert__(...) {}
};
template <> class __static_assert__<true> {};
template <> class __static_assert__<false>;
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length>
struct validate_reed_solomon_code_parameters
{
private:
__static_assert__<(code_length > 0)> assertion1;
__static_assert__<(code_length > fec_length)> assertion2;
__static_assert__<(code_length > data_length)> assertion3;
__static_assert__<(code_length == fec_length + data_length)> assertion4;
};
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length>
struct validate_reed_solomon_block_parameters
{
private:
__static_assert__<(code_length > 0)> assertion1;
__static_assert__<(code_length > fec_length)> assertion2;
__static_assert__<(code_length > data_length)> assertion3;
__static_assert__<(code_length == fec_length + data_length)> assertion4;
};
template <typename Encoder, typename Decoder>
struct equivalent_encoder_decoder
{
private:
__static_assert__<(Encoder::trait::code_length == Decoder::trait::code_length)> assertion1;
__static_assert__<(Encoder::trait::fec_length == Decoder::trait::fec_length) > assertion2;
__static_assert__<(Encoder::trait::data_length == Decoder::trait::data_length)> assertion3;
};
template <std::size_t code_length_, std::size_t fec_length_, std::size_t data_length_ = code_length_ - fec_length_>
class reed_solomon_triat
{
public:
typedef validate_reed_solomon_code_parameters<code_length_,fec_length_,data_length_> vrscp;
enum { code_length = code_length_ };
enum { fec_length = fec_length_ };
enum { data_length = data_length_ };
};
}
} // namespace schifra
#endif

View File

@ -1,256 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ERASURE_CHANNEL_HPP
#define INCLUDE_SCHIFRA_ERASURE_CHANNEL_HPP
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t block_length, std::size_t fec_length>
inline void interleaved_stack_erasure_mapper(const std::vector<std::size_t>& missing_row_index,
std::vector<erasure_locations_t>& erasure_row_list)
{
erasure_row_list.resize(block_length);
for (std::size_t i = 0; i < block_length; ++i)
{
erasure_row_list[i].reserve(fec_length);
}
for (std::size_t i = 0; i < missing_row_index.size(); ++i)
{
for (std::size_t j = 0; j < block_length; ++j)
{
erasure_row_list[j].push_back(missing_row_index[i]);
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_encode(const encoder<code_length,fec_length>& encoder,
block<code_length,fec_length> (&output)[code_length])
{
for (std::size_t i = 0; i < code_length; ++i)
{
if (!encoder.encode(output[i]))
{
std::cout << "erasure_channel_stack_encode() - Error: Failed to encode block[" << i <<"]" << std::endl;
return false;
}
}
interleave<code_length,fec_length>(output);
return true;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class erasure_code_decoder : public decoder<code_length,fec_length,data_length>
{
public:
typedef decoder<code_length,fec_length,data_length> decoder_type;
typedef typename decoder_type::block_type block_type;
typedef std::vector<galois::field_polynomial> polynomial_list_type;
erasure_code_decoder(const galois::field& gfield,
const unsigned int& gen_initial_index)
: decoder<code_length,fec_length,data_length>(gfield, gen_initial_index)
{
for (std::size_t i = 0; i < code_length; ++i)
{
received_.push_back(galois::field_polynomial(decoder_type::field_, code_length - 1));
syndrome_.push_back(galois::field_polynomial(decoder_type::field_));
}
};
bool decode(block_type rsblock[code_length], const erasure_locations_t& erasure_list) const
{
if (
(!decoder_type::decoder_valid_) ||
(erasure_list.size() != fec_length)
)
{
return false;
}
for (std::size_t i = 0; i < code_length; ++i)
{
decoder_type::load_message (received_[i], rsblock [i]);
decoder_type::compute_syndrome(received_[i], syndrome_[i]);
}
erasure_locations_t erasure_locations;
decoder_type::prepare_erasure_list(erasure_locations,erasure_list);
galois::field_polynomial gamma(galois::field_element(decoder_type::field_, 1));
decoder_type::compute_gamma(gamma,erasure_locations);
std::vector<int> gamma_roots;
find_roots_in_data(gamma,gamma_roots);
polynomial_list_type omega;
for (std::size_t i = 0; i < code_length; ++i)
{
omega.push_back((gamma * syndrome_[i]) % fec_length);
}
galois::field_polynomial gamma_derivative = gamma.derivative();
for (std::size_t i = 0; i < gamma_roots.size(); ++i)
{
int error_location = static_cast<int>(gamma_roots[i]);
galois::field_symbol alpha_inverse = decoder_type::field_.alpha(error_location);
galois::field_element denominator = gamma_derivative(alpha_inverse);
if (denominator == 0)
{
return false;
}
for (std::size_t j = 0; j < code_length; ++j)
{
galois::field_element numerator = (omega[j](alpha_inverse) * decoder_type::root_exponent_table_[error_location]);
/*
A minor optimization can be made in the event the
numerator is equal to zero by not executing the
following line.
*/
rsblock[j][error_location - 1] ^= decoder_type::field_.div(numerator.poly(),denominator.poly());
}
}
return true;
}
private:
void find_roots_in_data(const galois::field_polynomial& poly, std::vector<int>& root_list) const
{
/*
Chien Search, as described in parent, but only
for locations within the data range of the message.
*/
root_list.reserve(fec_length << 1);
root_list.resize(0);
std::size_t polynomial_degree = poly.deg();
std::size_t root_list_size = 0;
for (int i = 1; i <= static_cast<int>(data_length); ++i)
{
if (0 == poly(decoder_type::field_.alpha(i)).poly())
{
root_list.push_back(i);
root_list_size++;
if (root_list_size == polynomial_degree)
{
break;
}
}
}
}
mutable polynomial_list_type received_;
mutable polynomial_list_type syndrome_;
};
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_decode(const decoder<code_length,fec_length>& general_decoder,
const erasure_locations_t& missing_row_index,
block<code_length,fec_length> (&output)[code_length])
{
if (missing_row_index.empty())
{
return true;
}
interleave<code_length,fec_length>(output);
for (std::size_t i = 0; i < code_length; ++i)
{
if (!general_decoder.decode(output[i],missing_row_index))
{
std::cout << "[2] erasure_channel_stack_decode() - Error: Failed to decode block[" << i <<"]" << std::endl;
return false;
}
}
return true;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_decode(const erasure_code_decoder<code_length,fec_length>& erasure_decoder,
const erasure_locations_t& missing_row_index,
block<code_length,fec_length> (&output)[code_length])
{
/*
Note: 1. Missing row indicies must be unique.
2. Missing row indicies must exist within
the stack's size.
3. There will be NO errors in the rows (aka output)
4. The information members of the blocks will
not be utilized.
There are NO exceptions to these rules!
*/
if (missing_row_index.empty())
{
return true;
}
else if (missing_row_index.size() == fec_length)
{
interleave<code_length,fec_length>(output);
return erasure_decoder.decode(output,missing_row_index);
}
else
return erasure_channel_stack_decode<code_length,fec_length>(
static_cast<const decoder<code_length,fec_length>&>(erasure_decoder),
missing_row_index,
output);
}
} // namespace reed_solomon
} // namepsace schifra
#endif

View File

@ -1,602 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ERROR_PROCESSES_HPP
#define INCLUDE_SCHIFRA_ERROR_PROCESSES_HPP
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <deque>
#include <vector>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
template <std::size_t code_length, std::size_t fec_length>
inline void add_erasure_error(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0xFF; // Or one can simply equate to zero
}
template <std::size_t code_length, std::size_t fec_length>
inline void add_error(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0xFF;
}
template <std::size_t code_length, std::size_t fec_length>
inline void add_error_4bit_symbol(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0x0F;
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors00(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < (fec_length >> 1); ++i)
{
add_error((start_position + scale * i) % code_length,rsblock);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_wth_mask(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const int& mask,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < (fec_length >> 1); ++i)
{
std::size_t position = (start_position + scale * i) % code_length;
rsblock[position] = (~rsblock[position]) & mask;
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < error_count; ++i)
{
add_error((start_position + scale * i) % code_length,rsblock);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_erasures00(reed_solomon::block<code_length,fec_length>& rsblock,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
for (std::size_t i = 0; i < fec_length; ++i)
{
std::size_t error_position = (start_position + scale * i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t erasure_count,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
for (std::size_t i = 0; i < erasure_count; ++i)
{
/* Note: Must make sure duplicate erasures are not added */
std::size_t error_position = (start_position + scale * i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
namespace error_mode
{
enum type
{
errors_erasures, // Errors first then erasures
erasures_errors // Erasures first then errors
};
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_errors_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
const error_mode::type& mode,
const std::size_t& start_position,
const std::size_t& erasure_count,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t between_space = 0)
{
std::size_t error_count = (fec_length - erasure_count) >> 1;
if ((2 * error_count) + erasure_count > fec_length)
{
std::cout << "corrupt_message_errors_erasures() - ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
std::size_t error_position = 0;
switch (mode)
{
case error_mode::erasures_errors : {
for (std::size_t i = 0; i < erasure_count; ++i)
{
error_position = (start_position + i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < error_count; ++i)
{
error_position = (start_position + erasure_count + between_space + i) % code_length;
add_error(error_position,rsblock);
}
}
break;
case error_mode::errors_erasures : {
for (std::size_t i = 0; i < error_count; ++i)
{
error_position = (start_position + i) % code_length;
add_error(error_position,rsblock);
}
for (std::size_t i = 0; i < erasure_count; ++i)
{
error_position = (start_position + error_count + between_space + i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
}
break;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_interleaved_errors_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& erasure_count,
reed_solomon::erasure_locations_t& erasure_list)
{
std::size_t error_count = (fec_length - erasure_count) >> 1;
if ((2 * error_count) + erasure_count > fec_length)
{
std::cout << "corrupt_message_interleaved_errors_erasures() - [1] ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
std::size_t e = 0;
std::size_t s = 0;
std::size_t i = 0;
while ((e < error_count) || (s < erasure_count) || (i < (error_count + erasure_count)))
{
std::size_t error_position = (start_position + i) % code_length;
if (((i & 0x01) == 0) && (s < erasure_count))
{
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
s++;
}
else if (((i & 0x01) == 1) && (e < error_count))
{
e++;
add_error(error_position,rsblock);
}
++i;
}
for (std::size_t j = 0; j < code_length; ++j)
{
if (erasures[j] == 1) erasure_list.push_back(j);
}
if ((2 * e) + erasure_list.size() > fec_length)
{
std::cout << "corrupt_message_interleaved_errors_erasures() - [2] ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
}
namespace details
{
template <std::size_t code_length, std::size_t fec_length, bool t>
struct corrupt_message_all_errors_segmented_impl
{
static void process(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& distance_between_blocks = 1)
{
std::size_t block_1_error_count = (fec_length >> 2);
std::size_t block_2_error_count = (fec_length >> 1) - block_1_error_count;
for (std::size_t i = 0; i < block_1_error_count; ++i)
{
add_error((start_position + i) % code_length,rsblock);
}
std::size_t new_start_position = (start_position + (block_1_error_count)) + distance_between_blocks;
for (std::size_t i = 0; i < block_2_error_count; ++i)
{
add_error((new_start_position + i) % code_length,rsblock);
}
}
};
template <std::size_t code_length, std::size_t fec_length>
struct corrupt_message_all_errors_segmented_impl<code_length,fec_length,false>
{
static void process(reed_solomon::block<code_length,fec_length>&,
const std::size_t&, const std::size_t&)
{}
};
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_segmented(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& distance_between_blocks = 1)
{
details::corrupt_message_all_errors_segmented_impl<code_length,fec_length,(fec_length > 2)>::
process(rsblock,start_position,distance_between_blocks);
}
inline bool check_for_duplicate_erasures(const std::vector<int>& erasure_list)
{
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
for (std::size_t j = i + 1; j < erasure_list.size(); ++j)
{
if (erasure_list[i] == erasure_list[j])
{
return false;
}
}
}
return true;
}
inline void dump_erasure_list(const schifra::reed_solomon::erasure_locations_t& erasure_list)
{
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
std::cout << "[" << i << "," << erasure_list[i] << "] ";
}
std::cout << std::endl;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool is_block_equivelent(const reed_solomon::block<code_length,fec_length>& rsblock,
const std::string& data,
const bool display = false,
const bool all_errors = false)
{
std::string::const_iterator it = data.begin();
bool error_found = false;
for (std::size_t i = 0; i < code_length - fec_length; ++i, ++it)
{
if (static_cast<char>(rsblock.data[i] & 0xFF) != (*it))
{
error_found = true;
if (display)
{
printf("is_block_equivelent() - Error at loc : %02d\td1: %02X\td2: %02X\n",
static_cast<unsigned int>(i),
rsblock.data[i],
static_cast<unsigned char>(*it));
}
if (!all_errors)
return false;
}
}
return !error_found;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool are_blocks_equivelent(const reed_solomon::block<code_length,fec_length>& block1,
const reed_solomon::block<code_length,fec_length>& block2,
const std::size_t span = code_length,
const bool display = false,
const bool all_errors = false)
{
bool error_found = false;
for (std::size_t i = 0; i < span; ++i)
{
if (block1[i] != block2[i])
{
error_found = true;
if (display)
{
printf("are_blocks_equivelent() - Error at loc : %02d\td1: %04X\td2: %04X\n",
static_cast<unsigned int>(i),
block1[i],
block2[i]);
}
if (!all_errors)
return false;
}
}
return !error_found;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline bool block_stacks_equivelent(const reed_solomon::block<code_length,fec_length> block_stack1[stack_size],
const reed_solomon::block<code_length,fec_length> block_stack2[stack_size])
{
for (std::size_t i = 0; i < stack_size; ++i)
{
if (!are_blocks_equivelent(block_stack1[i],block_stack2[i]))
{
return false;
}
}
return true;
}
template <std::size_t block_length, std::size_t stack_size>
inline bool block_stacks_equivelent(const reed_solomon::data_block<std::size_t,block_length> block_stack1[stack_size],
const reed_solomon::data_block<std::size_t,block_length> block_stack2[stack_size])
{
for (std::size_t i = 0; i < stack_size; ++i)
{
for (std::size_t j = 0; j < block_length; ++j)
{
if (block_stack1[i][j] != block_stack2[i][j])
{
return false;
}
}
}
return true;
}
inline void corrupt_file_with_burst_errors(const std::string& file_name,
const long& start_position,
const long& burst_length)
{
if (!schifra::fileio::file_exists(file_name))
{
std::cout << "corrupt_file() - Error: " << file_name << " does not exist!" << std::endl;
return;
}
if (static_cast<std::size_t>(start_position + burst_length) >= schifra::fileio::file_size(file_name))
{
std::cout << "corrupt_file() - Error: Burst error out of bounds." << std::endl;
return;
}
std::vector<char> data(burst_length);
std::ifstream ifile(file_name.c_str(), std::ios::in | std::ios::binary);
if (!ifile)
{
return;
}
ifile.seekg(start_position,std::ios_base::beg);
ifile.read(&data[0],burst_length);
ifile.close();
for (long i = 0; i < burst_length; ++i)
{
data[i] = ~data[i];
}
std::ofstream ofile(file_name.c_str(), std::ios::in | std::ios::out | std::ios::binary);
if (!ofile)
{
return;
}
ofile.seekp(start_position,std::ios_base::beg);
ofile.write(&data[0],burst_length);
ofile.close();
}
static const std::size_t global_random_error_index[] =
{
13, 170, 148, 66, 228, 208, 182, 92,
4, 137, 97, 99, 237, 151, 15, 0,
119, 243, 41, 222, 33, 211, 188, 5,
44, 30, 210, 111, 54, 79, 61, 223,
239, 149, 73, 115, 201, 234, 194, 62,
147, 70, 19, 49, 72, 52, 164, 29,
102, 225, 203, 153, 18, 205, 40, 217,
165, 177, 166, 134, 236, 68, 231, 154,
116, 136, 47, 240, 46, 89, 120, 183,
242, 28, 161, 226, 241, 230, 10, 131,
207, 132, 83, 171, 202, 195, 227, 206,
112, 88, 90, 146, 117, 180, 26, 78,
118, 254, 107, 110, 220, 7, 192, 187,
31, 175, 127, 209, 32, 12, 84, 128,
190, 156, 95, 105, 104, 246, 91, 215,
219, 142, 36, 186, 247, 233, 167, 133,
160, 16, 140, 169, 23, 96, 155, 235,
179, 76, 253, 103, 238, 67, 35, 121,
100, 27, 213, 58, 77, 248, 174, 39,
214, 56, 42, 200, 106, 21, 129, 114,
252, 113, 168, 53, 25, 216, 64, 232,
81, 75, 2, 224, 250, 60, 135, 204,
48, 196, 94, 63, 244, 191, 93, 126,
138, 159, 9, 85, 249, 34, 185, 163,
17, 65, 184, 82, 109, 172, 108, 69,
150, 3, 20, 221, 162, 212, 152, 59,
198, 74, 229, 55, 87, 178, 141, 199,
57, 130, 80, 173, 101, 122, 144, 51,
139, 11, 8, 125, 158, 124, 123, 37,
14, 24, 22, 43, 197, 50, 98, 6,
176, 251, 86, 218, 193, 71, 145, 1,
45, 38, 189, 143, 245, 157, 181
};
static const std::size_t error_index_size = sizeof(global_random_error_index) / sizeof(std::size_t);
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_at_index(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& error_index_start_position,
const bool display_positions = false)
{
schifra::reed_solomon::block<code_length,fec_length> tmp_rsblock = rsblock;
for (std::size_t i = 0; i < error_count; ++i)
{
std::size_t error_position = (global_random_error_index[(error_index_start_position + i) % error_index_size]) % code_length;
add_error(error_position,rsblock);
if (display_positions)
{
std::cout << "Error index: " << error_position << std::endl;
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_at_index(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& error_index_start_position,
const std::vector<std::size_t>& random_error_index,
const bool display_positions = false)
{
for (std::size_t i = 0; i < error_count; ++i)
{
std::size_t error_position = (random_error_index[(error_index_start_position + i) % random_error_index.size()]) % code_length;
add_error(error_position,rsblock);
if (display_positions)
{
std::cout << "Error index: " << error_position << std::endl;
}
}
}
inline void generate_error_index(const std::size_t index_size,
std::vector<std::size_t>& random_error_index,
std::size_t seed)
{
if (0 == seed)
{
seed = 0xA5A5A5A5;
}
::srand(static_cast<unsigned int>(seed));
std::deque<std::size_t> index_list;
for (std::size_t i = 0; i < index_size; ++i)
{
index_list.push_back(i);
}
random_error_index.reserve(index_size);
random_error_index.resize(0);
while (!index_list.empty())
{
// possibly the worst way of doing this.
std::size_t index = ::rand() % index_list.size();
random_error_index.push_back(index_list[index]);
index_list.erase(index_list.begin() + index);
}
}
} // namespace schifra
#endif

View File

@ -1,227 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_FILEIO_HPP
#define INCLUDE_SCHIFRA_FILEIO_HPP
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
#include "schifra_crc.hpp"
namespace schifra
{
namespace fileio
{
inline void read_into_vector(const std::string& file_name, std::vector<std::string>& buffer)
{
std::ifstream file(file_name.c_str());
if (!file) return;
std::string line;
while (std::getline(file,line))
{
buffer.push_back(line);
}
file.close();
}
inline void write_from_vector(const std::string& file_name, const std::vector<std::string>& buffer)
{
std::ofstream file(file_name.c_str());
if (!file) return;
std::ostream_iterator <std::string> os(file,"\n");
std::copy(buffer.begin(),buffer.end(), os);
file.close();
}
inline bool file_exists(const std::string& file_name)
{
std::ifstream file(file_name.c_str(), std::ios::binary);
return ((!file) ? false : true);
}
inline std::size_t file_size(const std::string& file_name)
{
std::ifstream file(file_name.c_str(),std::ios::binary);
if (!file) return 0;
file.seekg (0, std::ios::end);
return static_cast<std::size_t>(file.tellg());
}
inline void load_file(const std::string& file_name, std::string& buffer)
{
std::ifstream file(file_name.c_str(), std::ios::binary);
if (!file) return;
buffer.assign(std::istreambuf_iterator<char>(file),std::istreambuf_iterator<char>());
file.close();
}
inline void load_file(const std::string& file_name, char** buffer, std::size_t& buffer_size)
{
std::ifstream in_stream(file_name.c_str(),std::ios::binary);
if (!in_stream) return;
buffer_size = file_size(file_name);
*buffer = new char[buffer_size];
in_stream.read(*buffer,static_cast<std::streamsize>(buffer_size));
in_stream.close();
}
inline void write_file(const std::string& file_name, const std::string& buffer)
{
std::ofstream file(file_name.c_str(),std::ios::binary);
file << buffer;
file.close();
}
inline void write_file(const std::string& file_name, char* buffer, const std::size_t& buffer_size)
{
std::ofstream out_stream(file_name.c_str(),std::ios::binary);
if (!out_stream) return;
out_stream.write(buffer,static_cast<std::streamsize>(buffer_size));
out_stream.close();
}
inline bool copy_file(const std::string& src_file_name, const std::string& dest_file_name)
{
std::ifstream src_file(src_file_name.c_str(),std::ios::binary);
std::ofstream dest_file(dest_file_name.c_str(),std::ios::binary);
if (!src_file) return false;
if (!dest_file) return false;
const std::size_t block_size = 1024;
char buffer[block_size];
std::size_t remaining_bytes = file_size(src_file_name);
while (remaining_bytes >= block_size)
{
src_file.read(&buffer[0],static_cast<std::streamsize>(block_size));
dest_file.write(&buffer[0],static_cast<std::streamsize>(block_size));
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
src_file.read(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
dest_file.write(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
remaining_bytes = 0;
}
src_file.close();
dest_file.close();
return true;
}
inline bool files_identical(const std::string& file_name1, const std::string& file_name2)
{
std::ifstream file1(file_name1.c_str(),std::ios::binary);
std::ifstream file2(file_name2.c_str(),std::ios::binary);
if (!file1) return false;
if (!file2) return false;
if (file_size(file_name1) != file_size(file_name2)) return false;
const std::size_t block_size = 1024;
char buffer1[block_size];
char buffer2[block_size];
std::size_t remaining_bytes = file_size(file_name1);
while (remaining_bytes >= block_size)
{
file1.read(&buffer1[0],static_cast<std::streamsize>(block_size));
file2.read(&buffer2[0],static_cast<std::streamsize>(block_size));
for (std::size_t i = 0; i < block_size; ++i)
{
if (buffer1[i] != buffer2[i])
{
return false;
}
}
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
file1.read(&buffer1[0],static_cast<std::streamsize>(remaining_bytes));
file2.read(&buffer2[0],static_cast<std::streamsize>(remaining_bytes));
for (std::size_t i = 0; i < remaining_bytes; ++i)
{
if (buffer1[i] != buffer2[i])
{
return false;
}
}
remaining_bytes = 0;
}
file1.close();
file2.close();
return true;
}
inline std::size_t file_crc(crc32& crc_module, const std::string& file_name)
{
std::ifstream file(file_name.c_str(),std::ios::binary);
if (!file) return 0;
const std::size_t block_size = 1024;
char buffer[block_size];
std::size_t remaining_bytes = file_size(file_name);
crc_module.reset();
while (remaining_bytes >= block_size)
{
file.read(&buffer[0],static_cast<std::streamsize>(block_size));
crc_module.update(buffer,block_size);
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
file.read(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
crc_module.update(buffer,remaining_bytes);
remaining_bytes = 0;
}
return crc_module.crc();
}
} // namespace fileio
} // namespace schifra
#endif

View File

@ -1,518 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_HPP
#include <algorithm>
#include <iostream>
#include <vector>
#include <limits>
#include <string>
namespace schifra
{
namespace galois
{
typedef int field_symbol;
const field_symbol GFERROR = -1;
class field
{
public:
field(const int pwr, const std::size_t primpoly_deg, const unsigned int* primitive_poly);
~field();
bool operator==(const field& gf) const;
bool operator!=(const field& gf) const;
inline field_symbol index(const field_symbol value) const
{
return index_of_[value];
}
inline field_symbol alpha(const field_symbol value) const
{
return alpha_to_[value];
}
inline unsigned int size() const
{
return field_size_;
}
inline unsigned int pwr() const
{
return power_;
}
inline unsigned int mask() const
{
return field_size_;
}
inline field_symbol add(const field_symbol& a, const field_symbol& b) const
{
return (a ^ b);
}
inline field_symbol sub(const field_symbol& a, const field_symbol& b) const
{
return (a ^ b);
}
inline field_symbol normalize(field_symbol x) const
{
while (x < 0)
{
x += static_cast<field_symbol>(field_size_);
}
while (x >= static_cast<field_symbol>(field_size_))
{
x -= static_cast<field_symbol>(field_size_);
x = (x >> power_) + (x & field_size_);
}
return x;
}
inline field_symbol mul(const field_symbol& a, const field_symbol& b) const
{
#if !defined(NO_GFLUT)
return mul_table_[a][b];
#else
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] + index_of_[b])];
#endif
}
inline field_symbol div(const field_symbol& a, const field_symbol& b) const
{
#if !defined(NO_GFLUT)
return div_table_[a][b];
#else
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] - index_of_[b] + field_size_)];
#endif
}
inline field_symbol exp(const field_symbol& a, int n) const
{
#if !defined(NO_GFLUT)
if (n >= 0)
return exp_table_[a][n & field_size_];
else
{
while (n < 0) n += field_size_;
return (n ? exp_table_[a][n] : 1);
}
#else
if (a != 0)
{
if (n < 0)
{
while (n < 0) n += field_size_;
return (n ? alpha_to_[normalize(index_of_[a] * n)] : 1);
}
else if (n)
return alpha_to_[normalize(index_of_[a] * static_cast<field_symbol>(n))];
else
return 1;
}
else
return 0;
#endif
}
#ifdef LINEAR_EXP_LUT
inline field_symbol* const linear_exp(const field_symbol& a) const
{
#if !defined(NO_GFLUT)
static const field_symbol upper_bound = 2 * field_size_;
if ((a >= 0) && (a <= upper_bound))
return linear_exp_table_[a];
else
return reinterpret_cast<field_symbol*>(0);
#else
return reinterpret_cast<field_symbol*>(0);
#endif
}
#endif
inline field_symbol inverse(const field_symbol& val) const
{
#if !defined(NO_GFLUT)
return mul_inverse_[val];
#else
return alpha_to_[normalize(field_size_ - index_of_[val])];
#endif
}
inline unsigned int prim_poly_term(const unsigned int index) const
{
return prim_poly_[index];
}
friend std::ostream& operator << (std::ostream& os, const field& gf);
private:
field();
field(const field& gfield);
field& operator=(const field& gfield);
void generate_field(const unsigned int* prim_poly_);
field_symbol gen_mul (const field_symbol& a, const field_symbol& b) const;
field_symbol gen_div (const field_symbol& a, const field_symbol& b) const;
field_symbol gen_exp (const field_symbol& a, const std::size_t& n) const;
field_symbol gen_inverse (const field_symbol& val) const;
std::size_t create_array(char buffer_[],
const std::size_t& length,
const std::size_t offset,
field_symbol** array);
std::size_t create_2d_array(char buffer_[],
std::size_t row_cnt, std::size_t col_cnt,
const std::size_t offset,
field_symbol*** array);
unsigned int power_;
std::size_t prim_poly_deg_;
unsigned int field_size_;
unsigned int prim_poly_hash_;
unsigned int* prim_poly_;
field_symbol* alpha_to_; // aka exponential or anti-log
field_symbol* index_of_; // aka log
field_symbol* mul_inverse_; // multiplicative inverse
field_symbol** mul_table_;
field_symbol** div_table_;
field_symbol** exp_table_;
field_symbol** linear_exp_table_;
char* buffer_;
};
inline field::field(const int pwr, const std::size_t primpoly_deg, const unsigned int* primitive_poly)
: power_(pwr),
prim_poly_deg_(primpoly_deg),
field_size_((1 << power_) - 1)
{
alpha_to_ = new field_symbol [field_size_ + 1];
index_of_ = new field_symbol [field_size_ + 1];
#if !defined(NO_GFLUT)
#ifdef LINEAR_EXP_LUT
static const std::size_t buffer_size = ((6 * (field_size_ + 1) * (field_size_ + 1)) + ((field_size_ + 1) * 2)) * sizeof(field_symbol);
#else
static const std::size_t buffer_size = ((4 * (field_size_ + 1) * (field_size_ + 1)) + ((field_size_ + 1) * 2)) * sizeof(field_symbol);
#endif
buffer_ = new char[buffer_size];
std::size_t offset = 0;
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&mul_table_);
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&div_table_);
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&exp_table_);
#ifdef LINEAR_EXP_LUT
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1) * 2,offset,&linear_exp_table_);
#else
linear_exp_table_ = 0;
#endif
offset = create_array(buffer_,(field_size_ + 1) * 2,offset,&mul_inverse_);
#else
buffer_ = 0;
mul_table_ = 0;
div_table_ = 0;
exp_table_ = 0;
mul_inverse_ = 0;
linear_exp_table_ = 0;
#endif
prim_poly_ = new unsigned int [prim_poly_deg_ + 1];
for (unsigned int i = 0; i < (prim_poly_deg_ + 1); ++i)
{
prim_poly_[i] = primitive_poly[i];
}
prim_poly_hash_ = 0xAAAAAAAA;
for (std::size_t i = 0; i < (prim_poly_deg_ + 1); ++i)
{
prim_poly_hash_ += ((i & 1) == 0) ? ( (prim_poly_hash_ << 7) ^ primitive_poly[i] * (prim_poly_hash_ >> 3)) :
(~((prim_poly_hash_ << 11) + (primitive_poly[i] ^ (prim_poly_hash_ >> 5))));
}
generate_field(primitive_poly);
}
inline field::~field()
{
if (0 != alpha_to_) { delete [] alpha_to_; alpha_to_ = 0; }
if (0 != index_of_) { delete [] index_of_; index_of_ = 0; }
if (0 != prim_poly_) { delete [] prim_poly_; prim_poly_ = 0; }
#if !defined(NO_GFLUT)
if (0 != mul_table_) { delete [] mul_table_; mul_table_ = 0; }
if (0 != div_table_) { delete [] div_table_; div_table_ = 0; }
if (0 != exp_table_) { delete [] exp_table_; exp_table_ = 0; }
#ifdef LINEAR_EXP_LUT
if (0 != linear_exp_table_) { delete [] linear_exp_table_; linear_exp_table_ = 0; }
#endif
if (0 != buffer_) { delete [] buffer_; buffer_ = 0; }
#endif
}
inline bool field::operator==(const field& gf) const
{
return (
(this->power_ == gf.power_) &&
(this->prim_poly_hash_ == gf.prim_poly_hash_)
);
}
inline bool field::operator!=(const field& gf) const
{
return !field::operator ==(gf);
}
inline void field::generate_field(const unsigned int* prim_poly)
{
/*
Note: It is assumed that the degree of the primitive
polynomial will be equivelent to the m value as
in GF(2^m)
*/
field_symbol mask = 1;
alpha_to_[power_] = 0;
for (field_symbol i = 0; i < static_cast<field_symbol>(power_); ++i)
{
alpha_to_[i] = mask;
index_of_[alpha_to_[i]] = i;
if (prim_poly[i] != 0)
{
alpha_to_[power_] ^= mask;
}
mask <<= 1;
}
index_of_[alpha_to_[power_]] = power_;
mask >>= 1;
for (field_symbol i = power_ + 1; i < static_cast<field_symbol>(field_size_); ++i)
{
if (alpha_to_[i - 1] >= mask)
alpha_to_[i] = alpha_to_[power_] ^ ((alpha_to_[i - 1] ^ mask) << 1);
else
alpha_to_[i] = alpha_to_[i - 1] << 1;
index_of_[alpha_to_[i]] = i;
}
index_of_[0] = GFERROR;
alpha_to_[field_size_] = 1;
#if !defined(NO_GFLUT)
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
for (field_symbol j = 0; j < static_cast<field_symbol>(field_size_ + 1); ++j)
{
mul_table_[i][j] = gen_mul(i,j);
div_table_[i][j] = gen_div(i,j);
exp_table_[i][j] = gen_exp(i,j);
}
}
#ifdef LINEAR_EXP_LUT
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
for (int j = 0; j < static_cast<field_symbol>(2 * field_size_); ++j)
{
linear_exp_table_[i][j] = gen_exp(i,j);
}
}
#endif
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
mul_inverse_[i] = gen_inverse(i);
mul_inverse_[i + (field_size_ + 1)] = mul_inverse_[i];
}
#endif
}
inline field_symbol field::gen_mul(const field_symbol& a, const field_symbol& b) const
{
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] + index_of_[b])];
}
inline field_symbol field::gen_div(const field_symbol& a, const field_symbol& b) const
{
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] - index_of_[b] + field_size_)];
}
inline field_symbol field::gen_exp(const field_symbol& a, const std::size_t& n) const
{
if (a != 0)
return ((n == 0) ? 1 : alpha_to_[normalize(index_of_[a] * static_cast<field_symbol>(n))]);
else
return 0;
}
inline field_symbol field::gen_inverse(const field_symbol& val) const
{
return alpha_to_[normalize(field_size_ - index_of_[val])];
}
inline std::size_t field::create_array(char buffer[],
const std::size_t& length,
const std::size_t offset,
field_symbol** array)
{
const std::size_t row_size = length * sizeof(field_symbol);
(*array) = new(buffer + offset)field_symbol[length];
return row_size + offset;
}
inline std::size_t field::create_2d_array(char buffer[],
std::size_t row_cnt, std::size_t col_cnt,
const std::size_t offset,
field_symbol*** array)
{
const std::size_t row_size = col_cnt * sizeof(field_symbol);
char* buffer__offset = buffer + offset;
(*array) = new field_symbol* [row_cnt];
for (std::size_t i = 0; i < row_cnt; ++i)
{
(*array)[i] = new(buffer__offset + (i * row_size))field_symbol[col_cnt];
}
return (row_cnt * row_size) + offset;
}
inline std::ostream& operator << (std::ostream& os, const field& gf)
{
for (std::size_t i = 0; i < (gf.field_size_ + 1); ++i)
{
os << i << "\t" << gf.alpha_to_[i] << "\t" << gf.index_of_[i] << std::endl;
}
return os;
}
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 */
const unsigned int primitive_polynomial00[] = {1, 1, 0, 1};
const unsigned int primitive_polynomial_size00 = 4;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 1x^4*/
const unsigned int primitive_polynomial01[] = {1, 1, 0, 0, 1};
const unsigned int primitive_polynomial_size01 = 5;
/* 1x^0 + 0x^1 + 1x^2 + 0x^3 + 0x^4 + 1x^5 */
const unsigned int primitive_polynomial02[] = {1, 0, 1, 0, 0, 1};
const unsigned int primitive_polynomial_size02 = 6;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 1x^6 */
const unsigned int primitive_polynomial03[] = {1, 1, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size03 = 7;
/* 1x^0 + 0x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 1x^7 */
const unsigned int primitive_polynomial04[] = {1, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size04 = 8;
/* 1x^0 + 0x^1 + 1x^2 + 1x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 1x^8 */
const unsigned int primitive_polynomial05[] = {1, 0, 1, 1, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size05 = 9;
/* 1x^0 + 1x^1 + 1x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 1x^7 + 1x^8 */
const unsigned int primitive_polynomial06[] = {1, 1, 1, 0, 0, 0, 0, 1, 1};
const unsigned int primitive_polynomial_size06 = 9;
/* 1x^0 + 0x^1 + 0x^2 + 0x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 1x^9 */
const unsigned int primitive_polynomial07[] = {1, 0, 0, 0, 1, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size07 = 10;
/* 1x^0 + 0x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 1x^10 */
const unsigned int primitive_polynomial08[] = {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size08 = 11;
/* 1x^0 + 0x^1 + 1x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 1x^11 */
const unsigned int primitive_polynomial09[] = {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size09 = 12;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 1x^4 + 0x^5 + 1x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 1x^12 */
const unsigned int primitive_polynomial10[] = {1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size10 = 13;
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 0x^12 + 1x^13 */
const unsigned int primitive_polynomial11[] = {1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size11 = 14;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 1x^6 + 0x^7 + 0x^8 + 0x^9 + 1x^10 + 0x^11 + 0x^12 + 0x^13 + 1x^14 */
const unsigned int primitive_polynomial12[] = {1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size12 = 15;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 0x^12 + 0x^13 + 0x^14 + 1x^15 */
const unsigned int primitive_polynomial13[] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size13 = 16;
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 1x^12 + 0x^13 + 0x^14 + 0x^15 + 1x^16 */
const unsigned int primitive_polynomial14[] = {1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size14 = 17;
} // namespace galois
} // namespace schifra
#endif

View File

@ -1,277 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_ELEMENT_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_ELEMENT_HPP
#include <iostream>
#include <vector>
#include "schifra_galois_field.hpp"
namespace schifra
{
namespace galois
{
class field_element
{
public:
field_element(const field& gfield)
: field_(gfield),
poly_value_(-1)
{}
field_element(const field& gfield,const field_symbol& v)
: field_(const_cast<field&>(gfield)),
poly_value_(v)
{}
field_element(const field_element& gfe)
: field_(const_cast<field&>(gfe.field_)),
poly_value_(gfe.poly_value_)
{}
~field_element()
{}
inline field_element& operator = (const field_element& gfe)
{
if ((this != &gfe) && (&field_ == &gfe.field_))
{
poly_value_ = gfe.poly_value_;
}
return *this;
}
inline field_element& operator = (const field_symbol& v)
{
poly_value_ = v & field_.size();
return *this;
}
inline field_element& operator += (const field_element& gfe)
{
poly_value_ ^= gfe.poly_value_;
return *this;
}
inline field_element& operator += (const field_symbol& v)
{
poly_value_ ^= v;
return *this;
}
inline field_element& operator -= (const field_element& gfe)
{
*this += gfe;
return *this;
}
inline field_element& operator -= (const field_symbol& v)
{
*this += v;
return *this;
}
inline field_element& operator *= (const field_element& gfe)
{
poly_value_ = field_.mul(poly_value_, gfe.poly_value_);
return *this;
}
inline field_element& operator *= (const field_symbol& v)
{
poly_value_ = field_.mul(poly_value_, v);
return *this;
}
inline field_element& operator /= (const field_element& gfe)
{
poly_value_ = field_.div(poly_value_, gfe.poly_value_);
return *this;
}
inline field_element& operator /= (const field_symbol& v)
{
poly_value_ = field_.div(poly_value_, v);
return *this;
}
inline field_element& operator ^= (const int& n)
{
poly_value_ = field_.exp(poly_value_,n);
return *this;
}
inline bool operator == (const field_element& gfe) const
{
return ((field_ == gfe.field_) && (poly_value_ == gfe.poly_value_));
}
inline bool operator == (const field_symbol& v) const
{
return (poly_value_ == v);
}
inline bool operator != (const field_element& gfe) const
{
return ((field_ != gfe.field_) || (poly_value_ != gfe.poly_value_));
}
inline bool operator != (const field_symbol& v) const
{
return (poly_value_ != v);
}
inline bool operator < (const field_element& gfe)
{
return (poly_value_ < gfe.poly_value_);
}
inline bool operator < (const field_symbol& v)
{
return (poly_value_ < v);
}
inline bool operator > (const field_element& gfe)
{
return (poly_value_ > gfe.poly_value_);
}
inline bool operator > (const field_symbol& v)
{
return (poly_value_ > v);
}
inline field_symbol index() const
{
return field_.index(poly_value_);
}
inline field_symbol poly() const
{
return poly_value_;
}
inline field_symbol& poly()
{
return poly_value_;
}
inline const field& galois_field() const
{
return field_;
}
inline field_symbol inverse() const
{
return field_.inverse(poly_value_);
}
inline void normalize()
{
poly_value_ &= field_.size();
}
friend std::ostream& operator << (std::ostream& os, const field_element& gfe);
private:
const field& field_;
field_symbol poly_value_;
};
inline field_element operator + (const field_element& a, const field_element& b);
inline field_element operator - (const field_element& a, const field_element& b);
inline field_element operator * (const field_element& a, const field_element& b);
inline field_element operator * (const field_element& a, const field_symbol& b);
inline field_element operator * (const field_symbol& a, const field_element& b);
inline field_element operator / (const field_element& a, const field_element& b);
inline field_element operator ^ (const field_element& a, const int& b);
inline std::ostream& operator << (std::ostream& os, const field_element& gfe)
{
os << gfe.poly_value_;
return os;
}
inline field_element operator + (const field_element& a, const field_element& b)
{
field_element result = a;
result += b;
return result;
}
inline field_element operator - (const field_element& a, const field_element& b)
{
field_element result = a;
result -= b;
return result;
}
inline field_element operator * (const field_element& a, const field_element& b)
{
field_element result = a;
result *= b;
return result;
}
inline field_element operator * (const field_element& a, const field_symbol& b)
{
field_element result = a;
result *= b;
return result;
}
inline field_element operator * (const field_symbol& a, const field_element& b)
{
field_element result = b;
result *= a;
return result;
}
inline field_element operator / (const field_element& a, const field_element& b)
{
field_element result = a;
result /= b;
return result;
}
inline field_element operator ^ (const field_element& a, const int& b)
{
field_element result = a;
result ^= b;
return result;
}
} // namespace galois
} // namespace schifra
#endif

View File

@ -1,839 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_POLYNOMIAL_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_POLYNOMIAL_HPP
#include <cassert>
#include <iostream>
#include <vector>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
namespace schifra
{
namespace galois
{
class field_polynomial
{
public:
field_polynomial(const field& gfield);
field_polynomial(const field& gfield, const unsigned int& degree);
field_polynomial(const field& gfield, const unsigned int& degree, const field_element element[]);
field_polynomial(const field_polynomial& polynomial);
field_polynomial(const field_element& gfe);
~field_polynomial() {}
bool valid() const;
int deg() const;
const field& galois_field() const;
void set_degree(const unsigned int& x);
void simplify();
field_polynomial& operator = (const field_polynomial& polynomial);
field_polynomial& operator = (const field_element& element);
field_polynomial& operator += (const field_polynomial& element);
field_polynomial& operator += (const field_element& element);
field_polynomial& operator -= (const field_polynomial& element);
field_polynomial& operator -= (const field_element& element);
field_polynomial& operator *= (const field_polynomial& polynomial);
field_polynomial& operator *= (const field_element& element);
field_polynomial& operator /= (const field_polynomial& divisor);
field_polynomial& operator /= (const field_element& element);
field_polynomial& operator %= (const field_polynomial& divisor);
field_polynomial& operator %= (const unsigned int& power);
field_polynomial& operator ^= (const unsigned int& n);
field_polynomial& operator <<= (const unsigned int& n);
field_polynomial& operator >>= (const unsigned int& n);
field_element& operator[] (const std::size_t& term);
field_element operator() (const field_element& value);
field_element operator() (field_symbol value);
const field_element& operator[](const std::size_t& term) const;
const field_element operator()(const field_element& value) const;
const field_element operator()(field_symbol value) const;
bool operator==(const field_polynomial& polynomial) const;
bool operator!=(const field_polynomial& polynomial) const;
bool monic() const;
field_polynomial derivative() const;
friend std::ostream& operator << (std::ostream& os, const field_polynomial& polynomial);
private:
typedef std::vector<field_element>::iterator poly_iter;
typedef std::vector<field_element>::const_iterator const_poly_iter;
void simplify(field_polynomial& polynomial) const;
field& field_;
std::vector<field_element> poly_;
};
field_polynomial operator + (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator + (const field_polynomial& a, const field_element& b);
field_polynomial operator + (const field_element& a, const field_polynomial& b);
field_polynomial operator + (const field_polynomial& a, const field_symbol& b);
field_polynomial operator + (const field_symbol& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_element& b);
field_polynomial operator - (const field_element& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_symbol& b);
field_polynomial operator - (const field_symbol& a, const field_polynomial& b);
field_polynomial operator * (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator * (const field_element& a, const field_polynomial& b);
field_polynomial operator * (const field_polynomial& a, const field_element& b);
field_polynomial operator / (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator / (const field_polynomial& a, const field_element& b);
field_polynomial operator % (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator % (const field_polynomial& a, const unsigned int& power);
field_polynomial operator ^ (const field_polynomial& a, const int& n);
field_polynomial operator <<(const field_polynomial& a, const unsigned int& n);
field_polynomial operator >>(const field_polynomial& a, const unsigned int& n);
field_polynomial gcd(const field_polynomial& a, const field_polynomial& b);
inline field_polynomial::field_polynomial(const field& gfield)
: field_(const_cast<field&>(gfield))
{
poly_.clear();
poly_.reserve(256);
}
inline field_polynomial::field_polynomial(const field& gfield, const unsigned int& degree)
: field_(const_cast<field&>(gfield))
{
poly_.reserve(256);
poly_.resize(degree + 1,field_element(field_,0));
}
inline field_polynomial::field_polynomial(const field& gfield, const unsigned int& degree, const field_element element[])
: field_(const_cast<field&>(gfield))
{
poly_.reserve(256);
if (element != NULL)
{
/*
It is assumed that element is an array of field elements
with size/element count of degree + 1.
*/
for (unsigned int i = 0; i <= degree; ++i)
{
poly_.push_back(element[i]);
}
}
else
poly_.resize(degree + 1, field_element(field_, 0));
}
inline field_polynomial::field_polynomial(const field_polynomial& polynomial)
: field_(const_cast<field&>(polynomial.field_)),
poly_ (polynomial.poly_)
{}
inline field_polynomial::field_polynomial(const field_element& element)
: field_(const_cast<field&>(element.galois_field()))
{
poly_.resize(1,element);
}
inline bool field_polynomial::valid() const
{
return (poly_.size() > 0);
}
inline int field_polynomial::deg() const
{
return static_cast<int>(poly_.size()) - 1;
}
inline const field& field_polynomial::galois_field() const
{
return field_;
}
inline void field_polynomial::set_degree(const unsigned int& x)
{
poly_.resize(x - 1,field_element(field_,0));
}
inline field_polynomial& field_polynomial::operator = (const field_polynomial& polynomial)
{
if ((this != &polynomial) && (&field_ == &(polynomial.field_)))
{
poly_ = polynomial.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator = (const field_element& element)
{
if (&field_ == &(element.galois_field()))
{
poly_.resize(1,element);
}
return *this;
}
inline field_polynomial& field_polynomial::operator += (const field_polynomial& polynomial)
{
if (&field_ == &(polynomial.field_))
{
if (poly_.size() < polynomial.poly_.size())
{
const_poly_iter it0 = polynomial.poly_.begin();
for (poly_iter it1 = poly_.begin(); it1 != poly_.end(); ++it0, ++it1)
{
(*it1) += (*it0);
}
while (it0 != polynomial.poly_.end())
{
poly_.push_back(*it0);
++it0;
}
}
else
{
poly_iter it0 = poly_.begin();
for (const_poly_iter it1 = polynomial.poly_.begin(); it1 != polynomial.poly_.end(); ++it0, ++it1)
{
(*it0) += (*it1);
}
}
simplify(*this);
}
return *this;
}
inline field_polynomial& field_polynomial::operator += (const field_element& element)
{
poly_[0] += element;
return *this;
}
inline field_polynomial& field_polynomial::operator -= (const field_polynomial& element)
{
return (*this += element);
}
inline field_polynomial& field_polynomial::operator -= (const field_element& element)
{
poly_[0] -= element;
return *this;
}
inline field_polynomial& field_polynomial::operator *= (const field_polynomial& polynomial)
{
if (&field_ == &(polynomial.field_))
{
field_polynomial product(field_,deg() + polynomial.deg() + 1);
poly_iter result_it = product.poly_.begin();
for (poly_iter it0 = poly_.begin(); it0 != poly_.end(); ++it0)
{
poly_iter current_result_it = result_it;
for (const_poly_iter it1 = polynomial.poly_.begin(); it1 != polynomial.poly_.end(); ++it1)
{
(*current_result_it) += (*it0) * (*it1);
++current_result_it;
}
++result_it;
}
simplify(product);
poly_ = product.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator *= (const field_element& element)
{
if (field_ == element.galois_field())
{
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it)
{
(*it) *= element;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator /= (const field_polynomial& divisor)
{
if (
(&field_ == &divisor.field_) &&
(deg() >= divisor.deg()) &&
(divisor.deg() >= 0)
)
{
field_polynomial quotient (field_, deg() - divisor.deg() + 1);
field_polynomial remainder(field_, divisor.deg() - 1);
for (int i = static_cast<int>(deg()); i >= 0; i--)
{
if (i <= static_cast<int>(quotient.deg()))
{
quotient[i] = remainder[remainder.deg()] / divisor[divisor.deg()];
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1] + (quotient[i] * divisor[j]);
}
remainder[0] = poly_[i] + (quotient[i] * divisor[0]);
}
else
{
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1];
}
remainder[0] = poly_[i];
}
}
simplify(quotient);
poly_ = quotient.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator /= (const field_element& element)
{
if (field_ == element.galois_field())
{
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it)
{
(*it) /= element;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator %= (const field_polynomial& divisor)
{
if (
(field_ == divisor.field_) &&
(deg() >= divisor.deg() ) &&
(divisor.deg() >= 0 )
)
{
field_polynomial quotient (field_, deg() - divisor.deg() + 1);
field_polynomial remainder(field_, divisor.deg() - 1);
for (int i = static_cast<int>(deg()); i >= 0; i--)
{
if (i <= static_cast<int>(quotient.deg()))
{
quotient[i] = remainder[remainder.deg()] / divisor[divisor.deg()];
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1] + (quotient[i] * divisor[j]);
}
remainder[0] = poly_[i] + (quotient[i] * divisor[0]);
}
else
{
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1];
}
remainder[0] = poly_[i];
}
}
poly_ = remainder.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator %= (const unsigned int& power)
{
if (poly_.size() >= power)
{
poly_.resize(power,field_element(field_,0));
simplify(*this);
}
return *this;
}
inline field_polynomial& field_polynomial::operator ^= (const unsigned int& n)
{
field_polynomial result = *this;
for (std::size_t i = 0; i < n; ++i)
{
result *= *this;
}
*this = result;
return *this;
}
inline field_polynomial& field_polynomial::operator <<= (const unsigned int& n)
{
if (poly_.size() > 0)
{
size_t initial_size = poly_.size();
poly_.resize(poly_.size() + n, field_element(field_,0));
for (size_t i = initial_size - 1; static_cast<int>(i) >= 0; --i)
{
poly_[i + n] = poly_[i];
}
for (unsigned int i = 0; i < n; ++i)
{
poly_[i] = 0;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator >>= (const unsigned int& n)
{
if (n <= poly_.size())
{
for (unsigned int i = 0; i <= deg() - n; ++i)
{
poly_[i] = poly_[i + n];
}
poly_.resize(poly_.size() - n,field_element(field_,0));
}
else if (static_cast<int>(n) >= (deg() + 1))
{
poly_.resize(0,field_element(field_,0));
}
return *this;
}
inline const field_element& field_polynomial::operator [] (const std::size_t& term) const
{
assert(term < poly_.size());
return poly_[term];
}
inline field_element& field_polynomial::operator [] (const std::size_t& term)
{
assert(term < poly_.size());
return poly_[term];
}
inline field_element field_polynomial::operator () (const field_element& value)
{
field_element result(field_,0);
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
field_symbol value_poly_form = value.poly();
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value_poly_form,i), (*it).poly());
}
result = total_sum;
}
return result;
}
inline const field_element field_polynomial::operator () (const field_element& value) const
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
field_symbol value_poly_form = value.poly();
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value_poly_form,i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline field_element field_polynomial::operator () (field_symbol value)
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value,i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline const field_element field_polynomial::operator () (field_symbol value) const
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value, i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline bool field_polynomial::operator == (const field_polynomial& polynomial) const
{
if (field_ == polynomial.field_)
{
if (poly_.size() != polynomial.poly_.size())
return false;
else
{
const_poly_iter it0 = polynomial.poly_.begin();
for (const_poly_iter it1 = poly_.begin(); it1 != poly_.end(); ++it0, ++it1)
{
if ((*it0) != (*it1))
return false;
}
return true;
}
}
else
return false;
}
inline bool field_polynomial::operator != (const field_polynomial& polynomial) const
{
return !(*this == polynomial);
}
inline field_polynomial field_polynomial::derivative() const
{
if ((*this).poly_.size() > 1)
{
field_polynomial deriv(field_,deg());
const std::size_t upper_bound = poly_.size() - 1;
for (std::size_t i = 0; i < upper_bound; i += 2)
{
deriv.poly_[i] = poly_[i + 1];
}
simplify(deriv);
return deriv;
}
return field_polynomial(field_,0);
}
inline bool field_polynomial::monic() const
{
return (poly_[poly_.size() - 1] == static_cast<galois::field_symbol>(1));
}
inline void field_polynomial::simplify()
{
simplify(*this);
}
inline void field_polynomial::simplify(field_polynomial& polynomial) const
{
std::size_t poly_size = polynomial.poly_.size();
if ((poly_size > 0) && (polynomial.poly_.back() == 0))
{
poly_iter it = polynomial.poly_.end ();
poly_iter begin = polynomial.poly_.begin();
std::size_t count = 0;
while ((begin != it) && (*(--it) == 0))
{
++count;
}
if (0 != count)
{
polynomial.poly_.resize(poly_size - count, field_element(field_,0));
}
}
}
inline field_polynomial operator + (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result += b;
return result;
}
inline field_polynomial operator + (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result += b;
return result;
}
inline field_polynomial operator + (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result += a;
return result;
}
inline field_polynomial operator + (const field_polynomial& a, const field_symbol& b)
{
return a + field_element(a.galois_field(),b);
}
inline field_polynomial operator + (const field_symbol& a, const field_polynomial& b)
{
return b + field_element(b.galois_field(),a);
}
inline field_polynomial operator - (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result -= b;
return result;
}
inline field_polynomial operator - (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result -= b;
return result;
}
inline field_polynomial operator - (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result -= a;
return result;
}
inline field_polynomial operator - (const field_polynomial& a, const field_symbol& b)
{
return a - field_element(a.galois_field(),b);
}
inline field_polynomial operator - (const field_symbol& a, const field_polynomial& b)
{
return b - field_element(b.galois_field(),a);
}
inline field_polynomial operator * (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result *= b;
return result;
}
inline field_polynomial operator * (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result *= a;
return result;
}
inline field_polynomial operator * (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result *= b;
return result;
}
inline field_polynomial operator / (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result /= b;
return result;
}
inline field_polynomial operator / (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result /= b;
return result;
}
inline field_polynomial operator % (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result %= b;
return result;
}
inline field_polynomial operator % (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result %= n;
return result;
}
inline field_polynomial operator ^ (const field_polynomial& a, const int& n)
{
field_polynomial result = a;
result ^= n;
return result;
}
inline field_polynomial operator << (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result <<= n;
return result;
}
inline field_polynomial operator >> (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result >>= n;
return result;
}
inline field_polynomial gcd(const field_polynomial& a, const field_polynomial& b)
{
if (&a.galois_field() == &b.galois_field())
{
if ((!a.valid()) && (!b.valid()))
{
field_polynomial error_polynomial(a.galois_field());
return error_polynomial;
}
if (!a.valid()) return b;
if (!b.valid()) return a;
field_polynomial x = a % b;
field_polynomial y = b;
field_polynomial z = x;
while ((z = (y % x)).valid())
{
y = x;
x = z;
}
return x;
}
else
{
field_polynomial error_polynomial(a.galois_field());
return error_polynomial;
}
}
inline field_polynomial generate_X(const field& gfield)
{
const field_element xgfe[2] = {
galois::field_element(gfield, 0),
galois::field_element(gfield, 1)
};
field_polynomial X_(gfield,1,xgfe);
return X_;
}
inline std::ostream& operator << (std::ostream& os, const field_polynomial& polynomial)
{
if (polynomial.deg() >= 0)
{
/*
for (unsigned int i = 0; i < polynomial.poly_.size(); ++i)
{
os << polynomial.poly[i].index()
<< ((i != (polynomial.deg())) ? " " : "");
}
std::cout << " poly form: ";
*/
for (unsigned int i = 0; i < polynomial.poly_.size(); ++i)
{
os << polynomial.poly_[i].poly()
<< " "
<< "x^"
<< i
<< ((static_cast<int>(i) != (polynomial.deg())) ? " + " : "");
}
}
return os;
}
} // namespace galois
} // namespace schifra
#endif

View File

@ -1,115 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_UTILITIES_HPP
#define INCLUDE_SCHIFRA_GALOIS_UTILITIES_HPP
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <string>
#include <sstream>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
namespace schifra
{
namespace galois
{
inline std::string convert_to_string(const unsigned int& value, const unsigned int& width)
{
std::stringstream stream;
stream << std::setw(width) << std::setfill('0') << value;
return stream.str();
}
inline std::string convert_to_string(const int& value, const unsigned int& width)
{
std::stringstream stream;
stream << std::setw(width) << std::setfill('0') << value;
return stream.str();
}
inline std::string convert_to_bin(const unsigned int& value, const unsigned int& field_descriptor)
{
std::string output = std::string(field_descriptor, ' ');
for (unsigned int i = 0; i < field_descriptor; ++i)
{
output[i] = ((((value >> (field_descriptor - 1 - i)) & 1) == 1) ? '1' : '0');
}
return output;
}
inline void alpha_table(std::ostream& os, const field& gf)
{
std::vector<std::string> str_list;
for (unsigned int i = 0; i < gf.size() + 1; ++i)
{
str_list.push_back("alpha^" + convert_to_string(gf.index(i),2) + "\t" +
convert_to_bin (i,gf.pwr()) + "\t" +
convert_to_string(gf.alpha(i),2));
}
std::sort(str_list.begin(),str_list.end());
std::copy(str_list.begin(),str_list.end(),std::ostream_iterator<std::string>(os,"\n"));
}
inline void polynomial_alpha_form(std::ostream& os, const field_polynomial& polynomial)
{
for (int i = 0; i < (polynomial.deg() + 1); ++i)
{
field_symbol alpha_power = polynomial.galois_field().index(polynomial[i].poly());
if (alpha_power != 0)
os << static_cast<unsigned char>(224) << "^" << convert_to_string(alpha_power,2);
else
os << 1;
os << " * "
<< "x^"
<< i
<< ((i != (polynomial.deg())) ? " + " : "");
}
}
inline void polynomial_alpha_form(std::ostream& os, const std::string& prepend, const field_polynomial& polynomial)
{
os << prepend;
polynomial_alpha_form(os,polynomial);
os << std::endl;
}
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,201 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_BITIO_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_BITIO_HPP
#include <iostream>
namespace schifra
{
namespace reed_solomon
{
namespace bitio
{
template <std::size_t symbol_bit_count> class convert_data_to_symbol;
template <>
class convert_data_to_symbol<2>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, s_it+=4)
{
(* s_it ) = (*d_it) & 0x03;
(*(s_it + 1)) = ((*d_it) >> 2) & 0x03;
(*(s_it + 2)) = ((*d_it) >> 4) & 0x03;
(*(s_it + 3)) = ((*d_it) >> 6) & 0x03;
}
}
};
template <>
class convert_data_to_symbol<4>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, s_it+=2)
{
(* s_it ) = (*d_it) & 0x0F;
(*(s_it + 1)) = ((*d_it) >> 4) & 0x0F;
}
}
};
template <>
class convert_data_to_symbol<8>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*s_it) = (*d_it) & 0xFF;
}
}
};
template <>
class convert_data_to_symbol<16>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; i+=2, d_it+=2, ++s_it)
{
(*s_it) = (*d_it) & 0x000000FF;
(*s_it) |= (static_cast<int>((*(d_it + 1))) << 8) & 0x0000FF00;
}
}
};
template <>
class convert_data_to_symbol<24>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; i+=3, d_it+=3, ++s_it)
{
(*s_it) |= (*d_it) & 0x000000FF;
(*s_it) |= (static_cast<int>((*(d_it + 1))) << 8) & 0x0000FF00;
(*s_it) |= (static_cast<int>((*(d_it + 2))) << 16) & 0x00FF0000;
}
}
};
template <std::size_t symbol_bit_count> class convert_symbol_to_data;
template <>
class convert_symbol_to_data<4>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = (*s_it) & 0x0000000F;
(*d_it) |= ((*(s_it + 1)) & 0x0000000F) << 4;
}
}
};
template <>
class convert_symbol_to_data<8>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = static_cast<BitBlock>((*s_it) & 0xFF);
}
}
};
template <>
class convert_symbol_to_data<16>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = (*s_it) & 0xFFFF;
}
}
};
} // namespace bitio
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,382 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_BLOCK_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_BLOCK_HPP
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
struct block
{
public:
typedef galois::field_symbol symbol_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef traits::symbol<code_length> symbol;
typedef block<code_length,fec_length,data_length> block_t;
enum error_t
{
e_no_error = 0,
e_encoder_error0 = 1,
e_encoder_error1 = 2,
e_decoder_error0 = 3,
e_decoder_error1 = 4,
e_decoder_error2 = 5,
e_decoder_error3 = 6,
e_decoder_error4 = 7
};
block()
: errors_detected (0),
errors_corrected(0),
zero_numerators (0),
unrecoverable(false),
error(e_no_error)
{
traits::validate_reed_solomon_block_parameters<code_length,fec_length,data_length>();
}
block(const std::string& _data, const std::string& _fec)
: errors_detected (0),
errors_corrected(0),
zero_numerators (0),
unrecoverable(false),
error(e_no_error)
{
traits::validate_reed_solomon_block_parameters<code_length,fec_length,data_length>();
for (std::size_t i = 0; i < data_length; ++i)
{
data[i] = static_cast<galois::field_symbol>(_data[i]);
}
for (std::size_t i = 0; i < fec_length; ++i)
{
data[i + data_length] = static_cast<galois::field_symbol>(_fec[i]);
}
}
galois::field_symbol& operator[](const std::size_t& index)
{
return data[index];
}
const galois::field_symbol& operator[](const std::size_t& index) const
{
return data[index];
}
galois::field_symbol& operator()(const std::size_t& index)
{
return operator[](index);
}
galois::field_symbol& fec(const std::size_t& index)
{
return data[data_length + index];
}
bool data_to_string(std::string& data_str) const
{
if (data_str.length() != data_length)
{
return false;
}
for (std::size_t i = 0; i < data_length; ++i)
{
data_str[i] = static_cast<char>(data[i]);
}
return true;
}
bool fec_to_string(std::string& fec_str) const
{
if (fec_str.length() != fec_length)
{
return false;
}
for (std::size_t i = 0; i < fec_length; ++i)
{
fec_str[i] = static_cast<char>(data[data_length + i]);
}
return true;
}
std::string fec_to_string() const
{
std::string fec_str(fec_length,0x00);
fec_to_string(fec_str);
return fec_str;
}
void clear(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < code_length; ++i)
{
data[i] = value;
}
}
void clear_data(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < data_length; ++i)
{
data[i] = value;
}
}
void clear_fec(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < fec_length; ++i)
{
data[data_length + i] = value;
}
}
void reset(galois::field_symbol value = 0)
{
clear(value);
errors_detected = 0;
errors_corrected = 0;
zero_numerators = 0;
unrecoverable = false;
error = e_no_error;
}
template <typename BlockType>
void copy_state(const BlockType& b)
{
errors_detected = b.errors_detected;
errors_corrected = b.errors_corrected;
zero_numerators = b.zero_numerators;
unrecoverable = b.unrecoverable;
error = static_cast<error_t>(b.error);
}
inline std::string error_as_string() const
{
switch (error)
{
case e_no_error : return "No Error";
case e_encoder_error0 : return "Invalid Encoder";
case e_encoder_error1 : return "Incompatible Generator Polynomial";
case e_decoder_error0 : return "Invalid Decoder";
case e_decoder_error1 : return "Decoder Failure - Non-zero Syndrome";
case e_decoder_error2 : return "Decoder Failure - Too Many Errors/Erasures";
case e_decoder_error3 : return "Decoder Failure - Invalid Symbol Correction";
case e_decoder_error4 : return "Decoder Failure - Invalid Codeword Correction";
default : return "Invalid Error Code";
}
}
std::size_t errors_detected;
std::size_t errors_corrected;
std::size_t zero_numerators;
bool unrecoverable;
error_t error;
galois::field_symbol data[code_length];
};
template <std::size_t code_length, std::size_t fec_length>
inline void copy(const block<code_length,fec_length>& src_block, block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < code_length; ++index)
{
dest_block.data[index] = src_block.data[index];
}
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void copy(const T src_data[], block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < (code_length - fec_length); ++index, ++src_data)
{
dest_block.data[index] = static_cast<typename block<code_length,fec_length>::symbol_type>(*src_data);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void copy(const T src_data[],
const std::size_t& src_length,
block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < src_length; ++index, ++src_data)
{
dest_block.data[index] = static_cast<typename block<code_length,fec_length>::symbol_type>(*src_data);
}
}
template <std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline void copy(const block<code_length,fec_length> src_block_stack[stack_size],
block<code_length,fec_length> dest_block_stack[stack_size])
{
for (std::size_t row = 0; row < stack_size; ++row)
{
copy(src_block_stack[row], dest_block_stack[row]);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline bool copy(const T src_data[],
const std::size_t src_length,
block<code_length,fec_length> dest_block_stack[stack_size])
{
const std::size_t data_length = code_length - fec_length;
if (src_length > (stack_size * data_length))
{
return false;
}
const std::size_t row_count = src_length / data_length;
for (std::size_t row = 0; row < row_count; ++row, src_data += data_length)
{
copy(src_data, dest_block_stack[row]);
}
if ((src_length % data_length) != 0)
{
copy(src_data, src_length % data_length, dest_block_stack[row_count]);
}
return true;
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void full_copy(const block<code_length,fec_length>& src_block,
T dest_data[])
{
for (std::size_t i = 0; i < code_length; ++i, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block[i]);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline void copy(const block<code_length,fec_length> src_block_stack[stack_size],
T dest_data[])
{
const std::size_t data_length = code_length - fec_length;
for (std::size_t i = 0; i < stack_size; ++i)
{
for (std::size_t j = 0; j < data_length; ++j, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block_stack[i][j]);
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline std::ostream& operator<<(std::ostream& os, const block<code_length,fec_length>& rs_block)
{
for (std::size_t i = 0; i < code_length; ++i)
{
os << static_cast<char>(rs_block[i]);
}
return os;
}
template <typename T, std::size_t block_length>
struct data_block
{
public:
typedef T value_type;
T& operator[](const std::size_t index) { return data[index]; }
const T& operator[](const std::size_t index) const { return data[index]; }
T* begin() { return data; }
const T* begin() const { return data; }
T* end() { return data + block_length; }
const T* end() const { return data + block_length; }
void clear(T value = 0)
{
for (std::size_t i = 0; i < block_length; ++i)
{
data[i] = value;
}
}
private:
T data[block_length];
};
template <typename T, std::size_t block_length>
inline void copy(const data_block<T,block_length>& src_block, data_block<T,block_length>& dest_block)
{
for (std::size_t index = 0; index < block_length; ++index)
{
dest_block[index] = src_block[index];
}
}
template <typename T, std::size_t block_length, std::size_t stack_size>
inline void copy(const data_block<T,block_length> src_block_stack[stack_size],
data_block<T,block_length> dest_block_stack[stack_size])
{
for (std::size_t row = 0; row < stack_size; ++row)
{
copy(src_block_stack[row], dest_block_stack[row]);
}
}
template <typename T, std::size_t block_length>
inline void full_copy(const data_block<T,block_length>& src_block, T dest_data[])
{
for (std::size_t i = 0; i < block_length; ++i, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block[i]);
}
}
typedef std::vector<std::size_t> erasure_locations_t;
} // namespace reed_solomon
} // namepsace schifra
#endif

View File

@ -1,998 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_CODEC_VALIDATOR_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_CODEC_VALIDATOR_HPP
#include <cstddef>
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_ecc_traits.hpp"
#include "schifra_error_processes.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length,
std::size_t fec_length,
typename encoder_type = encoder<code_length,fec_length>,
typename decoder_type = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
class codec_validator
{
public:
typedef block<code_length,fec_length> block_type;
codec_validator(const galois::field& gf,
const unsigned int gpii,
const std::string& msg)
: field_(gf),
generator_polynomial_(galois::field_polynomial(field_)),
rs_encoder_(reinterpret_cast<encoder_type*>(0)),
rs_decoder_(reinterpret_cast<decoder_type*>(0)),
message(msg),
genpoly_initial_index_(gpii),
blocks_processed_(0),
block_failures_(0)
{
traits::equivalent_encoder_decoder<encoder_type,decoder_type>();
if (
!make_sequential_root_generator_polynomial(field_,
genpoly_initial_index_,
fec_length,
generator_polynomial_)
)
{
return;
}
rs_encoder_ = new encoder_type(field_,generator_polynomial_);
rs_decoder_ = new decoder_type(field_,genpoly_initial_index_);
if (!rs_encoder_->encode(message,rs_block_original))
{
std::cout << "codec_validator() - ERROR: Encoding process failed!" << std::endl;
return;
}
}
bool execute()
{
schifra::utils::timer timer;
timer.start();
bool result = stage1() &&
stage2() &&
stage3() &&
stage4() &&
stage5() &&
stage6() &&
stage7() &&
stage8() &&
stage9() &&
stage10() &&
stage11() &&
stage12() ;
timer.stop();
double time = timer.time();
print_codec_properties();
std::cout << "Blocks decoded: " << blocks_processed_ <<
"\tDecoding Failures: " << block_failures_ <<
"\tRate: " << ((blocks_processed_ * data_length) * 8.0) / (1048576.0 * time) << "Mbps" << std::endl;
/*
Note: The throughput rate is not only the throughput of reed solomon
encoding and decoding, but also that of the steps needed to add
simulated transmission errors to the reed solomon block such as
the calculation of the positions and additions of errors and
erasures to the reed solomon block, which normally in a true
data transmission medium would not be taken into consideration.
*/
return result;
}
~codec_validator()
{
delete rs_encoder_;
delete rs_decoder_;
}
void print_codec_properties()
{
std::cout << "Codec: RS(" << code_length << "," << data_length << "," << fec_length <<") ";
}
private:
bool stage1()
{
/* Burst Error Only Combinations */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors
(
rs_block,
error_count,
start_position,
1
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage1() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage1() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage1() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage1() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage1() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
bool stage2()
{
/* Burst Erasure Only Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_all_erasures
(
rs_block,
erasure_list,
erasure_count,
start_position,
1
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage2() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
std::cout << "stage2() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage2() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != erasure_count)
{
print_codec_properties();
std::cout << "stage2() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != erasure_count)
{
print_codec_properties();
std::cout << "stage2() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage3()
{
/* Consecutive Burst Erasure and Error Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::erasures_errors,
start_position,erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage3() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage3() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage3() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage4()
{
/* Consecutive Burst Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::errors_erasures,
start_position,
erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage4() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage4() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage4() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage5()
{
/* Distanced Burst Erasure and Error Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t between_distance = 1; between_distance <= 10; ++between_distance)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::erasures_errors,
start_position,
erasure_count,
erasure_list,
between_distance
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage5() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage5() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage5() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage6()
{
/* Distanced Burst Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t between_distance = 1; between_distance <= 10; ++between_distance)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::errors_erasures,
start_position,
erasure_count,
erasure_list,between_distance
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage6() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage6() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage6() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage7()
{
/* Intermittent Error Combinations */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t error_count = 1; error_count < (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t scale = 1; scale < 5; ++scale)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors
(
rs_block,
error_count,
start_position,
scale
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage7() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage7() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage7() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage7() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage7() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage8()
{
/* Intermittent Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t scale = 4; scale < 5; ++scale)
{
block_type rs_block = rs_block_original;
corrupt_message_all_erasures
(
rs_block,
erasure_list,
erasure_count,
start_position,
scale
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage8() - Decoding Failure! start position: " << start_position << "\t scale: " << scale << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage8() - Error Correcting Failure! start position: " << start_position << "\t scale: " << scale <<std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != (rs_block.errors_corrected + rs_block.zero_numerators))
{
print_codec_properties();
std::cout << "stage8() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected > erasure_count)
{
print_codec_properties();
std::cout << "stage8() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected > erasure_count)
{
print_codec_properties();
std::cout << "stage8() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage9()
{
/* Burst Interleaved Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_interleaved_errors_erasures
(
rs_block,
start_position,
erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage9() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage9() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage9() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage10()
{
/* Segmented Burst Errors */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t distance_between_blocks = 0; distance_between_blocks < 5; ++distance_between_blocks)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors_segmented
(
rs_block,
start_position,
distance_between_blocks
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage10() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage10() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage10() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
bool stage11()
{
/* No Errors */
const std::size_t initial_failure_count = block_failures_;
block_type rs_block = rs_block_original;
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage11() - Decoding Failure!" << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != 0)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != 0)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.unrecoverable)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
++blocks_processed_;
return (block_failures_ == initial_failure_count);
}
bool stage12()
{
/* Random Errors Only */
const std::size_t initial_failure_count = block_failures_;
std::vector<std::size_t> random_error_index;
generate_error_index((fec_length >> 1),random_error_index,0xA5A5A5A5);
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t error_index = 0; error_index < error_index_size; ++error_index)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors_at_index
(
rs_block,
error_count,
error_index,
random_error_index
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage12() - Decoding Failure! error index: " << error_index << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage12() - Error Correcting Failure! error index: " << error_index << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage12() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage12() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage12() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
protected:
codec_validator() {}
private:
codec_validator(const codec_validator&);
const codec_validator& operator=(const codec_validator&);
const galois::field& field_;
galois::field_polynomial generator_polynomial_;
encoder_type* rs_encoder_;
decoder_type* rs_decoder_;
block_type rs_block_original;
const std::string& message;
const unsigned int genpoly_initial_index_;
unsigned int blocks_processed_;
unsigned int block_failures_;
};
template <std::size_t data_length>
void create_messages(std::vector<std::string>& message_list, const bool full_test_set = false)
{
/* Various message bit patterns */
message_list.clear();
if (full_test_set)
{
for (std::size_t i = 0; i < 256; ++i)
{
message_list.push_back(std::string(data_length, static_cast<unsigned char>(i)));
}
}
else
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x00)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x5A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xF0)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x0F)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xFF)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x92)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x6D)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x77)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x7A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA7)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xE5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xEB)));
}
std::string tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0xFF);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0xFF));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0x00);
}
message_list.push_back(tmp_str);
}
template <std::size_t field_descriptor, std::size_t gen_poly_index, std::size_t code_length, std::size_t fec_length>
inline bool codec_validation_test(const std::size_t prim_poly_size,const unsigned int prim_poly[])
{
const unsigned int data_length = code_length - fec_length;
galois::field field(field_descriptor,prim_poly_size,prim_poly);
std::vector<std::string> message_list;
create_messages<data_length>(message_list);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
codec_validator<code_length,fec_length>
validator(field, gen_poly_index, message_list[i]);
if (!validator.execute())
{
return false;
}
}
return true;
}
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length>
inline bool shortened_codec_validation_test(const std::size_t prim_poly_size,const unsigned int prim_poly[])
{
typedef shortened_encoder<code_length,fec_length> encoder_type;
typedef shortened_decoder<code_length,fec_length> decoder_type;
const unsigned int data_length = code_length - fec_length;
galois::field field(field_descriptor,prim_poly_size,prim_poly);
std::vector<std::string> message_list;
create_messages<data_length>(message_list);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
codec_validator<code_length,fec_length,encoder_type,decoder_type>
validator(field,gen_poly_index,message_list[i]);
if (!validator.execute())
{
return false;
}
}
return true;
}
inline bool codec_validation_test00()
{
return codec_validation_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 22>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 24>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) ;
}
inline bool codec_validation_test01()
{
return shortened_codec_validation_test<8,120,126,14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 1 RS Code */
shortened_codec_validation_test<8,120,194,16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 2 RS Code */
shortened_codec_validation_test<8,120,219,18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 3 RS Code */
shortened_codec_validation_test<8,120,225,20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 4 RS Code */
shortened_codec_validation_test<8, 1,204,16>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* DBV/MPEG-2 TSP RS Code */
shortened_codec_validation_test<8, 1,104,27>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* Magnetic Storage Outer RS Code */
shortened_codec_validation_test<8, 1,204,12>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* Magnetic Storage Inner RS Code */
shortened_codec_validation_test<8,120, 72,10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) ; /* VDL Mode 3 RS Code */
}
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,485 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_DECODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_DECODER_HPP
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class decoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
decoder(const galois::field& field, const unsigned int& gen_initial_index = 0)
: decoder_valid_(field.size() == code_length),
field_(field),
X_(galois::generate_X(field_)),
gen_initial_index_(gen_initial_index)
{
if (decoder_valid_)
{
//Note: code_length and field size can be used interchangeably
create_lookup_tables();
}
};
const galois::field& field() const
{
return field_;
}
bool decode(block_type& rsblock) const
{
std::vector<std::size_t> erasure_list;
return decode(rsblock,erasure_list);
}
bool decode(block_type& rsblock, const erasure_locations_t& erasure_list) const
{
if ((!decoder_valid_) || (erasure_list.size() > fec_length))
{
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error0;
return false;
}
galois::field_polynomial received(field_,code_length - 1);
load_message(received,rsblock);
galois::field_polynomial syndrome(field_);
if (compute_syndrome(received,syndrome) == 0)
{
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = false;
return true;
}
galois::field_polynomial lambda(galois::field_element(field_,1));
erasure_locations_t erasure_locations;
if (!erasure_list.empty())
{
prepare_erasure_list(erasure_locations, erasure_list);
compute_gamma(lambda, erasure_locations);
}
if (erasure_list.size() < fec_length)
{
modified_berlekamp_massey_algorithm(lambda, syndrome, erasure_list.size());
}
std::vector<int> error_locations;
find_roots(lambda, error_locations);
if (0 == error_locations.size())
{
/*
Syndrome is non-zero yet no error locations have
been obtained, conclusion:
It is possible that there are MORE errrors in the
message than can be detected and corrected for this
particular code.
*/
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error1;
return false;
}
else if (((2 * error_locations.size()) - erasure_list.size()) > fec_length)
{
/*
Too many errors\erasures! 2E + S <= fec_length
L = E + S
E = L - S
2E = 2L - 2S
2E + S = 2L - 2S + S
= 2L - S
Where:
L : Error Locations
E : Errors
S : Erasures
*/
rsblock.errors_detected = error_locations.size();
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error2;
return false;
}
else
rsblock.errors_detected = error_locations.size();
return forney_algorithm(error_locations, lambda, syndrome, rsblock);
}
private:
decoder();
decoder(const decoder& dec);
decoder& operator=(const decoder& dec);
protected:
void load_message(galois::field_polynomial& received, const block_type& rsblock) const
{
/*
Load message data into received polynomial in reverse order.
*/
for (std::size_t i = 0; i < code_length; ++i)
{
received[code_length - 1 - i] = rsblock[i];
}
}
void create_lookup_tables()
{
root_exponent_table_.reserve(field_.size() + 1);
for (int i = 0; i < static_cast<int>(field_.size() + 1); ++i)
{
root_exponent_table_.push_back(field_.exp(field_.alpha(code_length - i),(1 - gen_initial_index_)));
}
syndrome_exponent_table_.reserve(fec_length);
for (int i = 0; i < static_cast<int>(fec_length); ++i)
{
syndrome_exponent_table_.push_back(field_.alpha(gen_initial_index_ + i));
}
gamma_table_.reserve(field_.size() + 1);
for (int i = 0; i < static_cast<int>(field_.size() + 1); ++i)
{
gamma_table_.push_back((1 + (X_ * galois::field_element(field_,field_.alpha(i)))));
}
}
void prepare_erasure_list(erasure_locations_t& erasure_locations, const erasure_locations_t& erasure_list) const
{
/*
Note: 1. Erasure positions must be unique.
2. Erasure positions must exist within the code block.
There are NO exceptions to these rules!
*/
erasure_locations.resize(erasure_list.size());
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
erasure_locations[i] = (code_length - 1 - erasure_list[i]);
}
}
int compute_syndrome(const galois::field_polynomial& received,
galois::field_polynomial& syndrome) const
{
int error_flag = 0;
syndrome = galois::field_polynomial(field_,fec_length - 1);
for (std::size_t i = 0; i < fec_length; ++i)
{
syndrome[i] = received(syndrome_exponent_table_[i]);
error_flag |= syndrome[i].poly();
}
return error_flag;
}
void compute_gamma(galois::field_polynomial& gamma, const erasure_locations_t& erasure_locations) const
{
for (std::size_t i = 0; i < erasure_locations.size(); ++i)
{
gamma *= gamma_table_[erasure_locations[i]];
}
}
void find_roots(const galois::field_polynomial& poly, std::vector<int>& root_list) const
{
/*
Chien Search: Find the roots of the error locator polynomial
via an exhaustive search over all non-zero elements in the
given finite field.
*/
root_list.reserve(fec_length << 1);
root_list.resize(0);
const std::size_t polynomial_degree = poly.deg();
for (int i = 1; i <= static_cast<int>(code_length); ++i)
{
if (0 == poly(field_.alpha(i)).poly())
{
root_list.push_back(i);
if (polynomial_degree == root_list.size())
{
break;
}
}
}
}
void compute_discrepancy(galois::field_element& discrepancy,
const galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
const std::size_t& l,
const std::size_t& round) const
{
/*
Compute the lambda discrepancy at the current round of BMA
*/
const std::size_t upper_bound = std::min(static_cast<int>(l), lambda.deg());
discrepancy = 0;
for (std::size_t i = 0; i <= upper_bound; ++i)
{
discrepancy += lambda[i] * syndrome[round - i];
}
}
void modified_berlekamp_massey_algorithm(galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
const std::size_t erasure_count) const
{
/*
Modified Berlekamp-Massey Algorithm
Identify the shortest length linear feed-back shift register (LFSR)
that will generate the sequence equivalent to the syndrome.
*/
int i = -1;
std::size_t l = erasure_count;
galois::field_element discrepancy(field_,0);
galois::field_polynomial previous_lambda = lambda << 1;
for (std::size_t round = erasure_count; round < fec_length; ++round)
{
compute_discrepancy(discrepancy, lambda, syndrome, l, round);
if (discrepancy != 0)
{
galois::field_polynomial tau = lambda - (discrepancy * previous_lambda);
if (static_cast<int>(l) < (static_cast<int>(round) - i))
{
const std::size_t tmp = round - i;
i = static_cast<int>(round - l);
l = tmp;
previous_lambda = lambda / discrepancy;
}
lambda = tau;
}
previous_lambda <<= 1;
}
}
bool forney_algorithm(const std::vector<int>& error_locations,
const galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
block_type& rsblock) const
{
/*
The Forney algorithm for computing the error magnitudes
*/
const galois::field_polynomial omega = (lambda * syndrome) % fec_length;
const galois::field_polynomial lambda_derivative = lambda.derivative();
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
for (std::size_t i = 0; i < error_locations.size(); ++i)
{
const unsigned int error_location = error_locations[i];
const galois::field_symbol alpha_inverse = field_.alpha(error_location);
const galois::field_symbol numerator = (omega(alpha_inverse) * root_exponent_table_[error_location]).poly();
const galois::field_symbol denominator = lambda_derivative(alpha_inverse).poly();
if (0 != numerator)
{
if (0 != denominator)
{
rsblock[error_location - 1] ^= field_.div(numerator, denominator);
rsblock.errors_corrected++;
}
else
{
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error3;
return false;
}
}
else
++rsblock.zero_numerators;
}
if (lambda.deg() == static_cast<int>(rsblock.errors_detected))
return true;
else
{
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error4;
return false;
}
}
protected:
bool decoder_valid_;
const galois::field& field_;
std::vector<galois::field_symbol> root_exponent_table_;
std::vector<galois::field_symbol> syndrome_exponent_table_;
std::vector<galois::field_polynomial> gamma_table_;
const galois::field_polynomial X_;
const unsigned int gen_initial_index_;
};
template <std::size_t code_length,
std::size_t fec_length,
std::size_t data_length = code_length - fec_length,
std::size_t natural_length = 255, // Needs to be in-sync with field size
std::size_t padding_length = natural_length - data_length - fec_length>
class shortened_decoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
shortened_decoder(const galois::field& field, const unsigned int gen_initial_index = 0)
: decoder_(field, gen_initial_index)
{}
inline bool decode(block_type& rsblock, const erasure_locations_t& erasure_list) const
{
typename natural_decoder_type::block_type block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < code_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
erasure_locations_t shifted_position_erasure_list(erasure_list.size(),0);
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
shifted_position_erasure_list[i] = erasure_list[i] + padding_length;
}
if (decoder_.decode(block, shifted_position_erasure_list))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
rsblock.copy_state(block);
return true;
}
else
{
rsblock.copy_state(block);
return false;
}
}
inline bool decode(block_type& rsblock) const
{
typename natural_decoder_type::block_type block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < code_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
if (decoder_.decode(block))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
rsblock.copy_state(block);
return true;
}
else
{
rsblock.copy_state(block);
return false;
}
}
private:
typedef decoder<natural_length,fec_length> natural_decoder_type;
const natural_decoder_type decoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,204 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_ENCODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_ENCODER_HPP
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class encoder
{
public:
typedef traits::reed_solomon_triat<code_length, fec_length,data_length> trait;
typedef block<code_length, fec_length> block_type;
encoder(const galois::field& gfield, const galois::field_polynomial& generator)
: encoder_valid_(code_length == gfield.size()),
field_(gfield),
generator_(generator)
{}
~encoder()
{}
inline bool encode(block_type& rsblock) const
{
if (!encoder_valid_)
{
rsblock.error = block_type::e_encoder_error0;
return false;
}
const galois::field_polynomial parities = msg_poly(rsblock) % generator_;
const galois::field_symbol mask = field_.mask();
if (parities.deg() == (fec_length - 1))
{
for (std::size_t i = 0; i < fec_length; ++i)
{
rsblock.fec(i) = parities[fec_length - 1 - i].poly() & mask;
}
}
else
{
/*
Note: Encoder should never branch here.
Possible issues to look for:
1. Generator polynomial degree is not equivelent to fec length
2. Field and code length are not consistent.
*/
rsblock.error = block_type::e_encoder_error1;
return false;
}
return true;
}
inline bool encode(const std::string& data, block_type& rsblock) const
{
std::string::const_iterator itr = data.begin();
const galois::field_symbol mask = field_.mask();
for (std::size_t i = 0; i < data_length; ++i, ++itr)
{
rsblock.data[i] = static_cast<typename block_type::symbol_type>(*itr) & mask;
}
return encode(rsblock);
}
private:
encoder();
encoder(const encoder& enc);
encoder& operator=(const encoder& enc);
inline galois::field_polynomial msg_poly(const block_type& rsblock) const
{
galois::field_polynomial message(field_, code_length);
for (std::size_t i = fec_length; i < code_length; ++i)
{
message[i] = rsblock.data[code_length - 1 - i];
}
return message;
}
const bool encoder_valid_;
const galois::field& field_;
const galois::field_polynomial generator_;
};
template <std::size_t code_length,
std::size_t fec_length ,
std::size_t data_length = code_length - fec_length,
std::size_t natural_length = 255, // Needs to be in-sync with field size
std::size_t padding_length = natural_length - data_length - fec_length>
class shortened_encoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
typedef block<natural_length,fec_length> short_block_t;
shortened_encoder(const galois::field& gfield,
const galois::field_polynomial& generator)
: encoder_(gfield, generator)
{}
inline bool encode(block_type& rsblock) const
{
short_block_t block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < data_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
if (encoder_.encode(block))
{
for (std::size_t i = 0; i < fec_length; ++i)
{
rsblock.fec(i) = block.fec(i);
}
return true;
}
else
return false;
}
inline bool encode(const std::string& data, block_type& rsblock) const
{
short_block_t block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < data_length; ++i)
{
block.data[padding_length + i] = data[i];
}
if (encoder_.encode(block))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
return true;
}
else
return false;
}
private:
const encoder<natural_length,fec_length> encoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,171 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_DECODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_DECODER_HPP
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class file_decoder
{
public:
typedef decoder<code_length,fec_length> decoder_type;
typedef typename decoder_type::block_type block_type;
file_decoder(const decoder_type& decoder,
const std::string& input_file_name,
const std::string& output_file_name)
: current_block_index_(0)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (remaining_bytes == 0)
{
std::cout << "reed_solomon::file_decoder() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_decoder() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_decoder() - Error: output file could not be created." << std::endl;
return;
}
current_block_index_ = 0;
while (remaining_bytes >= code_length)
{
process_complete_block(decoder,in_stream,out_stream);
remaining_bytes -= code_length;
current_block_index_++;
}
if (remaining_bytes > 0)
{
process_partial_block(decoder,in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_complete_block(const decoder_type& decoder,
std::ifstream& in_stream,
std::ofstream& out_stream)
{
in_stream.read(&buffer_[0],static_cast<std::streamsize>(code_length));
copy<char,code_length,fec_length>(buffer_,code_length,block_);
if (!decoder.decode(block_))
{
std::cout << "reed_solomon::file_decoder.process_complete_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
for (std::size_t i = 0; i < data_length; ++i)
{
buffer_[i] = static_cast<char>(block_[i]);
}
out_stream.write(&buffer_[0],static_cast<std::streamsize>(data_length));
}
inline void process_partial_block(const decoder_type& decoder,
std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t& read_amount)
{
if (read_amount <= fec_length)
{
std::cout << "reed_solomon::file_decoder.process_partial_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
in_stream.read(&buffer_[0],static_cast<std::streamsize>(read_amount));
for (std::size_t i = 0; i < (read_amount - fec_length); ++i)
{
block_.data[i] = static_cast<typename block_type::symbol_type>(buffer_[i]);
}
if ((read_amount - fec_length) < data_length)
{
for (std::size_t i = (read_amount - fec_length); i < data_length; ++i)
{
block_.data[i] = 0;
}
}
for (std::size_t i = 0; i < fec_length; ++i)
{
block_.fec(i) = static_cast<typename block_type::symbol_type>(buffer_[(read_amount - fec_length) + i]);
}
if (!decoder.decode(block_))
{
std::cout << "reed_solomon::file_decoder.process_partial_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
for (std::size_t i = 0; i < (read_amount - fec_length); ++i)
{
buffer_[i] = static_cast<char>(block_.data[i]);
}
out_stream.write(&buffer_[0],static_cast<std::streamsize>(read_amount - fec_length));
}
block_type block_;
std::size_t current_block_index_;
char buffer_[code_length];
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,138 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_ENCODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_ENCODER_HPP
#include <cstring>
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class file_encoder
{
public:
typedef encoder<code_length,fec_length> encoder_type;
typedef typename encoder_type::block_type block_type;
file_encoder(const encoder_type& encoder,
const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (remaining_bytes == 0)
{
std::cout << "reed_solomon::file_encoder() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_encoder() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_encoder() - Error: output file could not be created." << std::endl;
return;
}
std::memset(data_buffer_,0,sizeof(data_buffer_));
std::memset(fec_buffer_ ,0,sizeof(fec_buffer_ ));
while (remaining_bytes >= data_length)
{
process_block(encoder,in_stream,out_stream,data_length);
remaining_bytes -= data_length;
}
if (remaining_bytes > 0)
{
process_block(encoder,in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(const encoder_type& encoder,
std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t& read_amount)
{
in_stream.read(&data_buffer_[0],static_cast<std::streamsize>(read_amount));
for (std::size_t i = 0; i < read_amount; ++i)
{
block_.data[i] = (data_buffer_[i] & 0xFF);
}
if (read_amount < data_length)
{
for (std::size_t i = read_amount; i < data_length; ++i)
{
block_.data[i] = 0x00;
}
}
if (!encoder.encode(block_))
{
std::cout << "reed_solomon::file_encoder.process_block() - Error during encoding of block!" << std::endl;
return;
}
for (std::size_t i = 0; i < fec_length; ++i)
{
fec_buffer_[i] = static_cast<char>(block_.fec(i) & 0xFF);
}
out_stream.write(&data_buffer_[0],static_cast<std::streamsize>(read_amount));
out_stream.write(&fec_buffer_[0],fec_length);
}
block_type block_;
char data_buffer_[data_length];
char fec_buffer_[fec_length];
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,247 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_INTERLEAVER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_INTERLEAVER_HPP
#include <iostream>
#include <string>
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t block_length, std::size_t stack_size>
class file_interleaver
{
public:
file_interleaver(const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (0 == remaining_bytes)
{
std::cout << "reed_solomon::file_interleaver() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_interleaver() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_interleaver() - Error: output file could not be created." << std::endl;
return;
}
while (remaining_bytes >= (block_length * stack_size))
{
process_block(in_stream,out_stream);
remaining_bytes -= (block_length * stack_size);
}
if (remaining_bytes > 0)
{
process_incomplete_block(in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(std::ifstream& in_stream,
std::ofstream& out_stream)
{
for (std::size_t i = 0; i < stack_size; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
interleave<char,block_length,stack_size>(block_stack_);
for (std::size_t i = 0; i < stack_size; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
}
inline void process_incomplete_block(std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t amount)
{
std::size_t complete_row_count = amount / block_length;
std::size_t remainder = amount % block_length;
for (std::size_t i = 0; i < complete_row_count; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
in_stream.read(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
if (remainder == 0)
interleave<char,block_length,stack_size>(block_stack_,complete_row_count);
else
interleave<char,block_length>(block_stack_,complete_row_count + 1,remainder);
for (std::size_t i = 0; i < complete_row_count; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
out_stream.write(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
}
data_block<char,block_length> block_stack_[stack_size];
};
template <std::size_t block_length, std::size_t stack_size>
class file_deinterleaver
{
public:
file_deinterleaver(const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t input_file_size = schifra::fileio::file_size(input_file_name);
if (input_file_size == 0)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: output file could not be created." << std::endl;
return;
}
for (std::size_t i = 0; i < (input_file_size / (block_length * stack_size)); ++i)
{
process_block(in_stream,out_stream);
}
if ((input_file_size % (block_length * stack_size)) != 0)
{
process_incomplete_block(in_stream,out_stream,(input_file_size % (block_length * stack_size)));
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(std::ifstream& in_stream,
std::ofstream& out_stream)
{
for (std::size_t i = 0; i < stack_size; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
deinterleave<char,block_length,stack_size>(block_stack_);
for (std::size_t i = 0; i < stack_size; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
}
inline void process_incomplete_block(std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t amount)
{
std::size_t complete_row_count = amount / block_length;
std::size_t remainder = amount % block_length;
for (std::size_t i = 0; i < complete_row_count; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
in_stream.read(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
if (remainder == 0)
deinterleave<char,block_length>(block_stack_,complete_row_count);
else
deinterleave<char,block_length>(block_stack_,complete_row_count + 1,remainder);
for (std::size_t i = 0; i < complete_row_count; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
out_stream.write(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
}
data_block<char,block_length> block_stack_[stack_size];
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,210 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_GENERAL_CODEC_HPP
#define INCLUDE_SCHIFRA_REED_GENERAL_CODEC_HPP
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
void* create_encoder(const galois::field& field,
const std::size_t& gen_poly_index)
{
const std::size_t data_length = code_length - fec_length;
traits::validate_reed_solomon_code_parameters<code_length,fec_length,data_length>();
galois::field_polynomial gen_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
gen_polynomial)
)
{
return reinterpret_cast<void*>(0);
}
return new encoder<code_length,fec_length>(field,gen_polynomial);
}
template <std::size_t code_length, std::size_t fec_length>
void* create_decoder(const galois::field& field,
const std::size_t& gen_poly_index)
{
const std::size_t data_length = code_length - fec_length;
traits::validate_reed_solomon_code_parameters<code_length,fec_length,data_length>();
return new decoder<code_length,fec_length>(field,static_cast<unsigned int>(gen_poly_index));
}
template <std::size_t code_length, std::size_t max_fec_length = 128>
class general_codec
{
public:
general_codec(const galois::field& field,
const std::size_t& gen_poly_index)
{
for (std::size_t i = 0; i < max_fec_length; ++i)
{
encoder_[i] = 0;
decoder_[i] = 0;
}
encoder_[ 2] = create_encoder<code_length, 2>(field, gen_poly_index);
encoder_[ 4] = create_encoder<code_length, 4>(field, gen_poly_index);
encoder_[ 6] = create_encoder<code_length, 6>(field, gen_poly_index);
encoder_[ 8] = create_encoder<code_length, 8>(field, gen_poly_index);
encoder_[ 10] = create_encoder<code_length, 10>(field, gen_poly_index);
encoder_[ 12] = create_encoder<code_length, 12>(field, gen_poly_index);
encoder_[ 14] = create_encoder<code_length, 14>(field, gen_poly_index);
encoder_[ 16] = create_encoder<code_length, 16>(field, gen_poly_index);
encoder_[ 18] = create_encoder<code_length, 18>(field, gen_poly_index);
encoder_[ 20] = create_encoder<code_length, 20>(field, gen_poly_index);
encoder_[ 22] = create_encoder<code_length, 22>(field, gen_poly_index);
encoder_[ 24] = create_encoder<code_length, 24>(field, gen_poly_index);
encoder_[ 26] = create_encoder<code_length, 26>(field, gen_poly_index);
encoder_[ 28] = create_encoder<code_length, 28>(field, gen_poly_index);
encoder_[ 30] = create_encoder<code_length, 30>(field, gen_poly_index);
encoder_[ 32] = create_encoder<code_length, 32>(field, gen_poly_index);
encoder_[ 64] = create_encoder<code_length, 64>(field, gen_poly_index);
encoder_[ 80] = create_encoder<code_length, 80>(field, gen_poly_index);
encoder_[ 96] = create_encoder<code_length, 96>(field, gen_poly_index);
encoder_[128] = create_encoder<code_length,128>(field, gen_poly_index);
decoder_[ 2] = create_decoder<code_length, 2>(field, gen_poly_index);
decoder_[ 4] = create_decoder<code_length, 4>(field, gen_poly_index);
decoder_[ 6] = create_decoder<code_length, 6>(field, gen_poly_index);
decoder_[ 8] = create_decoder<code_length, 8>(field, gen_poly_index);
decoder_[ 10] = create_decoder<code_length, 10>(field, gen_poly_index);
decoder_[ 12] = create_decoder<code_length, 12>(field, gen_poly_index);
decoder_[ 14] = create_decoder<code_length, 14>(field, gen_poly_index);
decoder_[ 16] = create_decoder<code_length, 16>(field, gen_poly_index);
decoder_[ 18] = create_decoder<code_length, 18>(field, gen_poly_index);
decoder_[ 20] = create_decoder<code_length, 20>(field, gen_poly_index);
decoder_[ 22] = create_decoder<code_length, 22>(field, gen_poly_index);
decoder_[ 24] = create_decoder<code_length, 24>(field, gen_poly_index);
decoder_[ 26] = create_decoder<code_length, 26>(field, gen_poly_index);
decoder_[ 28] = create_decoder<code_length, 28>(field, gen_poly_index);
decoder_[ 30] = create_decoder<code_length, 30>(field, gen_poly_index);
decoder_[ 32] = create_decoder<code_length, 32>(field, gen_poly_index);
decoder_[ 64] = create_decoder<code_length, 64>(field, gen_poly_index);
decoder_[ 80] = create_decoder<code_length, 80>(field, gen_poly_index);
decoder_[ 96] = create_decoder<code_length, 96>(field, gen_poly_index);
decoder_[128] = create_decoder<code_length,128>(field, gen_poly_index);
}
~general_codec()
{
delete static_cast<reed_solomon::encoder<code_length, 2>*>(encoder_[ 2]);
delete static_cast<reed_solomon::encoder<code_length, 4>*>(encoder_[ 4]);
delete static_cast<reed_solomon::encoder<code_length, 6>*>(encoder_[ 6]);
delete static_cast<reed_solomon::encoder<code_length, 8>*>(encoder_[ 8]);
delete static_cast<reed_solomon::encoder<code_length, 10>*>(encoder_[ 10]);
delete static_cast<reed_solomon::encoder<code_length, 12>*>(encoder_[ 12]);
delete static_cast<reed_solomon::encoder<code_length, 14>*>(encoder_[ 14]);
delete static_cast<reed_solomon::encoder<code_length, 16>*>(encoder_[ 16]);
delete static_cast<reed_solomon::encoder<code_length, 18>*>(encoder_[ 18]);
delete static_cast<reed_solomon::encoder<code_length, 20>*>(encoder_[ 20]);
delete static_cast<reed_solomon::encoder<code_length, 22>*>(encoder_[ 22]);
delete static_cast<reed_solomon::encoder<code_length, 24>*>(encoder_[ 24]);
delete static_cast<reed_solomon::encoder<code_length, 26>*>(encoder_[ 26]);
delete static_cast<reed_solomon::encoder<code_length, 28>*>(encoder_[ 28]);
delete static_cast<reed_solomon::encoder<code_length, 30>*>(encoder_[ 30]);
delete static_cast<reed_solomon::encoder<code_length, 32>*>(encoder_[ 32]);
delete static_cast<reed_solomon::encoder<code_length, 64>*>(encoder_[ 64]);
delete static_cast<reed_solomon::encoder<code_length, 80>*>(encoder_[ 80]);
delete static_cast<reed_solomon::encoder<code_length, 96>*>(encoder_[ 96]);
delete static_cast<reed_solomon::encoder<code_length,128>*>(encoder_[128]);
delete static_cast<reed_solomon::decoder<code_length, 2>*>(decoder_[ 2]);
delete static_cast<reed_solomon::decoder<code_length, 4>*>(decoder_[ 4]);
delete static_cast<reed_solomon::decoder<code_length, 6>*>(decoder_[ 6]);
delete static_cast<reed_solomon::decoder<code_length, 8>*>(decoder_[ 8]);
delete static_cast<reed_solomon::decoder<code_length, 10>*>(decoder_[ 10]);
delete static_cast<reed_solomon::decoder<code_length, 12>*>(decoder_[ 12]);
delete static_cast<reed_solomon::decoder<code_length, 14>*>(decoder_[ 14]);
delete static_cast<reed_solomon::decoder<code_length, 16>*>(decoder_[ 16]);
delete static_cast<reed_solomon::decoder<code_length, 18>*>(decoder_[ 18]);
delete static_cast<reed_solomon::decoder<code_length, 20>*>(decoder_[ 20]);
delete static_cast<reed_solomon::decoder<code_length, 22>*>(decoder_[ 22]);
delete static_cast<reed_solomon::decoder<code_length, 24>*>(decoder_[ 24]);
delete static_cast<reed_solomon::decoder<code_length, 26>*>(decoder_[ 26]);
delete static_cast<reed_solomon::decoder<code_length, 28>*>(decoder_[ 28]);
delete static_cast<reed_solomon::decoder<code_length, 30>*>(decoder_[ 30]);
delete static_cast<reed_solomon::decoder<code_length, 32>*>(decoder_[ 32]);
delete static_cast<reed_solomon::decoder<code_length, 64>*>(decoder_[ 64]);
delete static_cast<reed_solomon::decoder<code_length, 80>*>(decoder_[ 80]);
delete static_cast<reed_solomon::decoder<code_length, 96>*>(decoder_[ 96]);
delete static_cast<reed_solomon::decoder<code_length,128>*>(decoder_[128]);
}
template <typename Block>
bool encode(Block& block) const
{
/*
cl : code length
fl : fec length
*/
typedef reed_solomon::encoder<Block::trait::code_length,Block::trait::fec_length> encoder_type;
traits::__static_assert__<(Block::trait::fec_length <= max_fec_length)>();
if (encoder_[Block::trait::fec_length] == 0)
return false;
else
return static_cast<encoder_type*>(encoder_[Block::trait::fec_length])->encode(block);
}
template <typename Block>
bool decode(Block& block) const
{
typedef reed_solomon::decoder<Block::trait::code_length,Block::trait::fec_length> decoder_type;
traits::__static_assert__<(Block::trait::fec_length <= max_fec_length)>();
if (decoder_[Block::trait::fec_length] == 0)
return false;
else
return static_cast<decoder_type*>(decoder_[Block::trait::fec_length])->decode(block);
}
private:
void* encoder_[max_fec_length + 1];
void* decoder_[max_fec_length + 1];
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,639 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_INTERLEAVING_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_INTERLEAVING_HPP
#include <cstddef>
#include <iostream>
#include <string>
#include "schifra_reed_solomon_block.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
inline void interleave(block<code_length,fec_length> (&block_stack)[code_length])
{
for (std::size_t i = 0; i < code_length; ++i)
{
for (std::size_t j = i + 1; j < code_length; ++j)
{
typename block<code_length,fec_length>::symbol_type tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void interleave(block<code_length,fec_length> (&block_stack)[row_count])
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < code_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
copy<code_length,fec_length,row_count>(auxiliary_stack,block_stack);
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void interleave(block<code_length,fec_length,row_count> (&block_stack)[row_count],
const std::size_t partial_code_length)
{
if (partial_code_length == code_length)
{
interleave<code_length,fec_length,row_count>(block_stack);
}
else
{
block<code_length,fec_length,row_count> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_code_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_code_length; index < code_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < code_length - fec_length; ++index)
{
block_stack[row].data[index] = auxiliary_stack[row].data[index];
}
for (std::size_t index = 0; index < fec_length; ++index)
{
block_stack[row].fec[index] = auxiliary_stack[row].fec[index];
}
}
for (std::size_t index = 0; index < partial_code_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> (&block_stack)[block_length])
{
for (std::size_t i = 0; i < block_length; ++i)
{
for (std::size_t j = i + 1; j < block_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void interleave(data_block<T,block_length> (&block_stack)[row_count])
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
copy<T,block_length,row_count>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void interleave(data_block<T,block_length> (&block_stack)[row_count],
const std::size_t partial_block_length)
{
if (partial_block_length == block_length)
{
interleave<T,block_length,row_count>(block_stack);
}
else
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_block_length; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> block_stack[],
const std::size_t row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> block_stack[],
const std::size_t row_count,
const std::size_t partial_block_length)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_block_length; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
delete[] auxiliary_stack;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void deinterleave(block<code_length,fec_length> (&block_stack)[row_count])
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < code_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
copy<code_length,fec_length,row_count>(auxiliary_stack,block_stack);
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void deinterleave(block<code_length,fec_length> (&block_stack)[row_count],
const std::size_t partial_code_length)
{
if (partial_code_length == code_length)
{
deinterleave<code_length,fec_length,row_count>(block_stack);
}
else
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row1 = 0;
std::size_t aux_index1 = 0;
std::size_t aux_row2 = 0;
std::size_t aux_index2 = 0;
for (std::size_t i = 0; i < partial_code_length * row_count; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == row_count)
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == code_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t i = 0; aux_index1 < code_length; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == (row_count - 1))
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == code_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < code_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_code_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> (&block_stack)[block_length])
{
data_block<T,block_length> auxiliary_stack[block_length];
for (std::size_t row = 0; row < block_length; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[index][row] = block_stack[row][index];
}
}
copy<T,block_length,block_length>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void deinterleave(data_block<T,block_length> (&block_stack)[row_count])
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
copy<T,block_length,row_count>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> block_stack[],
const std::size_t row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> block_stack[],
const std::size_t row_count,
const std::size_t partial_block_length)
{
if (row_count == 1) return;
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row1 = 0;
std::size_t aux_index1 = 0;
std::size_t aux_row2 = 0;
std::size_t aux_index2 = 0;
for (std::size_t i = 0; i < partial_block_length * row_count; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == row_count)
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == block_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t i = 0; aux_index1 < block_length; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == (row_count - 1))
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == block_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length, std::size_t skip_columns>
inline void interleave_columnskip(data_block<T,block_length>* block_stack)
{
for (std::size_t i = 0; i < block_length; ++i)
{
for (std::size_t j = i + 1; j < block_length; ++j)
{
std::size_t x1 = i + skip_columns;
std::size_t x2 = j + skip_columns;
T tmp = block_stack[i][x2];
block_stack[i][x2] = block_stack[j][x1];
block_stack[j][x1] = tmp;
}
}
}
template <typename T, std::size_t block_length, std::size_t skip_columns>
inline void interleave_columnskip(data_block<T,block_length>* block_stack, const std::size_t& row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = skip_columns;
for (std::size_t index = skip_columns; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = skip_columns;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = skip_columns; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t data_length>
inline void interleave(T* block_stack[data_length])
{
for (std::size_t i = 0; i < data_length; ++i)
{
for (std::size_t j = i + 1; j < data_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <typename T, std::size_t data_length, std::size_t skip_columns>
inline void interleave_columnskip(T* block_stack[data_length])
{
for (std::size_t i = skip_columns; i < data_length; ++i)
{
for (std::size_t j = i + 1; j < data_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,238 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_PRODUCT_CODE_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_PRODUCT_CODE_HPP
#include <cstddef>
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_reed_solomon_bitio.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class square_product_code_encoder
{
public:
typedef encoder<code_length,fec_length> encoder_type;
typedef block<code_length,fec_length> block_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef unsigned char data_type;
typedef data_type* data_ptr_type;
enum { data_size = data_length * data_length };
enum { total_size = code_length * code_length };
square_product_code_encoder(const encoder_type& enc)
: encoder_(enc)
{}
bool encode(data_ptr_type data)
{
data_ptr_type curr_data_ptr = data;
for (std::size_t row = 0; row < data_length; ++row, curr_data_ptr += data_length)
{
copy(curr_data_ptr, data_length, block_stack_[row]);
if (!encoder_.encode(block_stack_[row]))
{
return false;
}
}
block_type vertical_block;
for (std::size_t col = 0; col < code_length; ++col)
{
for (std::size_t row = 0; row < data_length; ++row)
{
vertical_block[row] = block_stack_[row][col];
}
if (!encoder_.encode(vertical_block))
{
return false;
}
for (std::size_t fec_index = 0; fec_index < fec_length; ++fec_index)
{
block_stack_[data_length + fec_index].fec(fec_index) = vertical_block.fec(fec_index);
}
}
return true;
}
bool encode_and_interleave(data_ptr_type data)
{
if (!encode(data))
{
return false;
}
interleave<code_length,fec_length>(block_stack_);
return true;
}
void output(data_ptr_type output_data)
{
for (std::size_t row = 0; row < code_length; ++row, output_data += code_length)
{
bitio::convert_symbol_to_data<traits::symbol<code_length>::size>(block_stack_[row].data,output_data,code_length);
}
}
void clear()
{
for (std::size_t i = 0; i < code_length; ++i)
{
block_stack_[i].clear();
}
}
private:
square_product_code_encoder(const square_product_code_encoder& spce);
square_product_code_encoder& operator=(const square_product_code_encoder& spce);
block_type block_stack_[code_length];
const encoder_type& encoder_;
};
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class square_product_code_decoder
{
public:
typedef decoder<code_length,fec_length> decoder_type;
typedef block<code_length,fec_length> block_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef unsigned char data_type;
typedef data_type* data_ptr_type;
enum { data_size = data_length * data_length };
enum { total_size = code_length * code_length };
square_product_code_decoder(const decoder_type& decoder)
: decoder_(decoder)
{}
void decode(data_ptr_type data)
{
copy_proxy(data);
decode_proxy();
}
void deinterleave_and_decode(data_ptr_type data)
{
copy_proxy(data);
interleave<code_length,fec_length>(block_stack_);
decode_proxy();
}
void output(data_ptr_type output_data)
{
for (std::size_t row = 0; row < data_length; ++row, output_data += data_length)
{
bitio::convert_symbol_to_data<traits::symbol<code_length>::size>(block_stack_[row].data,output_data,data_length);
}
}
void clear()
{
for (std::size_t i = 0; i < code_length; ++i)
{
block_stack_[i].clear();
}
}
private:
square_product_code_decoder(const square_product_code_decoder& spcd);
square_product_code_decoder& operator=(const square_product_code_decoder& spcd);
void copy_proxy(data_ptr_type data)
{
for (std::size_t row = 0; row < code_length; ++row, data += code_length)
{
bitio::convert_data_to_symbol<traits::symbol<code_length>::size>(data,code_length,block_stack_[row].data);
}
}
void decode_proxy()
{
bool first_iteration_failure = false;
for (std::size_t row = 0; row < data_length; ++row)
{
if (!decoder_.decode(block_stack_[row]))
{
first_iteration_failure = true;
}
}
if (!first_iteration_failure)
{
/*
Either no errors detected or all errors have
been detected and corrected.
*/
return;
}
block_type vertical_block;
for (std::size_t col = 0; col < code_length; ++col)
{
for (std::size_t row = 0; row < data_length; ++row)
{
vertical_block[row] = block_stack_[row][col];
}
decoder_.decode(vertical_block);
}
}
block_type block_stack_[code_length];
const decoder_type& decoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,411 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_SPPED_EVALUATOR_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_SPPED_EVALUATOR_HPP
#include <cstddef>
#include <cstdio>
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_file_encoder.hpp"
#include "schifra_reed_solomon_file_decoder.hpp"
#include "schifra_error_processes.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
void create_messages(const encoder<code_length,fec_length>& rs_encoder,
std::vector< block<code_length,fec_length> >& original_block_list,
const bool full_test_set = false)
{
const std::size_t data_length = code_length - fec_length;
std::vector<std::string> message_list;
if (full_test_set)
{
for (unsigned int i = 0; i < 256; ++i)
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(i)));
}
}
else
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x00)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x5A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xF0)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x0F)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xFF)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x92)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x6D)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x77)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x7A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA7)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xE5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xEB)));
}
std::string tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0xFF);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0xFF)) ;
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
block<code_length,fec_length> current_block;
rs_encoder.encode(message_list[i],current_block);
original_block_list.push_back(current_block);
}
}
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length,
typename RSEncoder = encoder<code_length,fec_length>,
typename RSDecoder = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
struct all_errors_decoder_speed_test
{
public:
all_errors_decoder_speed_test(const std::size_t prim_poly_size, const unsigned int prim_poly[])
{
galois::field field(field_descriptor,prim_poly_size,prim_poly);
galois::field_polynomial generator_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
generator_polynomial)
)
{
return;
}
RSEncoder rs_encoder(field,generator_polynomial);
RSDecoder rs_decoder(field,gen_poly_index);
std::vector< block<code_length,fec_length> > original_block;
create_messages<code_length,fec_length>(rs_encoder,original_block);
std::vector<block<code_length,fec_length> > rs_block;
std::vector<std::size_t> block_index_list;
for (std::size_t block_index = 0; block_index < original_block.size(); ++block_index)
{
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block<code_length,fec_length> block = original_block[block_index];
corrupt_message_all_errors(block,error_count,start_position,1);
rs_block.push_back(block);
block_index_list.push_back(block_index);
}
}
}
const std::size_t max_iterations = 100;
std::size_t blocks_decoded = 0;
std::size_t block_failures = 0;
schifra::utils::timer timer;
timer.start();
for (std::size_t j = 0; j < max_iterations; ++j)
{
for (std::size_t i = 0; i < rs_block.size(); ++i)
{
if (!rs_decoder.decode(rs_block[i]))
{
std::cout << "Decoding Failure!" << std::endl;
block_failures++;
}
else if (!are_blocks_equivelent(rs_block[i],original_block[block_index_list[i]]))
{
std::cout << "Error Correcting Failure!" << std::endl;
block_failures++;
}
else
blocks_decoded++;
}
}
timer.stop();
double time = timer.time();
double mbps = ((max_iterations * rs_block.size() * data_length) * 8.0) / (1048576.0 * time);
print_codec_properties();
if (block_failures == 0)
printf("Blocks decoded: %8d Time:%8.3fsec Rate:%8.3fMbps\n",
static_cast<int>(blocks_decoded),
time,
mbps);
else
std::cout << "Blocks decoded: " << blocks_decoded << "\tDecode Failures: " << block_failures <<"\tTime: " << time <<"sec\tRate: " << mbps << "Mbps" << std::endl;
}
void print_codec_properties()
{
printf("[All Errors Test] Codec: RS(%03d,%03d,%03d) ",
static_cast<int>(code_length),
static_cast<int>(data_length),
static_cast<int>(fec_length));
}
};
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length,
typename RSEncoder = encoder<code_length,fec_length>,
typename RSDecoder = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
struct all_erasures_decoder_speed_test
{
public:
all_erasures_decoder_speed_test(const std::size_t prim_poly_size, const unsigned int prim_poly[])
{
galois::field field(field_descriptor,prim_poly_size,prim_poly);
galois::field_polynomial generator_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
generator_polynomial)
)
{
return;
}
RSEncoder rs_encoder(field,generator_polynomial);
RSDecoder rs_decoder(field,gen_poly_index);
std::vector< block<code_length,fec_length> > original_block;
create_messages<code_length,fec_length>(rs_encoder,original_block);
std::vector<block<code_length,fec_length> > rs_block;
std::vector<erasure_locations_t> erasure_list;
std::vector<std::size_t> block_index_list;
for (std::size_t block_index = 0; block_index < original_block.size(); ++block_index)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block<code_length,fec_length> block = original_block[block_index];
erasure_locations_t erasures;
corrupt_message_all_erasures(block,erasures,erasure_count,start_position,1);
if (erasure_count != erasures.size())
{
std::cout << "all_erasures_decoder_speed_test() - Failed to properly generate erasures list. Details:";
std::cout << "(" << block_index << "," << erasure_count << "," << start_position << ")" << std::endl;
}
rs_block.push_back(block);
erasure_list.push_back(erasures);
block_index_list.push_back(block_index);
}
}
}
const std::size_t max_iterations = 100;
std::size_t blocks_decoded = 0;
std::size_t block_failures = 0;
schifra::utils::timer timer;
timer.start();
for (std::size_t j = 0; j < max_iterations; ++j)
{
for (std::size_t i = 0; i < rs_block.size(); ++i)
{
if (!rs_decoder.decode(rs_block[i],erasure_list[i]))
{
std::cout << "Decoding Failure!" << std::endl;
block_failures++;
}
else if (!are_blocks_equivelent(rs_block[i],original_block[block_index_list[i]]))
{
std::cout << "Error Correcting Failure!" << std::endl;
block_failures++;
}
else
blocks_decoded++;
}
}
timer.stop();
double time = timer.time();
double mbps = ((max_iterations * rs_block.size() * data_length) * 8.0) / (1048576.0 * time);
print_codec_properties();
if (block_failures == 0)
printf("Blocks decoded: %8d Time:%8.3fsec Rate:%8.3fMbps\n",
static_cast<int>(blocks_decoded),
time,
mbps);
else
std::cout << "Blocks decoded: " << blocks_decoded << "\tDecode Failures: " << block_failures <<"\tTime: " << time <<"sec\tRate: " << mbps << "Mbps" << std::endl;
}
void print_codec_properties()
{
printf("[All Erasures Test] Codec: RS(%03d,%03d,%03d) ",
static_cast<int>(code_length),
static_cast<int>(data_length),
static_cast<int>(fec_length));
}
};
void speed_test_00()
{
all_errors_decoder_speed_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 8>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 48>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
}
void speed_test_01()
{
all_erasures_decoder_speed_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 8>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 48>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
}
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -1,64 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_SEQUENTIAL_ROOT_GENERATOR_POLYNOMIAL_CREATOR_HPP
#define INCLUDE_SCHIFRA_SEQUENTIAL_ROOT_GENERATOR_POLYNOMIAL_CREATOR_HPP
#include <cstddef>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
namespace schifra
{
inline bool make_sequential_root_generator_polynomial(const galois::field& field,
const std::size_t initial_index,
const std::size_t num_elements,
galois::field_polynomial& generator_polynomial)
{
if (
(initial_index >= field.size()) ||
((initial_index + num_elements) > field.size())
)
{
return false;
}
galois::field_element alpha(field, 2);
galois::field_polynomial X = galois::generate_X(field);
generator_polynomial = galois::field_element(field, 1);
for (std::size_t i = initial_index; i < (initial_index + num_elements); ++i)
{
generator_polynomial *= (X + (alpha ^ static_cast<galois::field_symbol>(i)));
}
return true;
}
} // namespace schifra
#endif

View File

@ -1,198 +0,0 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_UTILITES_HPP
#define INCLUDE_SCHIFRA_UTILITES_HPP
#include <cstddef>
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#include <windows.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#endif
namespace schifra
{
namespace utils
{
const std::size_t high_bits_in_char[256] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
};
template <typename T>
inline std::size_t hamming_distance_element(const T v1, const T v2)
{
std::size_t distance = 0;
const unsigned char* it1 = reinterpret_cast<const unsigned char*>(&v1);
const unsigned char* it2 = reinterpret_cast<const unsigned char*>(&v2);
for (std::size_t i = 0; i < sizeof(T); ++i, ++it1, ++it2)
{
distance += high_bits_in_char[((*it1) ^ (*it2)) & 0xFF];
}
return distance;
}
inline std::size_t hamming_distance(const unsigned char data1[], const unsigned char data2[], const std::size_t length)
{
std::size_t distance = 0;
const unsigned char* it1 = data1;
const unsigned char* it2 = data2;
for (std::size_t i = 0; i < length; ++i, ++it1, ++it2)
{
distance += high_bits_in_char[((*it1) ^ (*it2)) & 0xFF];
}
return distance;
}
template <typename ForwardIterator>
inline std::size_t hamming_distance(ForwardIterator it1_begin, ForwardIterator it2_begin, ForwardIterator it1_end)
{
std::size_t distance = 0;
ForwardIterator it1 = it1_begin;
ForwardIterator it2 = it2_begin;
for (; it1 != it1_end; ++it1, ++it2)
{
distance += hamming_distance_element(*it1,*it2);
}
return distance;
}
class timer
{
public:
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
timer()
: in_use_(false)
{
QueryPerformanceFrequency(&clock_frequency_);
}
inline void start()
{
in_use_ = true;
QueryPerformanceCounter(&start_time_);
}
inline void stop()
{
QueryPerformanceCounter(&stop_time_);
in_use_ = false;
}
inline double time() const
{
return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart);
}
#else
timer()
: in_use_(false)
{
start_time_.tv_sec = 0;
start_time_.tv_usec = 0;
stop_time_.tv_sec = 0;
stop_time_.tv_usec = 0;
}
inline void start()
{
in_use_ = true;
gettimeofday(&start_time_,0);
}
inline void stop()
{
gettimeofday(&stop_time_, 0);
in_use_ = false;
}
inline unsigned long long int usec_time() const
{
if (!in_use_)
{
if (stop_time_.tv_sec >= start_time_.tv_sec)
{
return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) +
(stop_time_.tv_usec - start_time_.tv_usec);
}
else
return std::numeric_limits<unsigned long long int>::max();
}
else
return std::numeric_limits<unsigned long long int>::max();
}
inline double time() const
{
return usec_time() * 0.000001;
}
#endif
inline bool in_use() const
{
return in_use_;
}
private:
bool in_use_;
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
LARGE_INTEGER start_time_;
LARGE_INTEGER stop_time_;
LARGE_INTEGER clock_frequency_;
#else
struct timeval start_time_;
struct timeval stop_time_;
#endif
};
} // namespace utils
} // namespace schifra
#endif

View File

@ -1,140 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
#include <fftw3.h>
#include <math.h>
#define AUDIOSAMPLERATE 8000
double *din = NULL; // input data for fft
fftw_complex *cpout = NULL; // ouput data from fft
fftw_plan plan = NULL;
#define fft_rate (AUDIOSAMPLERATE / 10) // resolution: 10 Hz
int fftidx = 0;
int fftcnt = fft_rate/2+1; // number of output values
uint16_t fftout[AUDIOSAMPLERATE / 10/2+1];
uint16_t *make_waterfall(uint8_t *pdata, int len, int *retlen)
{
int fftrdy = 0;
// get the real sample in float (imag is not required for the FFT)
int re=0;
// GR sends 8 Bytes containing 4x 0x000003e8 (marker) and 4x input-samples (real integer)
#define dlen 8
static uint8_t rbuf[dlen];
for(int i=0; i<len; i++)
{
// insert new byte in rbuf
for(int sh = (dlen-1); sh > 0; sh--)
rbuf[sh] = rbuf[sh - 1];
rbuf[0] = pdata[i];
// check for BIG/LITTLE endian
if(rbuf[0] == 0 && rbuf[1] == 0 && rbuf[2] == 3 && rbuf[3] == 0xe8)
{
re = rbuf[4];
re <<= 24;
re += rbuf[5];
re <<= 16;
re += rbuf[6];
re <<= 8;
re += rbuf[7];
}
else if(rbuf[0] == 0xe8 && rbuf[1] == 3 && rbuf[2] == 0 && rbuf[3] == 0)
{
re = rbuf[7];
re <<= 24;
re += rbuf[6];
re <<= 16;
re += rbuf[5];
re <<= 8;
re += rbuf[4];
}
else
continue;
// the value was scaled in GR by 2^24 = 16777216
// in order to send it in an INT
// undo this scaling
float fre = (float)re / 16777216;
// fre are the float samples
// fill into the fft input buffer
din[fftidx++] = fre;
if(fftidx == fft_rate)
{
fftidx = 0;
// the fft buffer is full, execute the FFT
fftw_execute(plan);
for (int j = 0; j < fftcnt; j++)
{
// calculate absolute value (magnitute without phase)
float fre = cpout[j][0];
float fim = cpout[j][1];
float mag = sqrt((fre * fre) + (fim * fim));
fftout[j] = (uint16_t)mag;
fftrdy = 1;
}
}
}
if(fftrdy == 1)
{
*retlen = fftcnt;
return fftout;
}
return NULL;
}
void init_fft()
{
char fn[300];
sprintf(fn, "capture_fft_%d", fft_rate); // wisdom file for each capture rate
fftw_import_wisdom_from_filename(fn);
din = (double *)fftw_malloc(sizeof(double) * fft_rate);
cpout = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * fft_rate);
plan = fftw_plan_dft_r2c_1d(fft_rate, din, cpout, FFTW_MEASURE);
fftw_export_wisdom_to_filename(fn);
}
void exit_fft()
{
if(plan) fftw_destroy_plan(plan);
if(din) fftw_free(din);
if(cpout) fftw_free(cpout);
}

View File

@ -1,325 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
void Insert(uint8_t bit);
uint8_t *FindDatablock();
uint8_t rxbuffer[UDPBLOCKLEN*8/2+100]; // 3...bits per symbol QPSK, enough space also for QPSK and 8PSK, +100 ... reserve, just to be sure
uint8_t rx_status = 0;
int framecounter = 0;
int lastframenum = 0;
// header for TX,
uint8_t TXheaderbytes[HEADERLEN] = {0x53, 0xe1, 0xa6};
// corresponds to these QPSK symbols:
// bits: 01010011 11100001 10100110
// QPSK:
// syms: 1 1 0 3 3 2 0 1 2 2 1 2
// 8PSK:
// syms: 2 4 7 6 0 6 4 6
// QPSK
// each header has 12 symbols
// we have 4 constellations
uint8_t QPSK_headertab[4][HEADERLEN*8/2];
// 8PSK
// each header has 12 symbols
// we have 8 constellations
uint8_t _8PSK_headertab[8][HEADERLEN*8/3];
// init header tables
void init_packer()
{
// create the QPSK symbol table for the HEADER
// in all possible rotations
convertBytesToSyms_QPSK(TXheaderbytes, QPSK_headertab[0], 3);
for(int i=1; i<4; i++)
rotateQPSKsyms(QPSK_headertab[i-1], QPSK_headertab[i], 12);
// create the 8PSK symbol table for the HEADER
// in all possible rotations
convertBytesToSyms_8PSK(TXheaderbytes, _8PSK_headertab[0], 3);
for(int i=1; i<8; i++)
rotate8PSKsyms(_8PSK_headertab[i-1], _8PSK_headertab[i], 8);
}
// packs a payload into an udp data block
// the payload has a size of PAYLOADLEN
// type ... inserted in the "frame type information" field
// status ... specifies first/last frame of a data stream
uint8_t *Pack(uint8_t *payload, int type, int status, int *plen)
{
FRAME frame; // raw frame without fec
// polulate the raw frame
// make the frame counter
if(status & (1<<4))
framecounter = 0; // first block of a stream
else
framecounter++;
// insert frame counter and status bits
frame.counter_LSB = framecounter & 0xff;
int framecnt_MSB = (framecounter >> 8) & 0x03; // Bit 8+9 of framecounter
frame.status = framecnt_MSB << 6;
frame.status += ((status & 0x03)<<4);
frame.status += (type & 0x0f);
// insert the payload
memcpy(frame.payload, payload, PAYLOADLEN);
// calculate and insert the CRC16
uint16_t crc16 = Crc16_messagecalc(CRC16TX,(uint8_t *)(&frame), CRCSECUREDLEN);
frame.crc16_MSB = (uint8_t)(crc16 >> 8);
frame.crc16_LSB = (uint8_t)(crc16 & 0xff);
// make the final arry for transmission
static uint8_t txblock[UDPBLOCKLEN];
// calculate the fec and insert into txblock (leave space for the header)
GetFEC((uint8_t *)(&frame), DATABLOCKLEN, txblock+HEADERLEN);
// scramble
TX_Scramble(txblock+HEADERLEN, FECBLOCKLEN); // scramble all data
// insert the header
memcpy(txblock,TXheaderbytes,HEADERLEN);
/* test pattern
* for(int i=0; i<FECBLOCKLEN; i+=2)
{
*(txblock+HEADERLEN+i) = i;
*(txblock+HEADERLEN+i+1) = 0xf0;
}*/
*plen = UDPBLOCKLEN;
return txblock;
}
/*void store(int newfile, uint8_t * d, int len)
{
FILE *fp;
if(newfile)
fp = fopen("hdr","w");
else
fp = fopen("hdr","a");
if(fp)
{
for(int i=0; i<len; i++)
fprintf(fp,"%02X ",d[i]);
fprintf(fp,"\n");
fclose(fp);
}
}*/
#define MAXHEADERRS 3
/*
* Header erros will not cause any data errors because the CRC will filter out
* false header detects,
* but it will cause higher CPU load due to excessive execution of FEC and CRC
*/
int seekHeadersyms()
{
if(constellationSize == 4)
{
// QPSK
for(int tab=0; tab<4; tab++)
{
int errs = 0;
for(int i=0; i<HEADERLEN*8/2; i++)
{
if(rxbuffer[i] != QPSK_headertab[tab][i])
{
errs++;
}
}
if(errs <= MAXHEADERRS) return tab;
}
}
else
{
// 8PSK
for(int tab=0; tab<8; tab++)
{
int errs = 0;
for(int i=0; i<HEADERLEN*8/3; i++)
{
if(rxbuffer[i] != _8PSK_headertab[tab][i])
{
errs++;
}
}
if(errs <= MAXHEADERRS) return tab;
}
}
return -1;
}
// unpacks a received data frame
// pdata, len ... symbols received from the modem
// returns ... payload, one full frame
uint8_t *unpack_data(uint8_t *rxd, int len)
{
int framerdy = 0;
static uint8_t payload[PAYLOADLEN+10];
rx_status = 0;
// shift all received symbols through rxbuffer
// until a header is detected
for(int sym=0; sym<len; sym++)
{
// shift rxbuffer right by one symbol (=byte)
// frmlen ... number of symbols
int frmlen = UDPBLOCKLEN*8/bitsPerSymbol;
memmove(rxbuffer,rxbuffer+1,frmlen-1);
// insert new symbol at the top
rxbuffer[frmlen-1] = rxd[sym];
//showbytestring((char*)"rx: ",rxbuffer,30);
int rotations = seekHeadersyms();
if(rotations != -1)
{
//printf("Header found, rotation: %d\n",rotations);
// rxbuffer contains all symbols of the received frame
// convert to bytes
uint8_t *rxbytes = NULL;
if(constellationSize == 4)
{
uint8_t *backbuf = rotateBackQPSK(rxbuffer,frmlen,rotations);
rxbytes = convertQPSKSymToBytes(backbuf);
}
else
{
uint8_t *backbuf = rotateBack8PSK(rxbuffer,frmlen,rotations);
rxbytes = convert8PSKSymToBytes(backbuf,UDPBLOCKLEN);
}
if(rxbytes == NULL) return NULL;
// check if we found a data block
uint8_t *pl = getPayload(rxbytes);
if (pl != NULL)
{
memcpy(payload,pl, PAYLOADLEN+10);
framerdy = 1;
}
}
}
if(framerdy)
return payload;
return NULL;
}
// inserts bit per bit into the rxbuffer
// rxbuffer has the size of a complete frame
// so if the header is detected, rxbuffer contains the frame
void Insert(uint8_t bit)
{
if (bit != 0) bit = 1;
// bitshift right
for (int i = 0; i < UDPBLOCKLEN; i++)
{
rxbuffer[i] <<= 1;
if (i == (UDPBLOCKLEN - 1)) break;
uint8_t ov = (uint8_t)(rxbuffer[i + 1] & 0x80);
if (ov != 0) rxbuffer[i] |= 1;
else rxbuffer[i] &= 0xfe;
}
// insert new bit
rxbuffer[UDPBLOCKLEN - 1] &= 0xfe;
rxbuffer[UDPBLOCKLEN - 1] |= (uint8_t)bit;
}
uint8_t *getPayload(uint8_t *rxb)
{
//showbytestring((char *)"orig: ",rxb+HEADERLEN,30);
// unscramble
uint8_t *rxarray = RX_Scramble(rxb+HEADERLEN, FECBLOCKLEN);
// calculate the FEC over the received data
// and fill a frame structure
FRAME frame;
int ret = cfec_Reconstruct(rxarray,(uint8_t *)(&frame));
if(ret == 0)
{
//printf("fec ERROR\n");
return NULL; // fec impossible
}
//printf("fec ok\n");
// check the CRC
uint16_t crc = Crc16_messagecalc(CRC16RX,(uint8_t *)(&frame), CRCSECUREDLEN);
uint16_t rxcrc = frame.crc16_MSB;
rxcrc <<= 8;
rxcrc += frame.crc16_LSB;
if (crc != rxcrc)
{
//printf("crc ERROR\n");
return NULL; // no data found
}
// frame counter verification: lost frame detection
int framenumrx = (frame.status & 0xc0)>>6; // frame counter MSB
framenumrx <<= 8;
framenumrx += frame.counter_LSB; // frame counter LSB
if (lastframenum != framenumrx) rx_status |= 4;
lastframenum = framenumrx;
if (++lastframenum >= 1024) lastframenum = 0; // 1024 = 2^10 (10 bit frame number)
// extract information and build the string for the application
// we have 10 Management Byte then the payload follows
static uint8_t payload[PAYLOADLEN+10];
payload[0] = frame.status & 0x0f; // frame type
payload[1] = (frame.status & 0xc0)>>6; // frame counter MSB
payload[2] = frame.counter_LSB; // frame counter LSB
payload[3] = (frame.status & 0x30)>>4; // first/last frame marker
payload[4] = rx_status; // frame lost information
payload[5] = speed >> 8; // measured line speed
payload[6] = speed;
payload[7] = 0; // free for later use
payload[8] = 0;
payload[9] = 0;
//printf("Frame no.: %d, type:%d, minfo:%d\n",framenumrx,payload[0],payload[3]);
memcpy(payload+10,frame.payload,PAYLOADLEN);
return payload;
}

View File

@ -1,87 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
* The total length of the FEC-secured part is 255,
* this is a requirement of the Shifra FEC routine, which
* is the best FEC that I have seen so far, highly recommended
*/
// total "on the air" frame size
// the total length must be a multiple of 2 and 3, so QPSK and 8PSK symbols fit into full bytes
// this is the case with a total length of 258
#define HEADERLEN 3
#define FECBLOCKLEN 255
#define UDPBLOCKLEN (HEADERLEN + FECBLOCKLEN)
/* !!! IMPORTANT for GNU RADIO !!!
* the UDP payload size for TX MUST be exactly UDPBLOCKLEN (258 in this case) or
* the transmitter will not align bits to symbols correctly !
*
* RX payload size is not that important. But the currect size for
* QPSK is UDPBLOCKLEN*8/2 = 1032 and for 8PSK UDPBLOCKLEN*8/3 = 688
* so we can use 344 which are 2 blocks for 8PSK and 3 blocks for QPSK
* */
// size of the elements inside an FECblock
// sum must be 255
#define FECLEN 32 // supported: 16,32,64,128
#define STATUSLEN 2
#define CRCLEN 2
#define PAYLOADLEN (FECBLOCKLEN - FECLEN - CRCLEN - STATUSLEN)
#define CRCSECUREDLEN (PAYLOADLEN + STATUSLEN)
#define DATABLOCKLEN (PAYLOADLEN + CRCLEN + STATUSLEN)
// the header is not FEC secured therefore we give some room for bit
// errors. Only 24 out of the 32 bits must be correct for
// a valid frame detection
extern uint8_t header[HEADERLEN];
typedef struct {
// the total size of the following data must be 255 - 32 = 223 bytes
// the FEC is calculated on FRAME with a length of 223 and returns
// a data block with length 255.
// we use a 10 bits frame counter -> 1024 values
// so we can transmit a data block with a maximum
// size of 255 * 1024 = 261kByte. With the maximum modem speed
// this would be a transmission time of 5,8 minutes which
// is more then enough for a single data block
uint8_t counter_LSB; // lower 8 bits of the frame counter
// the status byte contains these information:
// bit 0..3 : 4 bit (16 values) frame type information
// bit 4 : first frame of a block if "1"
// bit 5 : last frame of a block if "1"
// bit 6..7 : MSB of the frame counter
uint8_t status;
// payload
uint8_t payload[PAYLOADLEN];
// CRC16
uint8_t crc16_MSB;
uint8_t crc16_LSB;
} FRAME;

View File

@ -1,6 +0,0 @@
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:gnuradio/gnuradio-releases
sudo apt-get update
sudo apt-get install gnuradio
sudo ldconfig

View File

@ -1,9 +0,0 @@
sudo apt install git autoconf libsndfile-dev libasound-dev
git clone git://github.com/jgaeddert/liquid-dsp.git
cd liquid-dsp
./bootstrap.sh
./configure
make -j 8
sudo make install
sudo ldconfig

View File

@ -1,171 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* liquid_dsp_interface.c ... functions using liquid-dsp
*
* liquid-dsp must be previously installed by running ./liquid-dsp-install (under linux)
*
*/
#include "qo100modem.h"
void modulator(uint8_t sym_in);
void close_dsp();
// modem objects
modulation_scheme ms = LIQUID_MODEM_QPSK;
modem mod = NULL;
// NCOs for mixing baseband <-> 1500 Hz
#define FREQUENCY 1500
int type = LIQUID_NCO; // nco type
nco_crcf upnco = NULL;
// TX-Interpolator Filter Parameters
// 44100 input rate for 2205 Sym/s = 20
// change for other rates
firinterp_crcf TX_interpolator = NULL;
unsigned int k_SampPerSymb = 20; // 44100 / (4410/2)
unsigned int m_filterDelay_Symbols = 15; // not too short for good filter
float beta_excessBW = 0.3f; // filter excess bandwidth factor
float tau_FracSymbOffset = -0.2f; // fractional symbol offset
int init_dsp()
{
close_dsp();
printf("create DSP\n");
k_SampPerSymb = txinterpolfactor;
if(bitsPerSymbol == 2)
ms = LIQUID_MODEM_QPSK;
else
ms = LIQUID_MODEM_DPSK8;
// create modulator
mod = modem_create(ms);
// create NCO for upmixing to 1500 Hz
double RADIANS_PER_SAMPLE = ((2.0*M_PI*(double)FREQUENCY)/(float)caprate);
upnco = nco_crcf_create(LIQUID_NCO);
nco_crcf_set_phase(upnco, 0.0f);
nco_crcf_set_frequency(upnco, RADIANS_PER_SAMPLE);
// TX: Interpolator Filter
// compute delay
while (tau_FracSymbOffset < 0) tau_FracSymbOffset += 1.0f; // ensure positive tau
float g = k_SampPerSymb*tau_FracSymbOffset; // number of samples offset
int ds=floorf(g); // additional symbol delay
float dt = (g - (float)ds); // fractional sample offset
// force dt to be in [0.5,0.5]
if (dt > 0.5f)
{
dt -= 1.0f;
ds++;
}
// calculate filter coeffs
unsigned int h_len_NumFilterCoeefs = 2 * k_SampPerSymb * m_filterDelay_Symbols + 1;
float h[h_len_NumFilterCoeefs];
liquid_firdes_prototype( LIQUID_FIRFILT_RRC,
k_SampPerSymb,
m_filterDelay_Symbols,
beta_excessBW,
dt,
h);
// create the filter
TX_interpolator = firinterp_crcf_create(k_SampPerSymb,h,h_len_NumFilterCoeefs);
printf("DSP created\n");
return 1;
}
void close_dsp()
{
if(mod != NULL) modem_destroy(mod);
if(upnco != NULL) nco_crcf_destroy(upnco);
if(TX_interpolator != NULL) firinterp_crcf_destroy(TX_interpolator);
mod = NULL;
upnco = NULL;
TX_interpolator = NULL;
}
// d ... symbols to send
// len ... number of symbols in d
void sendToModulator(uint8_t *d, int len)
{
//printf("sendToModulator %d bytes\n",len);
int symanz = len * 8 / bitsPerSymbol;
uint8_t syms[symanz];
if(bitsPerSymbol == 2)
convertBytesToSyms_QPSK(d, syms, len);
else
convertBytesToSyms_8PSK(d, syms, len);
for(int i=0; i<symanz; i++)
{
// remove gray code
// this adds gray code, liquid adds it again which removes it
syms[i] ^= (syms[i]>>1);
modulator(syms[i]);
}
}
// call for every symbol
// modulates, filters and upmixes symbols and send it to soundcard
void modulator(uint8_t sym_in)
{
liquid_float_complex sample;
modem_modulate(mod, sym_in, &sample);
//printf("TX ================= sample: %f + i%f\n", sample.real, sample.imag);
// interpolate by k_SampPerSymb
liquid_float_complex y[k_SampPerSymb];
firinterp_crcf_execute(TX_interpolator, sample, y);
for(unsigned int i=0; i<k_SampPerSymb; i++)
{
// move sample to 1,5kHz carrier
nco_crcf_step(upnco);
float minus_sine = -nco_crcf_sin(upnco);
float cosinus = nco_crcf_cos(upnco);
float re = y[i].real * cosinus;
float im = y[i].imag * minus_sine;
float usb = re + im;
// value is -1 .. +1
// adapt speed to soundcard samplerate
int fs;
while(1)
{
fs = pb_fifo_freespace(0);
if(fs) break;
usleep(10000);
}
pb_write_fifo(usb * 0.2); // reduce volume and send to soundcard
}
}

View File

@ -1,94 +0,0 @@
/*
* main_helper
* ===========
* by DJ0ABR
*
* functions useful for every main() program start
*
* */
#include "qo100modem.h"
// check if it is already running
int isRunning(char *prgname)
{
int num = 0;
char s[256];
sprintf(s,"ps -e | grep %s",prgname);
FILE *fp = popen(s,"r");
if(fp)
{
// gets the output of the system command
while (fgets(s, sizeof(s)-1, fp) != NULL)
{
if(strstr(s,prgname) && !strstr(s,"grep"))
{
if(++num == 2)
{
printf("%s is already running, do not start twice !",prgname);
pclose(fp);
return 1;
}
}
}
pclose(fp);
}
return 0;
}
// signal handler
void sighandler(int signum)
{
printf("program stopped by signal\n");
stopModem();
exit_fft();
keeprunning = 0;
close(BC_sock_AppToModem);
}
void install_signal_handler()
{
// signal handler, mainly used if the user presses Ctrl-C
struct sigaction sigact;
sigact.sa_handler = sighandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
sigaction(SIGABRT, &sigact, NULL); // assert() error
//sigaction(SIGSEGV, &sigact, NULL);
// switch off signal 13 (broken pipe)
// instead handle the return value of the write or send function
signal(SIGPIPE, SIG_IGN);
}
int run_console_program(char *cmd)
{
printf("executing: %s\n",cmd);
int ret = system(cmd);
if(ret){}
return 0;
}
void showbytestring(char *title, uint8_t *data, int anz)
{
printf("%s. Len %d: ",title,anz);
for(int i=0; i<anz; i++)
printf("%02X ",data[i]);
printf("\n");
}
void showbytestring16(char *title, uint16_t *data, int anz)
{
printf("%s. Len %d: ",title,anz);
for(int i=0; i<anz; i++)
printf("%04X ",data[i]);
printf("\n");
}

View File

@ -1,18 +0,0 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <wchar.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/file.h>
#include <signal.h>
int isRunning(char *prgname);
void install_signal_handler();
void sighandler(int signum);
int run_console_program(char *cmd);

View File

@ -1,575 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
int Open_BC_Socket();
void startModem();
void stopModem();
void getMyIP();
void bc_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
void appdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
void GRdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
void GRdata_FFTdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
void GRdata_I_Qdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
// threads will exit if set to 0
int keeprunning = 1;
// UDP I/O
int BC_sock_AppToModem = -1;
int DATA_sock_AppToModem = -1;
int DATA_sock_from_GR = -1;
int DATA_sock_FFT_from_GR = -1;
int DATA_sock_I_Q_from_GR = -1;
int UdpBCport_AppToModem = 40131;
int UdpDataPort_AppToModem = 40132;
int UdpDataPort_ModemToApp = 40133;
int UdpDataPort_toGR = 40134;
int UdpDataPort_fromGR = 40135;
int UdpDataPort_fromGR_FFT = 40136;
int UdpDataPort_fromGR_I_Q = 40137;
// op mode depending values
// default mode if not set by the app
int speedmode = 4;
int bitsPerSymbol = 2; // QPSK=2, 8PSK=3
int constellationSize = 4; // QPSK=4, 8PSK=8
char localIP[]={"127.0.0.1"};
char ownfilename[]={"qo100modem"};
char myIP[20];
char appIP[20] = {0};
int fixappIP = 0;
int restart_modems = 0;
int doNotLoadModems = 0;
int caprate = 44100;
int txinterpolfactor = 20;
int main(int argc, char *argv[])
{
int opt = 0;
char *modemip = NULL;
while ((opt = getopt(argc, argv, "m:e:")) != -1)
{
switch(opt)
{
case 'e':
doNotLoadModems = 1;
break;
case 'm':
modemip = optarg;
memset(appIP,0,20);
int len = strlen(modemip);
if(len < 16)
{
memcpy(appIP,modemip,len);
fixappIP = 1;
printf("Application IP set to: %s\n",modemip);
}
else
{
printf("invalid Application IP: %s\n",modemip);
exit(0);
}
break;
}
}
if(doNotLoadModems == 0 && isRunning(ownfilename) == 1)
exit(0);
install_signal_handler();
init_packer();
initFEC();
init_fft();
init_audio();
// start udp RX to listen for broadcast search message from Application
UdpRxInit(&BC_sock_AppToModem, UdpBCport_AppToModem, &bc_rxdata, &keeprunning);
// start udp RX for data from application
UdpRxInit(&DATA_sock_AppToModem, UdpDataPort_AppToModem, &appdata_rxdata, &keeprunning);
// start udp RX to listen for data from GR Receiver
UdpRxInit(&DATA_sock_from_GR, UdpDataPort_fromGR, &GRdata_rxdata, &keeprunning);
// start udp RX to listen for Audio-Samples (FFT) data from GR Receiver
UdpRxInit(&DATA_sock_FFT_from_GR, UdpDataPort_fromGR_FFT, &GRdata_FFTdata, &keeprunning);
// start udp RX to listen for IQ data from GR Receiver
UdpRxInit(&DATA_sock_I_Q_from_GR, UdpDataPort_fromGR_I_Q, &GRdata_I_Qdata, &keeprunning);
getMyIP();
printf("QO100modem initialised and running\n");
while (keeprunning)
{
if(restart_modems == 1)
{
stopModem();
startModem();
restart_modems = 0;
}
doArraySend();
usleep(100);
}
printf("stopped: %d\n",keeprunning);
close(BC_sock_AppToModem);
return 0;
}
typedef struct {
int audio;
int tx;
int rx;
} SPEEDRATE;
SPEEDRATE sr[9] = {
// QPSK modes
{48000, 32, 8}, // AudioRate, TX-Resampler, RX-Resampler/4
{44100, 28, 7}, // see samprate.ods
{44100, 24, 6},
{48000, 24, 6},
{44100, 20, 5},
{48000, 20, 5},
// 8PSK modes
{44100, 24, 6},
{48000, 24, 6}
};
void startModem()
{
char srx[512];
if(speedmode >= 0 && speedmode <=5)
{
bitsPerSymbol = 2; // QPSK=2, 8PSK=3
constellationSize = (1<<bitsPerSymbol); // QPSK=4, 8PSK=8
}
else if(speedmode >= 6 && speedmode <=7)
{
bitsPerSymbol = 3; // QPSK=2, 8PSK=3
constellationSize = (1<<bitsPerSymbol); // QPSK=4, 8PSK=8
}
caprate = sr[speedmode].audio;
txinterpolfactor = sr[speedmode].tx;
if(doNotLoadModems == 1) return;
if(speedmode >= 0 && speedmode <=5)
sprintf(srx,"python3 qpsk_rx.py -r %d -s %d &",sr[speedmode].rx,sr[speedmode].audio);
else if(speedmode >= 6 && speedmode <=7)
sprintf(srx,"python3 rx_8psk.py -r %d -s %d &",sr[speedmode].rx,sr[speedmode].audio);
else
{
printf("wrong modem number\n");
exit(0);
}
// int TX audio and modulator
init_dsp();
init_audio();
// the RX modem needs the app's IP address as a parameter -i ip
if(run_console_program(srx) == -1)
{
printf("cannot start RX modem\n");
exit(0);
}
}
void stopModem()
{
if(doNotLoadModems == 1) return;
printf("stop modem\n");
int ret = system("killall python3");
if(ret){}
// wait until stop job is done
sleep(1);
}
void getMyIP()
{
struct ifaddrs *ifaddr, *ifa;
int s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
printf("getifaddrs error\n");
exit(0);
}
ifa = ifaddr;
while(ifa)
{
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if(ifa->ifa_addr->sa_family==AF_INET)
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(0);
}
strcpy(myIP, host);
if(strncmp(host,"127",3) != 0)
break;
}
ifa = ifa->ifa_next;
}
freeifaddrs(ifaddr);
return;
}
// called from UDP RX thread for Broadcast-search from App
void bc_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
if (len > 0 && pdata[0] == 0x3c)
{
char rxip[20];
strcpy(rxip,inet_ntoa(rxsock->sin_addr));
if(fixappIP == 0)
{
if(strcmp(appIP,rxip))
{
printf("new app IP: %s, restarting modems\n",rxip);
restart_modems = 1;
}
strcpy(appIP,rxip);
//printf("app (%s) is searching modem. Sending modem IP to the app\n",appIP);
// App searches for the modem IP, mirror the received messages
// so the app gets an UDP message with this local IP
pdata[0] = 3;
sendUDP(appIP,UdpDataPort_ModemToApp,pdata,1);
}
else
{
// appIP is fixed, answer only to this IP
if(!strcmp(appIP,rxip))
{
//printf("app (%s) is searching modem. Sending modem IP to the app\n",appIP);
restart_modems = 1;
// App searches for the modem IP, mirror the received messages
// so the app gets an UDP message with this local IP
pdata[0] = 3;
sendUDP(appIP,UdpDataPort_ModemToApp,pdata,1);
}
}
}
}
// called by UDP RX thread for data from App
void appdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
uint8_t type = pdata[0];
uint8_t minfo = pdata[1];
if(len != (PAYLOADLEN+2))
{
printf("data from app: wrong length:%d (should be %d)\n",len-2,PAYLOADLEN);
return;
}
// type values: see oscardata config.cs: frame types
if(type == 16)
{
// Byte 1 contains the resampler ratio for TX and RX modem
speedmode = pdata[1];
printf("set speedmode to %d\n",speedmode);
restart_modems = 1;
return;
}
if(type == 17)
{
// auto send file
// TODO
// for testing only:
// simulate sending a text file with 1kB length
int testlen = 100000;
uint8_t arr[testlen];
char c = 'A';
for(int i=0; i<testlen; i++)
{
arr[i] = c;
if(++c>'Z') c='A';
}
arraySend(arr, testlen, 3, (char *)"testfile.txt");
return;
}
if(type == 18)
{
// auto send folder
// TODO
}
if(type == 19)
{
// shut down this modem PC
int r = system("sudo shutdown now");
exit(r);
}
if(getSending() == 1) return; // already sending (Array sending)
if(minfo == 0)
{
// this is the first frame of a larger file
// send it multiple times, like a preamble, to give the
// receiver some time for synchronisation
// duration: 3 seconds
// caprate: samples/s. This are symbols: caprate/txinterpolfactor
// and bits: symbols * bitsPerSymbol
// and bytes/second: bits/8 = (caprate/txinterpolfactor) * bitsPerSymbol / 8
// one frame has 258 bytes, so we need for 5s: 5* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
int numframespreamble = 3* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1;
for(int i=0; i<numframespreamble; i++)
toGR_sendData(pdata+2, type, minfo);
}
else if((len-2) < PAYLOADLEN)
{
// if not enough data for a full payload add Zeros
uint8_t payload[PAYLOADLEN];
memset(payload,0,PAYLOADLEN);
memcpy(payload,pdata+2,len-2);
toGR_sendData(payload, type, minfo);
}
else
{
toGR_sendData(pdata+2, type, minfo);
}
}
void toGR_sendData(uint8_t *data, int type, int status)
{
int len = 0;
uint8_t *txdata = Pack(data,type,status,&len);
//showbytestring((char *)"BERtx: ", txdata, len);
if(txdata != NULL)
sendToModulator(txdata,len);
}
#define SPEEDMEAN 3
int speedmean = SPEEDMEAN;
int meansumbytes = 0;
int speed = 0;
void measure_speed(int len)
{
struct timeval tv;
static uint64_t lastus = 0;
uint64_t us;
static int sparr[SPEEDMEAN] = {-1};
gettimeofday(&tv, NULL);
us = tv.tv_sec * 1000000 + tv.tv_usec;
if(lastus == 0)
{
lastus = us;
return;
}
uint64_t ts = us-lastus;
// make measurement only if time >= 1s
meansumbytes += len;
if(ts < 5000000)
{
// do not measure
return;
}
// ts ... time in us since last measurement
// divide by the number of bits
ts /= (meansumbytes*8); // time for one bit
int tbit = (int)ts;
int sp1 = 1000000/tbit;
// convert speed of symbols to speed of bits
speed = sp1 * bitsPerSymbol / 8;
int mean = 0;
if(sparr[0] == -1)
{
for(int i=0; i<speedmean; i++)
sparr[i] = speed;
}
else
{
// make mean value
for(int i=speedmean-1; i>0; i--)
sparr[i] = sparr[i-1];
sparr[0] = speed;
}
for(int i=0; i<speedmean; i++)
mean += sparr[i];
mean /= speedmean;
//printf("Speed %d bit/s\n",mean);
lastus = us;
meansumbytes = 0;
}
// called by UDP RX thread for data from GnuRadio Receiver
void GRdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
// raw symbols
measure_speed(len);
uint8_t *pl = unpack_data(pdata, len);
if(pl != NULL)
{
// complete frame received
// send payload to app
uint8_t txpl[PAYLOADLEN+10+1];
memcpy(txpl+1,pl,PAYLOADLEN+10);
txpl[0] = 1; // type 1: payload data follows
sendUDP(appIP,UdpDataPort_ModemToApp,txpl,PAYLOADLEN+10+1);
}
}
// called by UDP RX thread for Audio-Samples (FFT) data from GR
void GRdata_FFTdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
// send IQ data to FFT for waterfall calculation
int fftlen = 0;
uint16_t *fft = make_waterfall(pdata,len, &fftlen);
if(fft != NULL)
{
uint8_t txpl[10000];
if(fftlen > (10000*2+1))
{
printf("txpl too small !!!\n");
return;
}
int bidx = 0;
txpl[bidx++] = 4; // type 4: FFT data follows
for(int i=0; i<fftlen; i++)
{
txpl[bidx++] = fft[i] >> 8;
txpl[bidx++] = fft[i];
}
sendUDP(appIP,UdpDataPort_ModemToApp,txpl,bidx);
}
}
uint8_t lastb[12];
void display_IQ(uint8_t *pdata, int len)
{
for (int i = 0; i < len; i++)
{
// insert new byte in lastb
for (int sh = 12 - 1; sh > 0; sh--)
lastb[sh] = lastb[sh - 1];
lastb[0] = pdata[i];
// test if aligned
// for PC
if (lastb[0] == 0 && lastb[1] == 0 && lastb[2] == 3 && lastb[3] == 0xe8)
{
// we are aligned to a re value
int re = lastb[4];
re <<= 8;
re += lastb[5];
re <<= 8;
re += lastb[6];
re <<= 8;
re += lastb[7];
int im = lastb[8];
im <<= 8;
im += lastb[9];
im <<= 8;
im += lastb[10];
im <<= 8;
im += lastb[11];
double fre = (double)re / 16777216;
double fim = (double)im / 16777216;
printf("re: %f im: %f\n",fre,fim);
}
// and for ARM
else if (lastb[0] == 0xe8 && lastb[1] == 3 && lastb[2] == 0 && lastb[3] == 0)
{
// we are aligned to a re value
int re = lastb[7];
re <<= 8;
re += lastb[6];
re <<= 8;
re += lastb[5];
re <<= 8;
re += lastb[4];
int im = lastb[11];
im <<= 8;
im += lastb[10];
im <<= 8;
im += lastb[9];
im <<= 8;
im += lastb[8];
double fre = (double)re / 16777216;
double fim = (double)im / 16777216;
printf("ARM re: %f im: %f\n",fre,fim);
}
}
}
// called by UDP RX thread for IQ data from GR
void GRdata_I_Qdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
// these data are floats multiplied by 2^24 and then converted to int
// for testing convert it back and display it
//display_IQ(pdata,len);
// send the data "as is" to app
uint8_t txpl[len+1];
memcpy(txpl+1,pdata,len);
txpl[0] = 5; // type 5: IQ data follows
sendUDP(appIP,UdpDataPort_ModemToApp,txpl,len+1);
}

View File

@ -1,97 +0,0 @@
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <wchar.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/file.h>
#include <pthread.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <math.h>
#include <ifaddrs.h>
#include <zip.h>
#include "frameformat.h"
#include "main_helper.h"
#include "udp.h"
#include "bass.h"
#include <liquid/liquid.h>
#define jpg_tempfilename "rxdata.jpg"
#define CRC16TX 0
#define CRC16RX 1
#define CRC16FILE 2
void stopModem();
uint8_t *unpack_data(uint8_t *rxd, int len);
void TX_Scramble(uint8_t *data, int len);
uint8_t *RX_Scramble(uint8_t *data, int len);
uint16_t Crc16_messagecalc(int rxtx, uint8_t *data,int len);
uint32_t crc32_messagecalc(int txrx, unsigned char *data, int len);
int cfec_Reconstruct(uint8_t *darr, uint8_t *destination);
uint8_t *Pack(uint8_t *payload, int type, int status, int *plen);
void GetFEC(uint8_t *txblock, int len, uint8_t *destArray);
void initFEC();
void toGR_sendData(uint8_t *data, int type, int status);
uint16_t *make_waterfall(uint8_t *pdata, int len, int *retlen);
void init_fft();
void exit_fft();
uint8_t *convertQPSKSymToBytes(uint8_t *rxsymbols);
uint8_t *convert8PSKSymToBytes(uint8_t *rxsymbols, int len);
uint8_t *getPayload(uint8_t *rxb);
void showbytestring(char *title, uint8_t *data, int anz);
void init_packer();
void convertBytesToSyms_QPSK(uint8_t *bytes, uint8_t *syms, int bytenum);
void rotateQPSKsyms(uint8_t *src, uint8_t *dst, int len);
uint8_t * rotateBackQPSK(uint8_t *buf, int len, int rotations);
void convertBytesToSyms_8PSK(uint8_t *bytes, uint8_t *syms, int bytenum);
void rotate8PSKsyms(uint8_t *src, uint8_t *dst, int len);
uint8_t * rotateBack8PSK(uint8_t *buf, int len, int rotations);
void setSending(uint8_t onoff);
int getSending();
void doArraySend();
int arraySend(uint8_t *data, int length, uint8_t type, char *filename);
void shiftleft(uint8_t *data, int shiftnum, int len);
void showbytestring16(char *title, uint16_t *data, int anz);
int isTXRunning(char *prgname);
int pb_fifo_freespace(int nolock);
int init_audio();
void sendToModulator(uint8_t *d, int len);
void pb_write_fifo(float sample);
int init_dsp();
extern int keeprunning;
extern int BC_sock_AppToModem;
extern int speed;
extern int speedmode;
extern int bitsPerSymbol;
extern int constellationSize;
extern int caprate;
extern int txinterpolfactor;
/*
* Constellation as produced by the GR Constellation Decoder:
*
* 0 ... +1+1j
* 1 ... -1+1j
* 2 ... -1-1j
* 3 ... +1-1j
*
*
* */

View File

@ -1,209 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# SPDX-License-Identifier: GPL-3.0
#
# GNU Radio Python Flow Graph
# Title: QPSK RX-Modem
# Author: DJ0ABR
# Description: works with Gnu Radio 3.8.xxx
# GNU Radio version: 3.8.2.0
from gnuradio import analog
from gnuradio import audio
from gnuradio import blocks
from gnuradio import digital
from gnuradio import filter
from gnuradio.filter import firdes
from gnuradio import gr
import sys
import signal
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
class qpsk_rx(gr.top_block):
def __init__(self, resamp=5, samp_rate=44100):
gr.top_block.__init__(self, "QPSK RX-Modem")
##################################################
# Parameters
##################################################
self.resamp = resamp
self.samp_rate = samp_rate
##################################################
# Variables
##################################################
self.sps = sps = 4
self.qpsk__constellation = qpsk__constellation = digital.constellation_rect([0.707+0.707j, -0.707+0.707j, -0.707-0.707j, 0.707-0.707j], [0, 1, 2, 3],
4, 2, 2, 1, 1).base()
self.qpsk__constellation.gen_soft_dec_lut(8)
self.outputsps = outputsps = 8
self.nfilts = nfilts = 15
self.mixf = mixf = 1500
##################################################
# Blocks
##################################################
self.mmse_resampler_xx_1 = filter.mmse_resampler_cc(0, resamp)
self.mmse_resampler_xx_0 = filter.mmse_resampler_ff(0, samp_rate / 8000)
self.low_pass_filter_0 = filter.fir_filter_fff(
1,
firdes.low_pass(
8,
samp_rate,
3500,
3100,
firdes.WIN_HAMMING,
6.76))
self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, 0.1, firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), 0.35, 11*sps*nfilts), nfilts, nfilts/2, 1.5, outputsps)
self.digital_lms_dd_equalizer_cc_0 = digital.lms_dd_equalizer_cc(15, 0.01, outputsps, qpsk__constellation)
self.digital_costas_loop_cc_0 = digital.costas_loop_cc(0.06, 4, False)
self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(qpsk__constellation)
self.blocks_udp_sink_0_0_0 = blocks.udp_sink(gr.sizeof_int*1, '127.0.0.1', 40137, 120, False)
self.blocks_udp_sink_0_0 = blocks.udp_sink(gr.sizeof_int*1, '127.0.0.1', 40136, 120, False)
self.blocks_udp_sink_0 = blocks.udp_sink(gr.sizeof_char*1, '127.0.0.1', 40135, 344, False)
self.blocks_multiply_xx_0_1_0 = blocks.multiply_vff(1)
self.blocks_multiply_xx_0_1 = blocks.multiply_vff(1)
self.blocks_multiply_xx_0_0_0 = blocks.multiply_vff(1)
self.blocks_interleave_0_0 = blocks.interleave(gr.sizeof_int*1, 1)
self.blocks_interleave_0 = blocks.interleave(gr.sizeof_int*1, 1)
self.blocks_float_to_int_0_1 = blocks.float_to_int(1, 1)
self.blocks_float_to_int_0_0 = blocks.float_to_int(1, 16777216)
self.blocks_float_to_int_0 = blocks.float_to_int(1, 16777216)
self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
self.blocks_complex_to_float_1 = blocks.complex_to_float(1)
self.blocks_complex_to_float_0 = blocks.complex_to_float(1)
self.audio_source_0 = audio.source(samp_rate, '', True)
self.analog_sig_source_x_0_0_0 = analog.sig_source_c(samp_rate, analog.GR_COS_WAVE, mixf, 1, 0, 0)
self.analog_const_source_x_0_1 = analog.sig_source_f(0, analog.GR_CONST_WAVE, 0, 0, 16777216)
self.analog_const_source_x_0_0 = analog.sig_source_i(0, analog.GR_CONST_WAVE, 0, 0, 1000)
self.analog_const_source_x_0 = analog.sig_source_i(0, analog.GR_CONST_WAVE, 0, 0, 1000)
self.analog_agc2_xx_0_0 = analog.agc2_cc(0.01, 0.2, 1, 1)
self.analog_agc2_xx_0_0.set_max_gain(3)
##################################################
# Connections
##################################################
self.connect((self.analog_agc2_xx_0_0, 0), (self.digital_costas_loop_cc_0, 0))
self.connect((self.analog_const_source_x_0, 0), (self.blocks_interleave_0, 0))
self.connect((self.analog_const_source_x_0_0, 0), (self.blocks_interleave_0_0, 0))
self.connect((self.analog_const_source_x_0_1, 0), (self.blocks_multiply_xx_0_1_0, 1))
self.connect((self.analog_sig_source_x_0_0_0, 0), (self.blocks_complex_to_float_1, 0))
self.connect((self.audio_source_0, 0), (self.low_pass_filter_0, 0))
self.connect((self.audio_source_0, 0), (self.mmse_resampler_xx_0, 0))
self.connect((self.blocks_complex_to_float_0, 0), (self.blocks_float_to_int_0, 0))
self.connect((self.blocks_complex_to_float_0, 1), (self.blocks_float_to_int_0_0, 0))
self.connect((self.blocks_complex_to_float_1, 1), (self.blocks_multiply_xx_0_0_0, 1))
self.connect((self.blocks_complex_to_float_1, 0), (self.blocks_multiply_xx_0_1, 1))
self.connect((self.blocks_float_to_complex_0, 0), (self.mmse_resampler_xx_1, 0))
self.connect((self.blocks_float_to_int_0, 0), (self.blocks_interleave_0_0, 1))
self.connect((self.blocks_float_to_int_0_0, 0), (self.blocks_interleave_0_0, 2))
self.connect((self.blocks_float_to_int_0_1, 0), (self.blocks_interleave_0, 1))
self.connect((self.blocks_interleave_0, 0), (self.blocks_udp_sink_0_0, 0))
self.connect((self.blocks_interleave_0_0, 0), (self.blocks_udp_sink_0_0_0, 0))
self.connect((self.blocks_multiply_xx_0_0_0, 0), (self.blocks_float_to_complex_0, 0))
self.connect((self.blocks_multiply_xx_0_1, 0), (self.blocks_float_to_complex_0, 1))
self.connect((self.blocks_multiply_xx_0_1_0, 0), (self.blocks_float_to_int_0_1, 0))
self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_udp_sink_0, 0))
self.connect((self.digital_costas_loop_cc_0, 0), (self.blocks_complex_to_float_0, 0))
self.connect((self.digital_costas_loop_cc_0, 0), (self.digital_constellation_decoder_cb_0, 0))
self.connect((self.digital_lms_dd_equalizer_cc_0, 0), (self.analog_agc2_xx_0_0, 0))
self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_lms_dd_equalizer_cc_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_xx_0_0_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_xx_0_1, 0))
self.connect((self.mmse_resampler_xx_0, 0), (self.blocks_multiply_xx_0_1_0, 0))
self.connect((self.mmse_resampler_xx_1, 0), (self.digital_pfb_clock_sync_xxx_0, 0))
def get_resamp(self):
return self.resamp
def set_resamp(self, resamp):
self.resamp = resamp
self.mmse_resampler_xx_1.set_resamp_ratio(self.resamp)
def get_samp_rate(self):
return self.samp_rate
def set_samp_rate(self, samp_rate):
self.samp_rate = samp_rate
self.analog_sig_source_x_0_0_0.set_sampling_freq(self.samp_rate)
self.low_pass_filter_0.set_taps(firdes.low_pass(8, self.samp_rate, 3500, 3100, firdes.WIN_HAMMING, 6.76))
self.mmse_resampler_xx_0.set_resamp_ratio(self.samp_rate / 8000)
def get_sps(self):
return self.sps
def set_sps(self, sps):
self.sps = sps
self.digital_pfb_clock_sync_xxx_0.update_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.0/float(self.sps), 0.35, 11*self.sps*self.nfilts))
def get_qpsk__constellation(self):
return self.qpsk__constellation
def set_qpsk__constellation(self, qpsk__constellation):
self.qpsk__constellation = qpsk__constellation
def get_outputsps(self):
return self.outputsps
def set_outputsps(self, outputsps):
self.outputsps = outputsps
def get_nfilts(self):
return self.nfilts
def set_nfilts(self, nfilts):
self.nfilts = nfilts
self.digital_pfb_clock_sync_xxx_0.update_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.0/float(self.sps), 0.35, 11*self.sps*self.nfilts))
def get_mixf(self):
return self.mixf
def set_mixf(self, mixf):
self.mixf = mixf
self.analog_sig_source_x_0_0_0.set_frequency(self.mixf)
def argument_parser():
description = 'works with Gnu Radio 3.8.xxx'
parser = ArgumentParser(description=description)
parser.add_argument(
"-r", "--resamp", dest="resamp", type=intx, default=5,
help="Set resamp [default=%(default)r]")
parser.add_argument(
"-s", "--samp-rate", dest="samp_rate", type=intx, default=44100,
help="Set samp_rate [default=%(default)r]")
return parser
def main(top_block_cls=qpsk_rx, options=None):
if options is None:
options = argument_parser().parse_args()
tb = top_block_cls(resamp=options.resamp, samp_rate=options.samp_rate)
def sig_handler(sig=None, frame=None):
tb.stop()
tb.wait()
sys.exit(0)
signal.signal(signal.SIGINT, sig_handler)
signal.signal(signal.SIGTERM, sig_handler)
tb.start()
tb.wait()
if __name__ == '__main__':
main()

View File

@ -1,210 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# SPDX-License-Identifier: GPL-3.0
#
# GNU Radio Python Flow Graph
# Title: 8PSK Modem DJ0ABR
# Author: kurt
# Description: requires GNU Radio 3.8xxx
# GNU Radio version: 3.8.2.0
from gnuradio import analog
from gnuradio import audio
from gnuradio import blocks
from gnuradio import digital
from gnuradio import filter
from gnuradio.filter import firdes
from gnuradio import gr
import sys
import signal
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
class rx_8psk(gr.top_block):
def __init__(self, resamp=6, samp_rate=48000):
gr.top_block.__init__(self, "8PSK Modem DJ0ABR")
##################################################
# Parameters
##################################################
self.resamp = resamp
self.samp_rate = samp_rate
##################################################
# Variables
##################################################
self.sps = sps = 4
self.nfilts = nfilts = 32
self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, nfilts, 1.1/float(sps), 0.2, 11*sps*nfilts)
self.outputsps = outputsps = 7
self.mixf = mixf = 1500
##################################################
# Blocks
##################################################
self.mmse_resampler_xx_0_0 = filter.mmse_resampler_ff(0, samp_rate / 8000)
self.mmse_resampler_xx_0 = filter.mmse_resampler_cc(0, resamp)
self.low_pass_filter_0 = filter.fir_filter_fff(
1,
firdes.low_pass(
12,
samp_rate,
3900,
3300,
firdes.WIN_HAMMING,
6.76))
self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, 0.06, rrc_taps, nfilts, nfilts/16, 2, outputsps)
self.digital_lms_dd_equalizer_cc_0 = digital.lms_dd_equalizer_cc(15, 0.01, outputsps, digital.constellation_8psk_natural().base())
self.digital_diff_decoder_bb_0 = digital.diff_decoder_bb(8)
self.digital_costas_loop_cc_0 = digital.costas_loop_cc(0.15, 8, False)
self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(digital.constellation_8psk_natural().base())
self.blocks_udp_sink_0_0_0 = blocks.udp_sink(gr.sizeof_int*1, '127.0.0.1', 40137, 120, False)
self.blocks_udp_sink_0_0 = blocks.udp_sink(gr.sizeof_int*1, '127.0.0.1', 40136, 120, False)
self.blocks_udp_sink_0 = blocks.udp_sink(gr.sizeof_char*1, '127.0.0.1', 40135, 344, False)
self.blocks_multiply_xx_0_1_0 = blocks.multiply_vff(1)
self.blocks_multiply_xx_0_1 = blocks.multiply_vff(1)
self.blocks_multiply_xx_0_0_0 = blocks.multiply_vff(1)
self.blocks_interleave_0_0 = blocks.interleave(gr.sizeof_int*1, 1)
self.blocks_interleave_0 = blocks.interleave(gr.sizeof_int*1, 1)
self.blocks_float_to_int_0_1 = blocks.float_to_int(1, 1)
self.blocks_float_to_int_0_0 = blocks.float_to_int(1, 16777216)
self.blocks_float_to_int_0 = blocks.float_to_int(1, 16777216)
self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
self.blocks_complex_to_float_1 = blocks.complex_to_float(1)
self.blocks_complex_to_float_0 = blocks.complex_to_float(1)
self.audio_source_0 = audio.source(samp_rate, '', True)
self.analog_sig_source_x_0_0_0 = analog.sig_source_c(samp_rate, analog.GR_COS_WAVE, mixf, 1, 0, 0)
self.analog_const_source_x_0_1 = analog.sig_source_f(0, analog.GR_CONST_WAVE, 0, 0, 16777216)
self.analog_const_source_x_0_0 = analog.sig_source_i(0, analog.GR_CONST_WAVE, 0, 0, 1000)
self.analog_const_source_x_0 = analog.sig_source_i(0, analog.GR_CONST_WAVE, 0, 0, 1000)
self.analog_agc2_xx_0_0 = analog.agc2_cc(1e-2, 0.2, 1, 2)
self.analog_agc2_xx_0_0.set_max_gain(3)
##################################################
# Connections
##################################################
self.connect((self.analog_agc2_xx_0_0, 0), (self.digital_costas_loop_cc_0, 0))
self.connect((self.analog_const_source_x_0, 0), (self.blocks_interleave_0, 0))
self.connect((self.analog_const_source_x_0_0, 0), (self.blocks_interleave_0_0, 0))
self.connect((self.analog_const_source_x_0_1, 0), (self.blocks_multiply_xx_0_1_0, 1))
self.connect((self.analog_sig_source_x_0_0_0, 0), (self.blocks_complex_to_float_1, 0))
self.connect((self.audio_source_0, 0), (self.low_pass_filter_0, 0))
self.connect((self.audio_source_0, 0), (self.mmse_resampler_xx_0_0, 0))
self.connect((self.blocks_complex_to_float_0, 0), (self.blocks_float_to_int_0, 0))
self.connect((self.blocks_complex_to_float_0, 1), (self.blocks_float_to_int_0_0, 0))
self.connect((self.blocks_complex_to_float_1, 1), (self.blocks_multiply_xx_0_0_0, 1))
self.connect((self.blocks_complex_to_float_1, 0), (self.blocks_multiply_xx_0_1, 1))
self.connect((self.blocks_float_to_complex_0, 0), (self.mmse_resampler_xx_0, 0))
self.connect((self.blocks_float_to_int_0, 0), (self.blocks_interleave_0_0, 1))
self.connect((self.blocks_float_to_int_0_0, 0), (self.blocks_interleave_0_0, 2))
self.connect((self.blocks_float_to_int_0_1, 0), (self.blocks_interleave_0, 1))
self.connect((self.blocks_interleave_0, 0), (self.blocks_udp_sink_0_0, 0))
self.connect((self.blocks_interleave_0_0, 0), (self.blocks_udp_sink_0_0_0, 0))
self.connect((self.blocks_multiply_xx_0_0_0, 0), (self.blocks_float_to_complex_0, 0))
self.connect((self.blocks_multiply_xx_0_1, 0), (self.blocks_float_to_complex_0, 1))
self.connect((self.blocks_multiply_xx_0_1_0, 0), (self.blocks_float_to_int_0_1, 0))
self.connect((self.digital_constellation_decoder_cb_0, 0), (self.digital_diff_decoder_bb_0, 0))
self.connect((self.digital_costas_loop_cc_0, 0), (self.blocks_complex_to_float_0, 0))
self.connect((self.digital_costas_loop_cc_0, 0), (self.digital_constellation_decoder_cb_0, 0))
self.connect((self.digital_diff_decoder_bb_0, 0), (self.blocks_udp_sink_0, 0))
self.connect((self.digital_lms_dd_equalizer_cc_0, 0), (self.analog_agc2_xx_0_0, 0))
self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_lms_dd_equalizer_cc_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_xx_0_0_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_xx_0_1, 0))
self.connect((self.mmse_resampler_xx_0, 0), (self.digital_pfb_clock_sync_xxx_0, 0))
self.connect((self.mmse_resampler_xx_0_0, 0), (self.blocks_multiply_xx_0_1_0, 0))
def get_resamp(self):
return self.resamp
def set_resamp(self, resamp):
self.resamp = resamp
self.mmse_resampler_xx_0.set_resamp_ratio(self.resamp)
def get_samp_rate(self):
return self.samp_rate
def set_samp_rate(self, samp_rate):
self.samp_rate = samp_rate
self.analog_sig_source_x_0_0_0.set_sampling_freq(self.samp_rate)
self.low_pass_filter_0.set_taps(firdes.low_pass(12, self.samp_rate, 3900, 3300, firdes.WIN_HAMMING, 6.76))
self.mmse_resampler_xx_0_0.set_resamp_ratio(self.samp_rate / 8000)
def get_sps(self):
return self.sps
def set_sps(self, sps):
self.sps = sps
self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.1/float(self.sps), 0.2, 11*self.sps*self.nfilts))
def get_nfilts(self):
return self.nfilts
def set_nfilts(self, nfilts):
self.nfilts = nfilts
self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.1/float(self.sps), 0.2, 11*self.sps*self.nfilts))
def get_rrc_taps(self):
return self.rrc_taps
def set_rrc_taps(self, rrc_taps):
self.rrc_taps = rrc_taps
self.digital_pfb_clock_sync_xxx_0.update_taps(self.rrc_taps)
def get_outputsps(self):
return self.outputsps
def set_outputsps(self, outputsps):
self.outputsps = outputsps
def get_mixf(self):
return self.mixf
def set_mixf(self, mixf):
self.mixf = mixf
self.analog_sig_source_x_0_0_0.set_frequency(self.mixf)
def argument_parser():
description = 'requires GNU Radio 3.8xxx'
parser = ArgumentParser(description=description)
parser.add_argument(
"-r", "--resamp", dest="resamp", type=intx, default=6,
help="Set resamp [default=%(default)r]")
parser.add_argument(
"-s", "--samp-rate", dest="samp_rate", type=intx, default=48000,
help="Set samp_rate [default=%(default)r]")
return parser
def main(top_block_cls=rx_8psk, options=None):
if options is None:
options = argument_parser().parse_args()
tb = top_block_cls(resamp=options.resamp, samp_rate=options.samp_rate)
def sig_handler(sig=None, frame=None):
tb.stop()
tb.wait()
sys.exit(0)
signal.signal(signal.SIGINT, sig_handler)
signal.signal(signal.SIGTERM, sig_handler)
tb.start()
tb.wait()
if __name__ == '__main__':
main()

View File

@ -1,91 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
uint8_t scr[400] = {
130 , 239 , 223 , 19 , 146 , 254 , 12 , 86 , 106 , 68 ,
77 , 213 , 243 , 216 , 102 , 227 , 108 , 113 , 229 , 89 ,
26 , 64 , 138 , 216 , 225 , 121 , 194 , 137 , 152 , 64 ,
51 , 175 , 68 , 200 , 37 , 104 , 247 , 68 , 193 , 50 ,
19 , 14 , 196 , 81 , 4 , 236 , 191 , 249 , 83 , 25 ,
161 , 171 , 167 , 29 , 33 , 139 , 7 , 152 , 230 , 144 ,
125 , 206 , 34 , 236 , 112 , 78 , 219 , 34 , 181 , 161 ,
7 , 45 , 198 , 235 , 62 , 115 , 194 , 100 , 209 , 95 ,
186 , 161 , 53 , 10 , 110 , 246 , 122 , 246 , 207 , 194 ,
178 , 63 , 232 , 93 , 158 , 234 , 231 , 73 , 214 , 64,
130 , 239 , 223 , 19 , 146 , 254 , 12 , 86 , 106 , 68 ,
77 , 213 , 243 , 216 , 102 , 227 , 108 , 113 , 229 , 89 ,
26 , 64 , 138 , 216 , 225 , 121 , 194 , 137 , 152 , 64 ,
51 , 175 , 68 , 200 , 37 , 104 , 247 , 68 , 193 , 50 ,
19 , 14 , 196 , 81 , 4 , 236 , 191 , 249 , 83 , 25 ,
161 , 171 , 167 , 29 , 33 , 139 , 7 , 152 , 230 , 144 ,
125 , 206 , 34 , 236 , 112 , 78 , 219 , 34 , 181 , 161 ,
7 , 45 , 198 , 235 , 62 , 115 , 194 , 100 , 209 , 95 ,
186 , 161 , 53 , 10 , 110 , 246 , 122 , 246 , 207 , 194 ,
178 , 63 , 232 , 93 , 158 , 234 , 231 , 73 , 214 , 64,
130 , 239 , 223 , 19 , 146 , 254 , 12 , 86 , 106 , 68 ,
77 , 213 , 243 , 216 , 102 , 227 , 108 , 113 , 229 , 89 ,
26 , 64 , 138 , 216 , 225 , 121 , 194 , 137 , 152 , 64 ,
51 , 175 , 68 , 200 , 37 , 104 , 247 , 68 , 193 , 50 ,
19 , 14 , 196 , 81 , 4 , 236 , 191 , 249 , 83 , 25 ,
161 , 171 , 167 , 29 , 33 , 139 , 7 , 152 , 230 , 144 ,
125 , 206 , 34 , 236 , 112 , 78 , 219 , 34 , 181 , 161 ,
7 , 45 , 198 , 235 , 62 , 115 , 194 , 100 , 209 , 95 ,
186 , 161 , 53 , 10 , 110 , 246 , 122 , 246 , 207 , 194 ,
178 , 63 , 232 , 93 , 158 , 234 , 231 , 73 , 214 , 64,
130 , 239 , 223 , 19 , 146 , 254 , 12 , 86 , 106 , 68 ,
77 , 213 , 243 , 216 , 102 , 227 , 108 , 113 , 229 , 89 ,
26 , 64 , 138 , 216 , 225 , 121 , 194 , 137 , 152 , 64 ,
51 , 175 , 68 , 200 , 37 , 104 , 247 , 68 , 193 , 50 ,
19 , 14 , 196 , 81 , 4 , 236 , 191 , 249 , 83 , 25 ,
161 , 171 , 167 , 29 , 33 , 139 , 7 , 152 , 230 , 144 ,
125 , 206 , 34 , 236 , 112 , 78 , 219 , 34 , 181 , 161 ,
7 , 45 , 198 , 235 , 62 , 115 , 194 , 100 , 209 , 95 ,
186 , 161 , 53 , 10 , 110 , 246 , 122 , 246 , 207 , 194 ,
178 , 63 , 232 , 93 , 158 , 234 , 231 , 73 , 214 , 64
};
uint8_t rx_scrbuf[400];
void TX_Scramble(uint8_t *data, int len)
{
if (len > 400) return;
for(int i=0; i<len; i++)
data[i] ^= scr[i];
}
uint8_t *RX_Scramble(uint8_t *data, int len)
{
if (len > 400) return data;
memcpy(rx_scrbuf,data,len);
for(int i=0; i<len; i++)
rx_scrbuf[i] ^= scr[i];
return rx_scrbuf;
}

View File

@ -1,129 +0,0 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "qo100modem.h"
void *threadfunction(void *dummy);
#define MAXUDPTHREADS 20
RXCFG rxcfg[MAXUDPTHREADS];
int rxcfg_idx = 0;
// start UDP reception
// sock ... pointer to a socket (just a pointer to an int)
// port ... own port, messages only to this port are received
// rxfunc ... pointer to a callback function, will be called for received data
// keeprunning ... pointer to an int. If it is set to 0, the function exits
void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockaddr_in*), int *keeprunning)
{
if(rxcfg_idx >= MAXUDPTHREADS)
{
printf("max number of UDP threads\n");
exit(0);
}
rxcfg[rxcfg_idx].sock = sock;
rxcfg[rxcfg_idx].port = port;
rxcfg[rxcfg_idx].rxfunc = rxfunc;
rxcfg[rxcfg_idx].keeprunning = keeprunning;
// bind port
struct sockaddr_in sin;
*sock = socket(PF_INET, SOCK_DGRAM, 0);
if (*sock == -1){
printf("Failed to create Socket\n");
exit(0);
}
int enable = 1;
setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(*sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) != 0)
{
printf("Failed to bind socket, port:%d\n",port);
close(*sock);
exit(0);
}
// port sucessfully bound
// create the receive thread
pthread_t rxthread;
pthread_create(&rxthread, NULL, threadfunction, &(rxcfg[rxcfg_idx]));
rxcfg_idx++;
}
void *threadfunction(void *param)
{
RXCFG rxcfg;
memcpy((uint8_t *)(&rxcfg), (uint8_t *)param, sizeof(RXCFG));
socklen_t fromlen;
int recvlen;
char rxbuf[256];
struct sockaddr_in fromSock;
fromlen = sizeof(struct sockaddr_in);
while(*rxcfg.keeprunning)
{
recvlen = recvfrom(*rxcfg.sock, rxbuf, 256, 0, (struct sockaddr *)&fromSock, &fromlen);
if (recvlen > 0)
{
// data received, send it to callback function
(*rxcfg.rxfunc)((uint8_t *)rxbuf,recvlen, &fromSock);
}
}
return NULL;
}
// send UDP message
void sendUDP(char *destIP, int destPort, uint8_t *pdata, int len)
{
int sockfd;
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
printf("sendUDP: socket creation failed\n");
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(destPort);
//printf("Send to <%s><%d> Len:%d\n",destIP,destPort,len);
servaddr.sin_addr.s_addr=inet_addr(destIP);
sendto(sockfd, (char *)pdata, len, 0, (const struct sockaddr *) &servaddr, sizeof(servaddr));
close(sockfd);
}

View File

@ -1,9 +0,0 @@
void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockaddr_in*), int *keeprunning);
void sendUDP(char *destIP, int destPort, uint8_t *pdata, int len);
typedef struct {
int *sock;
int port;
void (*rxfunc)(uint8_t *, int, struct sockaddr_in*);
int *keeprunning;
} RXCFG;