diff --git a/.gitignore b/.gitignore index e84682e..ce1f90f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ dump978-fa skyview978 faup978 +fec_tests diff --git a/Makefile b/Makefile index bbf5e08..dfcf41b 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,9 @@ faup978: faup978_main.o socket_input.o uat_message.o track.o faup978_reporter.o skyaware978: skyaware978_main.o socket_input.o uat_message.o track.o skyaware_writer.o $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) +fec_tests: fec_tests.o libs/fec/init_rs_char.o libs/fec/decode_rs_char.o libs/fec/encode_rs_char.o + $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ + format: clang-format -style=file -i *.cc *.h diff --git a/fec_tests.cc b/fec_tests.cc new file mode 100644 index 0000000..d6d8501 --- /dev/null +++ b/fec_tests.cc @@ -0,0 +1,105 @@ +#include "uat_protocol.h" + +#include +#include +#include + +extern "C" { +#include "fec/rs.h" +} + +void test_rs_decode(unsigned seed, int trials, int symsize, int gfpoly, int fcr, int prim, int nroots, int pad) { + srand(seed); + + void *rs = ::init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad); + + int NN = (1 << symsize) - 1; + int blocklen = NN - pad; + int datalen = blocklen - nroots; + + std::vector test_block(blocklen, 0); + std::vector working_block(blocklen, 0); + + for (int trial = 0; trial < trials; ++trial) { + /* build random test data, encode it */ + for (int i = 0; i < datalen; ++i) + test_block[i] = std::rand() & NN; + + ::encode_rs_char(rs, test_block.data(), test_block.data() + datalen); + + /* test errors */ + for (int n_errors = 0; n_errors <= nroots; ++n_errors) { + working_block = test_block; + + std::vector error_val(blocklen, 0); + + /* generate errors */ + for (int i = 0; i < n_errors; ++i) { + int loc; + do { + loc = std::rand() % blocklen; + } while (error_val[loc]); + + int bits; + do { + bits = std::rand() & NN; + } while (!bits); + + error_val[loc] = bits; + working_block[loc] ^= bits; + } + + /* try to decode */ + int n_corrected = ::decode_rs_char(rs, working_block.data(), NULL, 0); + + if (n_errors > nroots / 2) { + /* exceeded error correction capacity */ + if (n_corrected >= 0) { + std::cerr << "RS(" << blocklen << "," << datalen << ") (seed: " << seed << " trial: " << trial << " errors: " << n_errors << ")" + << " returned success, but should have failed" << std::endl; + } + } else { + if (n_corrected != n_errors) { + std::cerr << "RS(" << blocklen << "," << datalen << ") (seed: " << seed << " trial: " << trial << " errors: " << n_errors << ")" + << " claimed to correct " << n_corrected << " errors" << std::endl; + } + if (working_block != test_block) { + std::cerr << "RS(" << blocklen << "," << datalen << ") (seed: " << seed << " trial: " << trial << " errors: " << n_errors << ")" + << " data wasn't corrected correctly" << std::endl; + } + } + } + } + + ::free_rs_char(rs); +} + +int main(int argc, char **argv) { + + test_rs_decode(/* seed */ 1, + /* trials */ 10000, + /* symsize */ 8, + /* gfpoly */ flightaware::uat::fec::DOWNLINK_SHORT_POLY, + /* fcr */ 120, + /* prim */ 1, + /* nroots */ flightaware::uat::fec::DOWNLINK_SHORT_ROOTS, + /* pad */ flightaware::uat::fec::DOWNLINK_SHORT_PAD); + + test_rs_decode(/* seed */ 1, + /* trials */ 10000, + /* symsize */ 8, + /* gfpoly */ flightaware::uat::fec::DOWNLINK_LONG_POLY, + /* fcr */ 120, + /* prim */ 1, + /* nroots */ flightaware::uat::fec::DOWNLINK_LONG_ROOTS, + /* pad */ flightaware::uat::fec::DOWNLINK_LONG_PAD); + + test_rs_decode(/* seed */ 1, + /* trials */ 10000, + /* symsize */ 8, + /* gfpoly */ flightaware::uat::fec::UPLINK_BLOCK_POLY, + /* fcr */ 120, + /* prim */ 1, + /* nroots */ flightaware::uat::fec::UPLINK_BLOCK_ROOTS, + /* pad */ flightaware::uat::fec::UPLINK_BLOCK_PAD); +} diff --git a/libs/fec/encode_rs.c b/libs/fec/encode_rs.c new file mode 100644 index 0000000..0649094 --- /dev/null +++ b/libs/fec/encode_rs.c @@ -0,0 +1,52 @@ +/* Reed-Solomon encoder + * Copyright 2002, Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ +#include + +#ifdef FIXED +#include "fixed.h" +#elif defined(BIGSYM) +#include "int.h" +#else +#include "char.h" +#endif + +void ENCODE_RS( +#ifdef FIXED +data_t *data, data_t *bb,int pad){ +#else +void *p,data_t *data, data_t *bb){ + struct rs *rs = (struct rs *)p; +#endif + int i, j; + data_t feedback; + +#ifdef FIXED + /* Check pad parameter for validity */ + if(pad < 0 || pad >= NN) + return; +#endif + + memset(bb,0,NROOTS*sizeof(data_t)); + + for(i=0;i) must be included by the calling + * program. + + * Copyright 2004, Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ + + +#undef A0 +#define A0 (NN) /* Special reserved value encoding zero in index form */ + +{ + int i, j; + data_t feedback; + + memset(parity,0,NROOTS*sizeof(data_t)); + + for(i=0;i + +#include "char.h" +#include "rs-common.h" + +void encode_rs_char(void *p,data_t *data, data_t *parity){ + struct rs *rs = (struct rs *)p; + +#include "encode_rs.h" + +} diff --git a/libs/fec/rs.h b/libs/fec/rs.h index 8b5ffeb..6ad7ad5 100644 --- a/libs/fec/rs.h +++ b/libs/fec/rs.h @@ -7,6 +7,7 @@ #define _FEC_RS_H_ /* General purpose RS codec, 8-bit symbols */ +void encode_rs_char(void *rs,unsigned char *data,unsigned char *parity); int decode_rs_char(void *rs,unsigned char *data,int *eras_pos, int no_eras); void *init_rs_char(int symsize,int gfpoly,