core/conv: Add support for other termination types (trunc & tail biting)

Note that this breaks the ABI and the low level API. But it shouldn't
break the high level API, nor the conv code definitions (because fields
default to 0, and for new fields '0' is the previous behavior)

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
Sylvain Munaut 2011-11-24 17:46:58 +01:00
parent d4440d4cfa
commit 297d13f460
2 changed files with 119 additions and 38 deletions

View File

@ -35,6 +35,19 @@
#include <osmocom/core/bits.h>
/*! \brief possibe termination types
*
* The termination type will determine which state the encoder/decoder
* can start/end with. This is mostly taken care of in the high level API
* call. So if you use the low level API, you must take care of making the
* proper calls yourself.
*/
enum osmo_conv_term {
CONV_TERM_FLUSH = 0, /*!< \brief Flush encoder state */
CONV_TERM_TRUNCATION, /*!< \brief Direct truncation */
CONV_TERM_TAIL_BITING, /*!< \brief Tail biting */
};
/*! \brief structure describing a given convolutional code
*
* The only required fields are N,K and the next_output/next_state arrays. The
@ -46,6 +59,8 @@ struct osmo_conv_code {
int K; /*!< \brief Constraint length */
int len; /*!< \brief # of data bits */
enum osmo_conv_term term; /*!< \brief Termination type */
const uint8_t (*next_output)[2];/*!< \brief Next output array */
const uint8_t (*next_state)[2]; /*!< \brief Next state array */
@ -70,9 +85,11 @@ struct osmo_conv_encoder {
void osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
const struct osmo_conv_code *code);
void osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
const ubit_t *input);
int osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
const ubit_t *input, ubit_t *output, int n);
int osmo_conv_encode_finish(struct osmo_conv_encoder *encoder, ubit_t *output);
int osmo_conv_encode_flush(struct osmo_conv_encoder *encoder, ubit_t *output);
/* All-in-one */
int osmo_conv_encode(const struct osmo_conv_code *code,
@ -100,16 +117,18 @@ struct osmo_conv_decoder {
};
void osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
const struct osmo_conv_code *code, int len);
void osmo_conv_decode_reset(struct osmo_conv_decoder *decoder);
const struct osmo_conv_code *code,
int len, int start_state);
void osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state);
void osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder);
void osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder);
int osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
const sbit_t *input, int n);
int osmo_conv_decode_finish(struct osmo_conv_decoder *decoder,
const sbit_t *input);
int osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
const sbit_t *input);
int osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
ubit_t *output, int has_finish);
ubit_t *output, int has_flush, int end_state);
/* All-in-one */
int osmo_conv_decode(const struct osmo_conv_code *code,

View File

@ -57,6 +57,19 @@ osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
encoder->code = code;
}
void
osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
const ubit_t *input)
{
int i;
uint8_t state = 0;
for (i=0; i<(encoder->code->K-1); i++)
state = (state << 1) | input[i];
encoder->state = state;
}
static inline int
_conv_encode_do_output(struct osmo_conv_encoder *encoder,
uint8_t out, ubit_t *output)
@ -117,8 +130,8 @@ osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
}
int
osmo_conv_encode_finish(struct osmo_conv_encoder *encoder,
ubit_t *output)
osmo_conv_encode_flush(struct osmo_conv_encoder *encoder,
ubit_t *output)
{
const struct osmo_conv_code *code = encoder->code;
uint8_t state;
@ -159,8 +172,8 @@ osmo_conv_encode_finish(struct osmo_conv_encoder *encoder,
* \return Number of produced output bits
*
* This is an all-in-one function, taking care of
* \ref osmo_conv_init, \ref osmo_conv_encode_raw and
* \ref osmo_conv_encode_finish.
* \ref osmo_conv_init, \ref osmo_conv_encode_load_state,
* \ref osmo_conv_encode_raw and \ref osmo_conv_encode_flush as needed.
*/
int
osmo_conv_encode(const struct osmo_conv_code *code,
@ -170,8 +183,16 @@ osmo_conv_encode(const struct osmo_conv_code *code,
int l;
osmo_conv_encode_init(&encoder, code);
l = osmo_conv_encode_raw(&encoder, input, output, code->len);
l += osmo_conv_encode_finish(&encoder, &output[l]);
if (code->term == CONV_TERM_TAIL_BITING) {
int eidx = code->len - code->K + 1;
osmo_conv_encode_load_state(&encoder, &input[eidx]);
}
l = osmo_conv_encode_raw(&encoder, input, output, code->len);
if (code->term == CONV_TERM_FLUSH)
l += osmo_conv_encode_flush(&encoder, &output[l]);
return l;
}
@ -185,7 +206,7 @@ osmo_conv_encode(const struct osmo_conv_code *code,
void
osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
const struct osmo_conv_code *code, int len)
const struct osmo_conv_code *code, int len, int start_state)
{
int n_states;
@ -208,11 +229,11 @@ osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
/* Classic reset */
osmo_conv_decode_reset(decoder);
osmo_conv_decode_reset(decoder, start_state);
}
void
osmo_conv_decode_reset(struct osmo_conv_decoder *decoder)
osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
{
int i;
@ -220,13 +241,38 @@ osmo_conv_decode_reset(struct osmo_conv_decoder *decoder)
decoder->o_idx = 0;
decoder->p_idx = 0;
/* Initial error (only state 0 is valid) */
decoder->ae[0] = 0;
for (i=1; i<decoder->n_states; i++) {
decoder->ae[i] = MAX_AE;
/* Initial error */
if (start_state < 0) {
/* All states possible */
memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
} else {
/* Fixed start state */
for (i=0; i<decoder->n_states; i++) {
decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
}
}
}
void
osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
{
int i;
unsigned int min_ae = MAX_AE;
/* Reset indexes */
decoder->o_idx = 0;
decoder->p_idx = 0;
/* Initial error normalize (remove constant) */
for (i=0; i<decoder->n_states; i++) {
if (decoder->ae[i] < min_ae)
min_ae = decoder->ae[i];
}
for (i=0; i<decoder->n_states; i++)
decoder->ae[i] -= min_ae;
}
void
osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
{
@ -339,8 +385,8 @@ osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
}
int
osmo_conv_decode_finish(struct osmo_conv_decoder *decoder,
const sbit_t *input)
osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
const sbit_t *input)
{
const struct osmo_conv_code *code = decoder->code;
@ -445,7 +491,7 @@ osmo_conv_decode_finish(struct osmo_conv_decoder *decoder,
int
osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
ubit_t *output, int has_finish)
ubit_t *output, int has_flush, int end_state)
{
const struct osmo_conv_code *code = decoder->code;
@ -455,20 +501,26 @@ osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
uint8_t *sh_ptr;
/* Find state with least error */
min_ae = MAX_AE;
min_state = 0xff;
/* End state ? */
if (end_state < 0) {
/* Find state with least error */
min_ae = MAX_AE;
min_state = 0xff;
for (s=0; s<decoder->n_states; s++)
{
if (decoder->ae[s] < min_ae) {
min_ae = decoder->ae[s];
min_state = s;
for (s=0; s<decoder->n_states; s++)
{
if (decoder->ae[s] < min_ae) {
min_ae = decoder->ae[s];
min_state = s;
}
}
}
if (min_state == 0xff)
return -1;
if (min_state == 0xff)
return -1;
} else {
min_state = (uint8_t) end_state;
min_ae = decoder->ae[end_state];
}
/* Traceback */
cur_state = min_state;
@ -478,7 +530,7 @@ osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
/* No output for the K-1 termination input bits */
if (has_finish) {
if (has_flush) {
for (i=0; i<code->K-1; i++) {
cur_state = sh_ptr[cur_state];
sh_ptr -= decoder->n_states;
@ -510,7 +562,7 @@ osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
*
* This is an all-in-one function, taking care of
* \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
* \ref osmo_conv_decode_finish, \ref osmo_conv_decode_get_output and
* \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_output and
* \ref osmo_conv_decode_deinit.
*/
int
@ -520,12 +572,22 @@ osmo_conv_decode(const struct osmo_conv_code *code,
struct osmo_conv_decoder decoder;
int rv, l;
osmo_conv_decode_init(&decoder, code, 0);
osmo_conv_decode_init(&decoder, code, 0, 0);
if (code->term == CONV_TERM_TAIL_BITING) {
osmo_conv_decode_scan(&decoder, input, code->len);
osmo_conv_decode_rewind(&decoder);
}
l = osmo_conv_decode_scan(&decoder, input, code->len);
l = osmo_conv_decode_finish(&decoder, &input[l]);
rv = osmo_conv_decode_get_output(&decoder, output, 1);
if (code->term == CONV_TERM_FLUSH)
l = osmo_conv_decode_flush(&decoder, &input[l]);
rv = osmo_conv_decode_get_output(&decoder, output,
code->term == CONV_TERM_FLUSH, /* has_flush */
code->term == CONV_TERM_FLUSH ? 0 : -1 /* end_state */
);
osmo_conv_decode_deinit(&decoder);