Bugfix + added M17 decoder to the linux CI

This commit is contained in:
AlexandreRouma
2021-10-02 17:01:23 +02:00
parent 26fa23c8f5
commit b4213ea049
86 changed files with 6601 additions and 20 deletions

View File

@ -0,0 +1,30 @@
#ifndef CORRECT_SSE_H
#define CORRECT_SSE_H
#include <correct.h>
struct correct_convolutional_sse;
typedef struct correct_convolutional_sse correct_convolutional_sse;
/* SSE versions of libcorrect's convolutional encoder/decoder.
* These instances should not be used with the non-sse functions,
* and non-sse instances should not be used with the sse functions.
*/
correct_convolutional_sse *correct_convolutional_sse_create(
size_t rate, size_t order, const correct_convolutional_polynomial_t *poly);
void correct_convolutional_sse_destroy(correct_convolutional_sse *conv);
size_t correct_convolutional_sse_encode_len(correct_convolutional_sse *conv, size_t msg_len);
size_t correct_convolutional_sse_encode(correct_convolutional_sse *conv, const uint8_t *msg,
size_t msg_len, uint8_t *encoded);
ssize_t correct_convolutional_sse_decode(correct_convolutional_sse *conv, const uint8_t *encoded,
size_t num_encoded_bits, uint8_t *msg);
ssize_t correct_convolutional_sse_decode_soft(correct_convolutional_sse *conv,
const correct_convolutional_soft_t *encoded,
size_t num_encoded_bits, uint8_t *msg);
#endif

View File

