kopia lustrzana https://github.com/AlexandreRouma/SDRPlusPlus
256 wiersze
8.0 KiB
C
256 wiersze
8.0 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "fec_shim.h"
|
|
|
|
typedef struct {
|
|
correct_reed_solomon *rs;
|
|
unsigned int msg_length;
|
|
unsigned int block_length;
|
|
unsigned int num_roots;
|
|
uint8_t *msg_out;
|
|
unsigned int pad;
|
|
uint8_t *erasures;
|
|
} reed_solomon_shim;
|
|
|
|
void *init_rs_char(int symbol_size, int primitive_polynomial,
|
|
int first_consecutive_root, int root_gap, int number_roots,
|
|
unsigned int pad) {
|
|
if (symbol_size != 8) {
|
|
return NULL;
|
|
}
|
|
|
|
reed_solomon_shim *shim = malloc(sizeof(reed_solomon_shim));
|
|
|
|
shim->pad = pad;
|
|
shim->block_length = 255 - pad;
|
|
shim->num_roots = number_roots;
|
|
shim->msg_length = shim->block_length - number_roots;
|
|
shim->rs = correct_reed_solomon_create(primitive_polynomial,
|
|
first_consecutive_root, root_gap, number_roots);
|
|
shim->msg_out = malloc(shim->block_length);
|
|
shim->erasures = malloc(number_roots);
|
|
|
|
return shim;
|
|
}
|
|
|
|
void free_rs_char(void *rs) {
|
|
reed_solomon_shim *shim = (reed_solomon_shim *)rs;
|
|
correct_reed_solomon_destroy(shim->rs);
|
|
free(shim->msg_out);
|
|
free(shim->erasures);
|
|
free(shim);
|
|
}
|
|
|
|
void encode_rs_char(void *rs, const unsigned char *msg, unsigned char *parity) {
|
|
reed_solomon_shim *shim = (reed_solomon_shim *)rs;
|
|
correct_reed_solomon_encode(shim->rs, msg, shim->msg_length, shim->msg_out);
|
|
memcpy(parity, shim->msg_out + shim->msg_length, shim->num_roots);
|
|
}
|
|
|
|
void decode_rs_char(void *rs, unsigned char *block, int *erasure_locations,
|
|
int num_erasures) {
|
|
reed_solomon_shim *shim = (reed_solomon_shim *)rs;
|
|
for (int i = 0; i < num_erasures; i++) {
|
|
shim->erasures[i] = (uint8_t)(erasure_locations[i]) - shim->pad;
|
|
}
|
|
correct_reed_solomon_decode_with_erasures(shim->rs, block, shim->block_length,
|
|
shim->erasures, num_erasures,
|
|
block);
|
|
}
|
|
|
|
typedef struct {
|
|
correct_convolutional *conv;
|
|
unsigned int rate;
|
|
unsigned int order;
|
|
uint8_t *buf;
|
|
size_t buf_len;
|
|
uint8_t *read_iter;
|
|
uint8_t *write_iter;
|
|
} convolutional_shim;
|
|
|
|
static correct_convolutional_polynomial_t r12k7[] = {V27POLYA, V27POLYB};
|
|
|
|
static correct_convolutional_polynomial_t r12k9[] = {V29POLYA, V29POLYB};
|
|
|
|
static correct_convolutional_polynomial_t r13k9[] = {V39POLYA, V39POLYB,
|
|
V39POLYC};
|
|
|
|
static correct_convolutional_polynomial_t r16k15[] = {
|
|
V615POLYA, V615POLYB, V615POLYC, V615POLYD, V615POLYE, V615POLYF};
|
|
|
|
/* Common methods */
|
|
static void *create_viterbi(unsigned int num_decoded_bits, unsigned int rate,
|
|
unsigned int order,
|
|
correct_convolutional_polynomial_t *poly) {
|
|
convolutional_shim *shim = malloc(sizeof(convolutional_shim));
|
|
|
|
size_t num_decoded_bytes = (num_decoded_bits % 8)
|
|
? (num_decoded_bits / 8 + 1)
|
|
: num_decoded_bits / 8;
|
|
|
|
shim->rate = rate;
|
|
shim->order = order;
|
|
shim->buf = malloc(num_decoded_bytes);
|
|
shim->buf_len = num_decoded_bytes;
|
|
shim->conv = correct_convolutional_create(rate, order, poly);
|
|
shim->read_iter = shim->buf;
|
|
shim->write_iter = shim->buf;
|
|
|
|
return shim;
|
|
}
|
|
|
|
static void delete_viterbi(void *vit) {
|
|
convolutional_shim *shim = (convolutional_shim *)vit;
|
|
free(shim->buf);
|
|
correct_convolutional_destroy(shim->conv);
|
|
free(shim);
|
|
}
|
|
|
|
static void init_viterbi(void *vit) {
|
|
convolutional_shim *shim = (convolutional_shim *)vit;
|
|
shim->read_iter = shim->buf;
|
|
shim->write_iter = shim->buf;
|
|
}
|
|
|
|
static void update_viterbi_blk(void *vit, const unsigned char *encoded_soft,
|
|
unsigned int num_encoded_groups) {
|
|
convolutional_shim *shim = (convolutional_shim *)vit;
|
|
|
|
// don't overwrite our buffer
|
|
size_t rem = (shim->buf + shim->buf_len) - shim->write_iter;
|
|
size_t rem_bits = 8 * rem;
|
|
// this math isn't very clear
|
|
// here we sort of do the opposite of what liquid-dsp does
|
|
size_t n_write_bits = num_encoded_groups - (shim->order - 1);
|
|
if (n_write_bits > rem_bits) {
|
|
size_t reduction = n_write_bits - rem_bits;
|
|
num_encoded_groups -= reduction;
|
|
n_write_bits -= reduction;
|
|
}
|
|
|
|
// what if n_write_bits isn't a multiple of 8?
|
|
// libcorrect can't start and stop at arbitrary indices...
|
|
correct_convolutional_decode_soft(
|
|
shim->conv, encoded_soft, num_encoded_groups * shim->rate, shim->write_iter);
|
|
shim->write_iter += n_write_bits / 8;
|
|
}
|
|
|
|
static void chainback_viterbi(void *vit, unsigned char *decoded,
|
|
unsigned int num_decoded_bits) {
|
|
convolutional_shim *shim = (convolutional_shim *)vit;
|
|
|
|
// num_decoded_bits not a multiple of 8?
|
|
// this is a similar problem to update_viterbi_blk
|
|
// although here we could actually resolve a non-multiple of 8
|
|
size_t rem = shim->write_iter - shim->read_iter;
|
|
size_t rem_bits = 8 * rem;
|
|
|
|
if (num_decoded_bits > rem_bits) {
|
|
num_decoded_bits = rem_bits;
|
|
}
|
|
|
|
size_t num_decoded_bytes = (num_decoded_bits % 8)
|
|
? (num_decoded_bits / 8 + 1)
|
|
: num_decoded_bits / 8;
|
|
memcpy(decoded, shim->read_iter, num_decoded_bytes);
|
|
|
|
shim->read_iter += num_decoded_bytes;
|
|
}
|
|
|
|
/* Rate 1/2, k = 7 */
|
|
void *create_viterbi27(int num_decoded_bits) {
|
|
return create_viterbi(num_decoded_bits, 2, 7, r12k7);
|
|
}
|
|
|
|
void delete_viterbi27(void *vit) { delete_viterbi(vit); }
|
|
|
|
int init_viterbi27(void *vit, int _) {
|
|
init_viterbi(vit);
|
|
return 0;
|
|
}
|
|
|
|
int update_viterbi27_blk(void *vit, unsigned char *encoded_soft,
|
|
int num_encoded_groups) {
|
|
update_viterbi_blk(vit, encoded_soft, num_encoded_groups);
|
|
return 0;
|
|
}
|
|
|
|
int chainback_viterbi27(void *vit, unsigned char *decoded,
|
|
unsigned int num_decoded_bits, unsigned int _) {
|
|
chainback_viterbi(vit, decoded, num_decoded_bits);
|
|
return 0;
|
|
}
|
|
|
|
/* Rate 1/2, k = 9 */
|
|
void *create_viterbi29(int num_decoded_bits) {
|
|
return create_viterbi(num_decoded_bits, 2, 9, r12k9);
|
|
}
|
|
|
|
void delete_viterbi29(void *vit) { delete_viterbi(vit); }
|
|
|
|
int init_viterbi29(void *vit, int _) {
|
|
init_viterbi(vit);
|
|
return 0;
|
|
}
|
|
|
|
int update_viterbi29_blk(void *vit, unsigned char *encoded_soft,
|
|
int num_encoded_groups) {
|
|
update_viterbi_blk(vit, encoded_soft, num_encoded_groups);
|
|
return 0;
|
|
}
|
|
|
|
int chainback_viterbi29(void *vit, unsigned char *decoded,
|
|
unsigned int num_decoded_bits, unsigned int _) {
|
|
chainback_viterbi(vit, decoded, num_decoded_bits);
|
|
return 0;
|
|
}
|
|
|
|
/* Rate 1/3, k = 9 */
|
|
void *create_viterbi39(int num_decoded_bits) {
|
|
return create_viterbi(num_decoded_bits, 3, 9, r13k9);
|
|
}
|
|
|
|
void delete_viterbi39(void *vit) { delete_viterbi(vit); }
|
|
|
|
int init_viterbi39(void *vit, int _) {
|
|
init_viterbi(vit);
|
|
return 0;
|
|
}
|
|
|
|
int update_viterbi39_blk(void *vit, unsigned char *encoded_soft,
|
|
int num_encoded_groups) {
|
|
update_viterbi_blk(vit, encoded_soft, num_encoded_groups);
|
|
return 0;
|
|
}
|
|
|
|
int chainback_viterbi39(void *vit, unsigned char *decoded,
|
|
unsigned int num_decoded_bits, unsigned int _) {
|
|
chainback_viterbi(vit, decoded, num_decoded_bits);
|
|
return 0;
|
|
}
|
|
|
|
/* Rate 1/6, k = 15 */
|
|
void *create_viterbi615(int num_decoded_bits) {
|
|
return create_viterbi(num_decoded_bits, 6, 15, r16k15);
|
|
}
|
|
|
|
void delete_viterbi615(void *vit) { delete_viterbi(vit); }
|
|
|
|
int init_viterbi615(void *vit, int _) {
|
|
init_viterbi(vit);
|
|
return 0;
|
|
}
|
|
|
|
int update_viterbi615_blk(void *vit, unsigned char *encoded_soft,
|
|
int num_encoded_groups) {
|
|
update_viterbi_blk(vit, encoded_soft, num_encoded_groups);
|
|
return 0;
|
|
}
|
|
|
|
int chainback_viterbi615(void *vit, unsigned char *decoded,
|
|
unsigned int num_decoded_bits, unsigned int _) {
|
|
chainback_viterbi(vit, decoded, num_decoded_bits);
|
|
return 0;
|
|
}
|