@ -0,0 +1,277 @@
#ifndef CORRECT_H
#define CORRECT_H
#include <stdint.h>
#ifndef _MSC_VER
#include <unistd.h>
#else
#include <stddef.h>
typedef ptrdiff_t ssize_t;
#endif
// Convolutional Codes
// Convolutional polynomials are 16 bits wide
typedef uint16_t correct_convolutional_polynomial_t;
static const correct_convolutional_polynomial_t correct_conv_r12_6_polynomial[] = {073, 061};
static const correct_convolutional_polynomial_t correct_conv_r12_7_polynomial[] = {0161, 0127};
static const correct_convolutional_polynomial_t correct_conv_r12_8_polynomial[] = {0225, 0373};
static const correct_convolutional_polynomial_t correct_conv_r12_9_polynomial[] = {0767, 0545};
static const correct_convolutional_polynomial_t correct_conv_r13_6_polynomial[] = {053, 075, 047};
static const correct_convolutional_polynomial_t correct_conv_r13_7_polynomial[] = {0137, 0153,
0121};
static const correct_convolutional_polynomial_t correct_conv_r13_8_polynomial[] = {0333, 0257,
0351};
static const correct_convolutional_polynomial_t correct_conv_r13_9_polynomial[] = {0417, 0627,
0675};
typedef uint8_t correct_convolutional_soft_t;
struct correct_convolutional;
typedef struct correct_convolutional correct_convolutional;
/* correct_convolutional_create allocates and initializes an encoder/decoder for
* a convolutional code with the given parameters. This function expects that
* poly will contain inv_rate elements. E.g., to create a conv. code instance
* with rate 1/2, order 7 and polynomials 0161, 0127, call
* correct_convolutional_create(2, 7, []correct_convolutional_polynomial_t{0161, 0127});
*
* If this call is successful, it returns a non-NULL pointer.
*/
correct_convolutional *correct_convolutional_create(size_t inv_rate, size_t order,
const correct_convolutional_polynomial_t *poly);
/* correct_convolutional_destroy releases all resources associated
* with conv. This pointer should not be used for further calls
* after calling destroy.
*/
void correct_convolutional_destroy(correct_convolutional *conv);
/* correct_convolutional_encode_len returns the number of *bits*
* in a msg_len of given size, in *bytes*. In order to convert
* this returned length to bytes, save the result of the length
* modulo 8. If it's nonzero, then the length in bytes is
* length/8 + 1. If it is zero, then the length is just
* length/8.
*/
size_t correct_convolutional_encode_len(correct_convolutional *conv, size_t msg_len);
/* correct_convolutional_encode uses the given conv instance to
* encode a block of data and write it to encoded. The length of
* encoded must be long enough to hold the resulting encoded length,
* which can be calculated by calling correct_convolutional_encode_len.
* However, this length should first be converted to bytes, as that
* function returns the length in bits.
*
* This function returns the number of bits written to encoded. If
* this is not an exact multiple of 8, then it occupies an additional
* byte.
*/
size_t correct_convolutional_encode(correct_convolutional *conv, const uint8_t *msg, size_t msg_len,
uint8_t *encoded);
/* correct_convolutional_decode uses the given conv instance to
* decode a block encoded by correct_convolutional_encode. This
* call can cope with some bits being corrupted. This function
* cannot detect if there are too many bits corrupted, however,
* and will still write a message even if it is not recovered
* correctly. It is up to the user to perform checksums or CRC
* in order to guarantee that the decoded message is intact.
*
* num_encoded_bits should contain the length of encoded in *bits*.
* This value need not be an exact multiple of 8. However,
* it must be a multiple of the inv_rate used to create
* the conv instance.
*
* This function writes the result to msg, which must be large
* enough to hold the decoded message. A good conservative size
* for this buffer is the number of encoded bits multiplied by the
* rate of the code, e.g. for a rate 1/2 code, divide by 2. This
* value should then be converted to bytes to find the correct
* length for msg.
*
* This function returns the number of bytes written to msg. If
* it fails, it returns -1.
*/
ssize_t correct_convolutional_decode(correct_convolutional *conv, const uint8_t *encoded,
size_t num_encoded_bits, uint8_t *msg);
/* correct_convolutional_decode_soft uses the given conv instance
* to decode a block encoded by correct_convolutional_encode and
* then modulated/demodulated to 8-bit symbols. This function expects
* that 1 is mapped to 255 and 0 to 0. An erased symbol should be
* set to 128. The decoded message may contain errors.
*
* num_encoded_bits should contain the length of encoded in *bits*.
* This value need not be an exact multiple of 8. However,
* it must be a multiple of the inv_rate used to create
* the conv instance.
*
* This function writes the result to msg, which must be large
* enough to hold the decoded message. A good conservative size
* for this buffer is the number of encoded bits multiplied by the
* rate of the code, e.g. for a rate 1/2 code, divide by 2. This
* value should then be converted to bytes to find the correct
* length for msg.
*
* This function returns the number of bytes written to msg. If
* it fails, it returns -1.
*/
ssize_t correct_convolutional_decode_soft(correct_convolutional *conv,
const correct_convolutional_soft_t *encoded,
size_t num_encoded_bits, uint8_t *msg);
// Reed-Solomon
struct correct_reed_solomon;
typedef struct correct_reed_solomon correct_reed_solomon;
static const uint16_t correct_rs_primitive_polynomial_8_4_3_2_0 =
0x11d; // x^8 + x^4 + x^3 + x^2 + 1
static const uint16_t correct_rs_primitive_polynomial_8_5_3_1_0 =
0x12b; // x^8 + x^5 + x^3 + x + 1
static const uint16_t correct_rs_primitive_polynomial_8_5_3_2_0 =
0x12d; // x^8 + x^5 + x^3 + x^2 + 1
static const uint16_t correct_rs_primitive_polynomial_8_6_3_2_0 =
0x14d; // x^8 + x^6 + x^3 + x^2 + 1
static const uint16_t correct_rs_primitive_polynomial_8_6_4_3_2_1_0 =
0x15f; // x^8 + x^6 + x^4 + x^3 + x^2 + x + 1;
static const uint16_t correct_rs_primitive_polynomial_8_6_5_1_0 =
0x163; // x^8 + x^6 + x^5 + x + 1
static const uint16_t correct_rs_primitive_polynomial_8_6_5_2_0 =
0x165; // x^8 + x^6 + x^5 + x^2 + 1
static const uint16_t correct_rs_primitive_polynomial_8_6_5_3_0 =
0x169; // x^8 + x^6 + x^5 + x^3 + 1
static const uint16_t correct_rs_primitive_polynomial_8_6_5_4_0 =
0x171; // x^8 + x^6 + x^5 + x^4 + 1
static const uint16_t correct_rs_primitive_polynomial_8_7_2_1_0 =
0x187; // x^8 + x^7 + x^2 + x + 1
static const uint16_t correct_rs_primitive_polynomial_8_7_3_2_0 =
0x18d; // x^8 + x^7 + x^3 + x^2 + 1
static const uint16_t correct_rs_primitive_polynomial_8_7_5_3_0 =
0x1a9; // x^8 + x^7 + x^5 + x^3 + 1
static const uint16_t correct_rs_primitive_polynomial_8_7_6_1_0 =
0x1c3; // x^8 + x^7 + x^6 + x + 1
static const uint16_t correct_rs_primitive_polynomial_8_7_6_3_2_1_0 =
0x1cf; // x^8 + x^7 + x^6 + x^3 + x^2 + x + 1
static const uint16_t correct_rs_primitive_polynomial_8_7_6_5_2_1_0 =
0x1e7; // x^8 + x^7 + x^6 + x^5 + x^2 + x + 1
static const uint16_t correct_rs_primitive_polynomial_8_7_6_5_4_2_0 =
0x1f5; // x^8 + x^7 + x^6 + x^5 + x^4 + x^2 + 1
static const uint16_t correct_rs_primitive_polynomial_ccsds =
0x187; // x^8 + x^7 + x^2 + x + 1
/* correct_reed_solomon_create allocates and initializes an
* encoder/decoder for a given reed solomon error correction
* code. The block size must be 255 bytes with 8-bit symbols.
*
* This block can repair corrupted bytes. It can handle as
* many as num_roots/2 bytes having corruption and still recover
* the encoded payload. However, using more num_roots
* adds more parity overhead and substantially increases
* the computational time for decoding.
*
* primitive_polynomial should be one of the given values in this
* file. Sane values for first_consecutive_root and
* generator_root_gap are 1 and 1. Not all combinations of
* values produce valid codes.
*/
correct_reed_solomon *correct_reed_solomon_create(uint16_t primitive_polynomial,
uint8_t first_consecutive_root,
uint8_t generator_root_gap,
size_t num_roots);
/* correct_reed_solomon_encode uses the rs instance to encode
* parity information onto a block of data. msg_length should be
* no more than the payload size for one block e.g. no more
* than 223 for a (255, 223) code. Shorter blocks will be encoded
* with virtual padding where the padding is not emitted.
*
* encoded should be at least msg_length + parity length bytes long
*
* It is allowable for msg and encoded to be the same pointer. In
* that case, the parity bytes will be written after the msg bytes
* end.
*
* This function returns the number of bytes written to encoded.
*/
ssize_t correct_reed_solomon_encode(correct_reed_solomon *rs, const uint8_t *msg, size_t msg_length,
uint8_t *encoded);
/* correct_reed_solomon_decode uses the rs instance to decode
* a payload from a block containing payload and parity bytes.
* This function can recover in spite of some bytes being corrupted.
*
* In most cases, if the block is too corrupted, this function
* will return -1 and not perform decoding. It is possible but
* unlikely that the payload written to msg will contain
* errors when this function returns a positive value.
*
* msg should be long enough to contain a decoded payload for
* this encoded block.
*
* This function returns a positive number of bytes written to msg
* if it has decoded or -1 if it has encountered an error.
*/
ssize_t correct_reed_solomon_decode(correct_reed_solomon *rs, const uint8_t *encoded,
size_t encoded_length, uint8_t *msg);
/* correct_reed_solomon_decode_with_erasures uses the rs
* instance to decode a payload from a block containing payload
* and parity bytes. Additionally, the user can provide the
* indices of bytes which have been suspected to be corrupted.
* This erasure information is typically provided by a demodulating
* or receiving device. This function can recover with
* some additional errors on top of the erasures.
*
* In order to successfully decode, the quantity
* (num_erasures + 2*num_errors) must be less than
* num_roots.
*
* erasure_locations shold contain erasure_length items.
* erasure_length should not exceed the number of parity
* bytes encoded into this block.
*
* In most cases, if the block is too corrupted, this function
* will return -1 and not perform decoding. It is possible but
* unlikely that the payload written to msg will contain
* errors when this function returns a positive value.
*
* msg should be long enough to contain a decoded payload for
* this encoded block.
*
* This function returns a positive number of bytes written to msg
* if it has decoded or -1 if it has encountered an error.
*/
ssize_t correct_reed_solomon_decode_with_erasures(correct_reed_solomon *rs, const uint8_t *encoded,
size_t encoded_length,
const uint8_t *erasure_locations,
size_t erasure_length, uint8_t *msg);
/* correct_reed_solomon_destroy releases the resources
* associated with rs. This pointer should not be
* used for any functions after this call.
*/
void correct_reed_solomon_destroy(correct_reed_solomon *rs);
#endif

View File

@ -0,0 +1,28 @@
#ifndef CORRECT_CONVOLUTIONAL
#define CORRECT_CONVOLUTIONAL
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include "correct.h"
#include "correct/portable.h"
typedef unsigned int shift_register_t;
typedef uint16_t polynomial_t;
typedef uint64_t path_t;
typedef uint8_t soft_t;
static const soft_t soft_max = UINT8_MAX;
typedef uint16_t distance_t;
static const distance_t distance_max = UINT16_MAX;
typedef enum {
CORRECT_SOFT_LINEAR,
CORRECT_SOFT_QUADRATIC,
} soft_measurement_t;
#endif

View File

@ -0,0 +1,44 @@
#ifndef CORRECT_CONVOLUTIONAL_BIT
#define CORRECT_CONVOLUTIONAL_BIT
#include "correct/convolutional.h"
typedef struct {
uint8_t current_byte;
unsigned int current_byte_len;
uint8_t *bytes;
size_t byte_index;
size_t len;
} bit_writer_t;
bit_writer_t *bit_writer_create(uint8_t *bytes, size_t len);
void bit_writer_reconfigure(bit_writer_t *w, uint8_t *bytes, size_t len);
void bit_writer_destroy(bit_writer_t *w);
void bit_writer_write(bit_writer_t *w, uint8_t val, unsigned int n);
void bit_writer_write_1(bit_writer_t *w, uint8_t val);
void bit_writer_write_bitlist_reversed(bit_writer_t *w, uint8_t *l, size_t len);
void bit_writer_flush_byte(bit_writer_t *w);
size_t bit_writer_length(bit_writer_t *w);
typedef struct {
uint8_t current_byte;
size_t byte_index;
size_t len;
size_t current_byte_len;
const uint8_t *bytes;
} bit_reader_t;
bit_reader_t *bit_reader_create(const uint8_t *bytes, size_t len);
void bit_reader_reconfigure(bit_reader_t *r, const uint8_t *bytes, size_t len);
void bit_reader_destroy(bit_reader_t *r);
uint8_t bit_reader_read(bit_reader_t *r, unsigned int n);
#endif

View File

@ -0,0 +1,40 @@
#ifndef CORRECT_CONVOLUTIONAL_H
#define CORRECT_CONVOLUTIONAL_H
#include "correct/convolutional.h"
#include "correct/convolutional/bit.h"
#include "correct/convolutional/metric.h"
#include "correct/convolutional/lookup.h"
#include "correct/convolutional/history_buffer.h"
#include "correct/convolutional/error_buffer.h"
struct correct_convolutional {
const unsigned int *table; // size 2**order
size_t rate; // e.g. 2, 3...
size_t order; // e.g. 7, 9...
unsigned int numstates; // 2**order
bit_writer_t *bit_writer;
bit_reader_t *bit_reader;
bool has_init_decode;
distance_t *distances;
pair_lookup_t pair_lookup;
soft_measurement_t soft_measurement;
history_buffer *history_buffer;
error_buffer_t *errors;
};
correct_convolutional *_correct_convolutional_init(correct_convolutional *conv,
size_t rate, size_t order,
const polynomial_t *poly);
void _correct_convolutional_teardown(correct_convolutional *conv);
// portable versions
void _convolutional_decode_init(correct_convolutional *conv, unsigned int min_traceback, unsigned int traceback_length, unsigned int renormalize_interval);
void convolutional_decode_warmup(correct_convolutional *conv, unsigned int sets,
const uint8_t *soft);
void convolutional_decode_inner(correct_convolutional *conv, unsigned int sets,
const uint8_t *soft);
void convolutional_decode_tail(correct_convolutional *conv, unsigned int sets,
const uint8_t *soft);
#endif

View File

@ -0,0 +1,15 @@
#include "correct/convolutional.h"
typedef struct {
unsigned int index;
distance_t *errors[2];
unsigned int num_states;
const distance_t *read_errors;
distance_t *write_errors;
} error_buffer_t;
error_buffer_t *error_buffer_create(unsigned int num_states);
void error_buffer_destroy(error_buffer_t *buf);
void error_buffer_reset(error_buffer_t *buf);
void error_buffer_swap(error_buffer_t *buf);

View File

@ -0,0 +1,59 @@
#include "correct/convolutional.h"
#include "correct/convolutional/bit.h"
// ring buffer of path histories
// generates output bits after accumulating sufficient history
typedef struct {
// history entries must be at least this old to be decoded
const unsigned int min_traceback_length;
// we'll decode entries in bursts. this tells us the length of the burst
const unsigned int traceback_group_length;
// we will store a total of cap entries. equal to min_traceback_length +
// traceback_group_length
const unsigned int cap;
// how many states in the shift register? this is one of the dimensions of
// history table
const unsigned int num_states;
// what's the high order bit of the shift register?
const shift_register_t highbit;
// history is a compact history representation for every shift register
// state,
// one bit per time slice
uint8_t **history;
// which slice are we writing next?
unsigned int index;
// how many valid entries are there?
unsigned int len;
// temporary store of fetched bits
uint8_t *fetched;
// how often should we renormalize?
unsigned int renormalize_interval;
unsigned int renormalize_counter;
} history_buffer;
history_buffer *history_buffer_create(unsigned int min_traceback_length,
unsigned int traceback_group_length,
unsigned int renormalize_interval,
unsigned int num_states,
shift_register_t highbit);
void history_buffer_destroy(history_buffer *buf);
void history_buffer_reset(history_buffer *buf);
void history_buffer_step(history_buffer *buf);
uint8_t *history_buffer_get_slice(history_buffer *buf);
shift_register_t history_buffer_search(history_buffer *buf,
const distance_t *distances,
unsigned int search_every);
void history_buffer_traceback(history_buffer *buf, shift_register_t bestpath,
unsigned int min_traceback_length,
bit_writer_t *output);
void history_buffer_process_skip(history_buffer *buf, distance_t *distances,
bit_writer_t *output, unsigned int skip);
void history_buffer_process(history_buffer *buf, distance_t *distances,
bit_writer_t *output);
void history_buffer_flush(history_buffer *buf, bit_writer_t *output);

View File

@ -0,0 +1,27 @@
#ifndef CORRECT_CONVOLUTIONAL_LOOKUP
#define CORRECT_CONVOLUTIONAL_LOOKUP
#include "correct/convolutional.h"
typedef unsigned int distance_pair_key_t;
typedef uint32_t output_pair_t;
typedef uint32_t distance_pair_t;
typedef struct {
distance_pair_key_t *keys;
output_pair_t *outputs;
output_pair_t output_mask;
unsigned int output_width;
size_t outputs_len;
distance_pair_t *distances;
} pair_lookup_t;
void fill_table(unsigned int order,
unsigned int rate,
const polynomial_t *poly,
unsigned int *table);
pair_lookup_t pair_lookup_create(unsigned int rate,
unsigned int order,
const unsigned int *table);
void pair_lookup_destroy(pair_lookup_t pairs);
void pair_lookup_fill_distance(pair_lookup_t pairs, distance_t *distances);
#endif

View File

@ -0,0 +1,20 @@
#include "correct/convolutional.h"
// measure the hamming distance of two bit strings
// implemented as population count of x XOR y
static inline distance_t metric_distance(unsigned int x, unsigned int y) {
return popcount(x ^ y);
}
static inline distance_t metric_soft_distance_linear(unsigned int hard_x, const uint8_t *soft_y, size_t len) {
distance_t dist = 0;
for (unsigned int i = 0; i < len; i++) {
unsigned int soft_x = ((int8_t)(0) - (hard_x & 1)) & 0xff;
hard_x >>= 1;
int d = soft_y[i] - soft_x;
dist += (d < 0) ? -d : d;
}
return dist;
}
distance_t metric_soft_distance_quadratic(unsigned int hard_x, const uint8_t *soft_y, size_t len);

View File

@ -0,0 +1,15 @@
#include "correct/convolutional/convolutional.h"
#include "correct/convolutional/sse/lookup.h"
// BIG HEAPING TODO sort out the include mess
#include "correct-sse.h"
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
struct correct_convolutional_sse {
correct_convolutional base_conv;
oct_lookup_t oct_lookup;
};

View File

@ -0,0 +1,65 @@
#include "correct/convolutional/lookup.h"
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
typedef unsigned int distance_quad_key_t;
typedef unsigned int output_quad_t;
typedef uint64_t distance_quad_t;
typedef struct {
distance_quad_key_t *keys;
output_quad_t *outputs;
output_quad_t output_mask;
unsigned int output_width;
size_t outputs_len;
distance_quad_t *distances;
} quad_lookup_t;
typedef uint16_t distance_oct_key_t;
typedef uint64_t output_oct_t;
typedef uint64_t distance_oct_t;
typedef struct {
distance_oct_key_t *keys;
output_oct_t *outputs;
output_oct_t output_mask;
unsigned int output_width;
size_t outputs_len;
distance_oct_t *distances;
} oct_lookup_t;
quad_lookup_t quad_lookup_create(unsigned int rate,
unsigned int order,
const unsigned int *table);
void quad_lookup_destroy(quad_lookup_t quads);
void quad_lookup_fill_distance(quad_lookup_t quads, distance_t *distances);
distance_oct_key_t oct_lookup_find_key(output_oct_t *outputs, output_oct_t out, size_t num_keys);
oct_lookup_t oct_lookup_create(unsigned int rate,
unsigned int order,
const unsigned int *table);
void oct_lookup_destroy(oct_lookup_t octs);
static inline void oct_lookup_fill_distance(oct_lookup_t octs, distance_t *distances) {
distance_pair_t *pairs = (distance_pair_t*)octs.distances;
for (unsigned int i = 1; i < octs.outputs_len; i += 1) {
output_oct_t concat_out = octs.outputs[i];
unsigned int i_0 = concat_out & 0xff;
unsigned int i_1 = (concat_out >> 8) & 0xff;
unsigned int i_2 = (concat_out >> 16) & 0xff;
unsigned int i_3 = (concat_out >> 24) & 0xff;
pairs[i*4 + 1] = distances[i_3] << 16 | distances[i_2];
pairs[i*4 + 0] = distances[i_1] << 16 | distances[i_0];
concat_out >>= 32;
unsigned int i_4 = concat_out & 0xff;
unsigned int i_5 = (concat_out >> 8) & 0xff;
unsigned int i_6 = (concat_out >> 16) & 0xff;
unsigned int i_7 = (concat_out >> 24) & 0xff;
pairs[i*4 + 3] = distances[i_7] << 16 | distances[i_6];
pairs[i*4 + 2] = distances[i_5] << 16 | distances[i_4];
}
}

View File

@ -0,0 +1,20 @@
#ifdef __GNUC__
#define HAVE_BUILTINS
#endif
#ifdef HAVE_BUILTINS
#define popcount __builtin_popcount
#define prefetch __builtin_prefetch
#else
static inline int popcount(int x) {
/* taken from the helpful http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel */
x = x - ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
return ((x + (x >> 4) & 0x0f0f0f0f) * 0x01010101) >> 24;
}
static inline void prefetch(void *x) {}
#endif

View File

@ -0,0 +1,76 @@
#ifndef CORRECT_REED_SOLOMON
#define CORRECT_REED_SOLOMON
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <stdint.h>
#include "correct.h"
#include "correct/portable.h"
// an element in GF(2^8)
typedef uint8_t field_element_t;
// a power of the primitive element alpha
typedef uint8_t field_logarithm_t;
// give us some bits of headroom to do arithmetic
// variables of this type aren't really in any proper space
typedef uint16_t field_operation_t;
// generated by find_poly
typedef struct {
const field_element_t *exp;
const field_logarithm_t *log;
} field_t;
typedef struct {
field_element_t *coeff;
unsigned int order;
} polynomial_t;
struct correct_reed_solomon {
size_t block_length;
size_t message_length;
size_t min_distance;
field_logarithm_t first_consecutive_root;
field_logarithm_t generator_root_gap;
field_t field;
polynomial_t generator;
field_element_t *generator_roots;
field_logarithm_t **generator_root_exp;
polynomial_t encoded_polynomial;
polynomial_t encoded_remainder;
field_element_t *syndromes;
field_element_t *modified_syndromes;
polynomial_t received_polynomial;
polynomial_t error_locator;
polynomial_t error_locator_log;
polynomial_t erasure_locator;
field_element_t *error_roots;
field_element_t *error_vals;
field_logarithm_t *error_locations;
field_logarithm_t **element_exp;
// scratch
// (do no allocations at steady state)
// used during find_error_locator
polynomial_t last_error_locator;
// used during error value search
polynomial_t error_evaluator;
polynomial_t error_locator_derivative;
polynomial_t init_from_roots_scratch[2];
bool has_init_decode;
};
#endif

View File

@ -0,0 +1,3 @@
#include "correct/reed-solomon.h"
#include "correct/reed-solomon/field.h"
#include "correct/reed-solomon/polynomial.h"

View File

@ -0,0 +1,3 @@
#include "correct/reed-solomon.h"
#include "correct/reed-solomon/field.h"
#include "correct/reed-solomon/polynomial.h"

View File

@ -0,0 +1,167 @@
#ifndef CORRECT_REED_SOLOMON_FIELD
#define CORRECT_REED_SOLOMON_FIELD
#include "correct/reed-solomon.h"
/*
field_t field_create(field_operation_t primitive_poly);
void field_destroy(field_t field);
field_element_t field_add(field_t field, field_element_t l, field_element_t r);
field_element_t field_sub(field_t field, field_element_t l, field_element_t r);
field_element_t field_sum(field_t field, field_element_t elem, unsigned int n);
field_element_t field_mul(field_t field, field_element_t l, field_element_t r);
field_element_t field_div(field_t field, field_element_t l, field_element_t r);
field_logarithm_t field_mul_log(field_t field, field_logarithm_t l, field_logarithm_t r);
field_logarithm_t field_div_log(field_t field, field_logarithm_t l, field_logarithm_t r);
field_element_t field_mul_log_element(field_t field, field_logarithm_t l, field_logarithm_t r);
field_element_t field_pow(field_t field, field_element_t elem, int pow);
*/
static inline field_element_t field_mul_log_element(field_t field, field_logarithm_t l, field_logarithm_t r) {
// like field_mul_log, but returns a field_element_t
// because we are doing lookup here, we can safely skip the wrapover check
field_operation_t res = (field_operation_t)l + (field_operation_t)r;
return field.exp[res];
}
static inline field_t field_create(field_operation_t primitive_poly) {
// in GF(2^8)
// log and exp
// bits are in GF(2), compute alpha^val in GF(2^8)
// exp should be of size 512 so that it can hold a "wraparound" which prevents some modulo ops
// log should be of size 256. no wraparound here, the indices into this table are field elements
field_element_t *exp = malloc(512 * sizeof(field_element_t));
field_logarithm_t *log = malloc(256 * sizeof(field_logarithm_t));
// assume alpha is a primitive element, p(x) (primitive_poly) irreducible in GF(2^8)
// addition is xor
// subtraction is addition (also xor)
// e.g. x^5 + x^4 + x^4 + x^2 + 1 = x^5 + x^2 + 1
// each row of exp contains the field element found by exponentiating
// alpha by the row index
// each row of log contains the coefficients of
// alpha^7 + alpha^6 + alpha^5 + alpha^4 + alpha^3 + alpha^2 + alpha + 1
// as 8 bits packed into one byte
field_operation_t element = 1;
exp[0] = (field_element_t)element;
log[0] = (field_logarithm_t)0; // really, it's undefined. we shouldn't ever access this
for (field_operation_t i = 1; i < 512; i++) {
element = element * 2;
element = (element > 255) ? (element ^ primitive_poly) : element;
exp[i] = (field_element_t)element;
if (i < 256) {
log[element] = (field_logarithm_t)i;
}
}
field_t field;
*(field_element_t **)&field.exp = exp;
*(field_logarithm_t **)&field.log = log;
return field;
}
static inline void field_destroy(field_t field) {
free(*(field_element_t **)&field.exp);
free(*(field_element_t **)&field.log);
}
static inline field_element_t field_add(field_t field, field_element_t l, field_element_t r) {
return l ^ r;
}
static inline field_element_t field_sub(field_t field, field_element_t l, field_element_t r) {
return l ^ r;
}
static inline field_element_t field_sum(field_t field, field_element_t elem, unsigned int n) {
// we'll do a closed-form expression of the sum, although we could also
// choose to call field_add n times
// since the sum is actually the bytewise XOR operator, this suggests two
// kinds of values: n odd, and n even
// if you sum once, you have coeff
// if you sum twice, you have coeff XOR coeff = 0
// if you sum thrice, you are back at coeff
// an even number of XORs puts you at 0
// an odd number of XORs puts you back at your value
// so, just throw away all the even n
return (n % 2) ? elem : 0;
}
static inline field_element_t field_mul(field_t field, field_element_t l, field_element_t r) {
if (l == 0 || r == 0) {
return 0;
}
// multiply two field elements by adding their logarithms.
// yep, get your slide rules out
field_operation_t res = (field_operation_t)field.log[l] + (field_operation_t)field.log[r];
// if coeff exceeds 255, we would normally have to wrap it back around
// alpha^255 = 1; alpha^256 = alpha^255 * alpha^1 = alpha^1
// however, we've constructed exponentiation table so that
// we can just directly lookup this result
// the result must be clamped to [0, 511]
// the greatest we can see at this step is alpha^255 * alpha^255
// = alpha^510
return field.exp[res];
}
static inline field_element_t field_div(field_t field, field_element_t l, field_element_t r) {
if (l == 0) {
return 0;
}
if (r == 0) {
// XXX ???
return 0;
}
// division as subtraction of logarithms
// if rcoeff is larger, then log[l] - log[r] wraps under
// so, instead, always add 255. in some cases, we'll wrap over, but
// that's ok because the exp table runs up to 511.
field_operation_t res = (field_operation_t)255 + (field_operation_t)field.log[l] - (field_operation_t)field.log[r];
return field.exp[res];
}
static inline field_logarithm_t field_mul_log(field_t field, field_logarithm_t l, field_logarithm_t r) {
// this function performs the equivalent of field_mul on two logarithms
// we save a little time by skipping the lookup step at the beginning
field_operation_t res = (field_operation_t)l + (field_operation_t)r;
// because we arent using the table, the value we return must be a valid logarithm
// which we have decided must live in [0, 255] (they are 8-bit values)
// ensuring this makes it so that multiple muls will not reach past the end of the
// exp table whenever we finally convert back to an element
if (res > 255) {
return (field_logarithm_t)(res - 255);
}
return (field_logarithm_t)res;
}
static inline field_logarithm_t field_div_log(field_t field, field_logarithm_t l, field_logarithm_t r) {
// like field_mul_log, this performs field_div without going through a field_element_t
field_operation_t res = (field_operation_t)255 + (field_operation_t)l - (field_operation_t)r;
if (res > 255) {
return (field_logarithm_t)(res - 255);
}
return (field_logarithm_t)res;
}
static inline field_element_t field_pow(field_t field, field_element_t elem, int pow) {
// take the logarithm, multiply, and then "exponentiate"
// n.b. the exp table only considers powers of alpha, the primitive element
// but here we have an arbitrary coeff
field_logarithm_t log = field.log[elem];
int res_log = log * pow;
int mod = res_log % 255;
if (mod < 0) {
mod += 255;
}
return field.exp[mod];
}
#endif

View File

@ -0,0 +1,14 @@
#include "correct/reed-solomon.h"
#include "correct/reed-solomon/field.h"
polynomial_t polynomial_create(unsigned int order);
void polynomial_destroy(polynomial_t polynomial);
void polynomial_mul(field_t field, polynomial_t l, polynomial_t r, polynomial_t res);
void polynomial_mod(field_t field, polynomial_t dividend, polynomial_t divisor, polynomial_t mod);
void polynomial_formal_derivative(field_t field, polynomial_t poly, polynomial_t der);
field_element_t polynomial_eval(field_t field, polynomial_t poly, field_element_t val);
field_element_t polynomial_eval_lut(field_t field, polynomial_t poly, const field_logarithm_t *val_exp);
field_element_t polynomial_eval_log_lut(field_t field, polynomial_t poly_log, const field_logarithm_t *val_exp);
void polynomial_build_exp_lut(field_t field, field_element_t val, unsigned int order, field_logarithm_t *val_exp);
polynomial_t polynomial_init_from_roots(field_t field, unsigned int nroots, field_element_t *roots, polynomial_t poly, polynomial_t *scratch);
polynomial_t polynomial_create_from_roots(field_t field, unsigned int nroots, field_element_t *roots);

View File

@ -0,0 +1,3 @@
#include "correct/reed-solomon.h"
#include "correct/reed-solomon/field.h"
#include "correct/reed-solomon/polynomial.h"

View File

@ -0,0 +1,8 @@
#include "correct/util/error-sim.h"
#include <fec.h>
void conv_fec27_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);
void conv_fec29_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);
void conv_fec39_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);
void conv_fec615_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);

View File

@ -0,0 +1,7 @@
#include "correct/util/error-sim.h"
#include "fec_shim.h"
ssize_t conv_shim27_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);
ssize_t conv_shim29_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);
ssize_t conv_shim39_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);
ssize_t conv_shim615_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);

View File

@ -0,0 +1,7 @@
#include "correct/util/error-sim.h"
#include "correct-sse.h"
size_t conv_correct_sse_enclen(void *conv_v, size_t msg_len);
void conv_correct_sse_encode(void *conv_v, uint8_t *msg, size_t msg_len, uint8_t *encoded);
ssize_t conv_correct_sse_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);

View File

@ -0,0 +1,47 @@
#include <stdbool.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <float.h>
#include <stdio.h>
#include "correct.h"
#include "correct/portable.h"
size_t distance(uint8_t *a, uint8_t *b, size_t len);
void gaussian(double *res, size_t n_res, double sigma);
void encode_bpsk(uint8_t *msg, double *voltages, size_t n_syms, double bpsk_voltage);
void byte2bit(uint8_t *bytes, uint8_t *bits, size_t n_bits);
void decode_bpsk(uint8_t *soft, uint8_t *msg, size_t n_syms);
void decode_bpsk_soft(double *voltages, uint8_t *soft, size_t n_syms, double bpsk_voltage);
double log2amp(double l);
double amp2log(double a);
double sigma_for_eb_n0(double eb_n0, double bpsk_bit_energy);
void build_white_noise(double *noise, size_t n_syms, double eb_n0, double bpsk_bit_energy);
void add_white_noise(double *signal, double *noise, size_t n_syms);
typedef struct {
uint8_t *msg_out;
size_t msg_len;
uint8_t *encoded;
double *v;
double *corrupted;
uint8_t *soft;
double *noise;
size_t enclen;
size_t enclen_bytes;
void (*encode)(void *, uint8_t *msg, size_t msg_len, uint8_t *encoded);
void *encoder;
ssize_t (*decode)(void *, uint8_t *soft, size_t soft_len, uint8_t *msg);
void *decoder;
} conv_testbench;
conv_testbench *resize_conv_testbench(conv_testbench *scratch, size_t (*enclen)(void *, size_t), void *enc, size_t msg_len);
void free_scratch(conv_testbench *scratch);
int test_conv_noise(conv_testbench *scratch, uint8_t *msg, size_t n_bytes,
double bpsk_voltage);
size_t conv_correct_enclen(void *conv_v, size_t msg_len);
void conv_correct_encode(void *conv_v, uint8_t *msg, size_t msg_len, uint8_t *encoded);
ssize_t conv_correct_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg);

View File

@ -0,0 +1,74 @@
#ifndef CORRECT_FEC_H
#define CORRECT_FEC_H
// libcorrect's libfec shim header
// this is a partial implementation of libfec
// header signatures derived from found usages of libfec -- some things may be different
#include <correct.h>
// Reed-Solomon
void *init_rs_char(int symbol_size, int primitive_polynomial, int first_consecutive_root,
int root_gap, int number_roots, unsigned int pad);
void free_rs_char(void *rs);
void encode_rs_char(void *rs, const unsigned char *msg, unsigned char *parity);
void decode_rs_char(void *rs, unsigned char *block, int *erasure_locations, int num_erasures);
// Convolutional Codes
// Polynomials
// These have been determined via find_conv_libfec_poly.c
// We could just make up new ones, but we use libfec's here so that
// codes encoded by this library can be decoded by the original libfec
// and vice-versa
#define V27POLYA 0155
#define V27POLYB 0117
#define V29POLYA 0657
#define V29POLYB 0435
#define V39POLYA 0755
#define V39POLYB 0633
#define V39POLYC 0447
#define V615POLYA 042631
#define V615POLYB 047245
#define V615POLYC 056507
#define V615POLYD 073363
#define V615POLYE 077267
#define V615POLYF 064537
// Convolutional Methods
void *create_viterbi27(int num_decoded_bits);
int init_viterbi27(void *vit, int _mystery);
int update_viterbi27_blk(void *vit, unsigned char *encoded_soft, int n_encoded_groups);
int chainback_viterbi27(void *vit, unsigned char *decoded, unsigned int n_decoded_bits, unsigned int _mystery);
void delete_viterbi27(void *vit);
void *create_viterbi29(int num_decoded_bits);
int init_viterbi29(void *vit, int _mystery);
int update_viterbi29_blk(void *vit, unsigned char *encoded_soft, int n_encoded_groups);
int chainback_viterbi29(void *vit, unsigned char *decoded, unsigned int n_decoded_bits, unsigned int _mystery);
void delete_viterbi29(void *vit);
void *create_viterbi39(int num_decoded_bits);
int init_viterbi39(void *vit, int _mystery);
int update_viterbi39_blk(void *vit, unsigned char *encoded_soft, int n_encoded_groups);
int chainback_viterbi39(void *vit, unsigned char *decoded, unsigned int n_decoded_bits, unsigned int _mystery);
void delete_viterbi39(void *vit);
void *create_viterbi615(int num_decoded_bits);
int init_viterbi615(void *vit, int _mystery);
int update_viterbi615_blk(void *vit, unsigned char *encoded_soft, int n_encoded_groups);
int chainback_viterbi615(void *vit, unsigned char *decoded, unsigned int n_decoded_bits, unsigned int _mystery);
void delete_viterbi615(void *vit);
// Misc other
static inline int parity(unsigned int x) {
/* http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel */
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x &= 0xf;
return (0x6996 >> x) & 1;
}
#endif