blob: 8963018baf412bfe2def81b5e6e38df8484e6b03 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file conv.c
2 * Generic convolutional encoding / decoding. */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +02003/*
Sylvain Munaut19dc5c92011-04-23 16:09:19 +02004 * Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
5 *
6 * All Rights Reserved
7 *
Harald Weltee08da972017-11-13 01:00:26 +09008 * SPDX-License-Identifier: GPL-2.0+
9 *
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020010 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020019 */
20
Harald Welteba6988b2011-08-17 12:46:48 +020021/*! \addtogroup conv
22 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020023 * Osmocom convolutional encoder and decoder.
24 *
25 * \file conv.c */
Harald Welteba6988b2011-08-17 12:46:48 +020026
Holger Hans Peter Freyther47723482011-11-09 11:26:15 +010027#include "config.h"
28#ifdef HAVE_ALLOCA_H
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020029#include <alloca.h>
Holger Hans Peter Freyther47723482011-11-09 11:26:15 +010030#endif
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020031#include <stdint.h>
32#include <stdlib.h>
33#include <string.h>
34
Vadim Yanitskiya8809f02020-02-09 04:12:53 +070035#include <osmocom/core/utils.h>
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020036#include <osmocom/core/bits.h>
37#include <osmocom/core/conv.h>
38
39
40/* ------------------------------------------------------------------------ */
Sylvain Munautae8dbb42011-11-24 17:47:32 +010041/* Common */
42/* ------------------------------------------------------------------------ */
43
44int
45osmo_conv_get_input_length(const struct osmo_conv_code *code, int len)
46{
47 return len <= 0 ? code->len : len;
48}
49
50int
51osmo_conv_get_output_length(const struct osmo_conv_code *code, int len)
52{
53 int pbits, in_len, out_len;
54
55 /* Input length */
56 in_len = osmo_conv_get_input_length(code, len);
57
58 /* Output length */
59 out_len = in_len * code->N;
60
61 if (code->term == CONV_TERM_FLUSH)
62 out_len += code->N * (code->K - 1);
63
64 /* Count punctured bits */
65 if (code->puncture) {
Harald Welte2f548892022-01-05 21:20:40 +010066 for (pbits = 0; code->puncture[pbits] >= 0; pbits++) {}
Sylvain Munautae8dbb42011-11-24 17:47:32 +010067 out_len -= pbits;
68 }
69
70 return out_len;
71}
72
73
74/* ------------------------------------------------------------------------ */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020075/* Encoding */
76/* ------------------------------------------------------------------------ */
77
Neels Hofmeyr87e45502017-06-20 00:17:59 +020078/*! Initialize a convolutional encoder
Harald Welteba6988b2011-08-17 12:46:48 +020079 * \param[in,out] encoder Encoder state to initialize
80 * \param[in] code Description of convolutional code
81 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020082void
83osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
Harald Welte2f548892022-01-05 21:20:40 +010084 const struct osmo_conv_code *code)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020085{
86 memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
Vadim Yanitskiya8809f02020-02-09 04:12:53 +070087 OSMO_ASSERT(code != NULL);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020088 encoder->code = code;
89}
90
Sylvain Munaut297d13f2011-11-24 17:46:58 +010091void
92osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
Harald Welte2f548892022-01-05 21:20:40 +010093 const ubit_t *input)
Sylvain Munaut297d13f2011-11-24 17:46:58 +010094{
95 int i;
96 uint8_t state = 0;
97
Harald Welte2f548892022-01-05 21:20:40 +010098 for (i = 0; i < (encoder->code->K - 1); i++)
Sylvain Munaut297d13f2011-11-24 17:46:58 +010099 state = (state << 1) | input[i];
100
101 encoder->state = state;
102}
103
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200104static inline int
105_conv_encode_do_output(struct osmo_conv_encoder *encoder,
Harald Welte2f548892022-01-05 21:20:40 +0100106 uint8_t out, ubit_t *output)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200107{
108 const struct osmo_conv_code *code = encoder->code;
109 int o_idx = 0;
110 int j;
111
112 if (code->puncture) {
Harald Welte2f548892022-01-05 21:20:40 +0100113 for (j = 0; j < code->N; j++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200114 int bit_no = code->N - j - 1;
115 int r_idx = encoder->i_idx * code->N + j;
116
117 if (code->puncture[encoder->p_idx] == r_idx)
118 encoder->p_idx++;
119 else
120 output[o_idx++] = (out >> bit_no) & 1;
121 }
122 } else {
Harald Welte2f548892022-01-05 21:20:40 +0100123 for (j = 0; j < code->N; j++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200124 int bit_no = code->N - j - 1;
125 output[o_idx++] = (out >> bit_no) & 1;
126 }
127 }
128
129 return o_idx;
130}
131
132int
133osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
Harald Welte2f548892022-01-05 21:20:40 +0100134 const ubit_t *input, ubit_t *output, int n)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200135{
136 const struct osmo_conv_code *code = encoder->code;
137 uint8_t state;
138 int i;
139 int o_idx;
140
141 o_idx = 0;
142 state = encoder->state;
143
Harald Welte2f548892022-01-05 21:20:40 +0100144 for (i = 0; i < n; i++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200145 int bit = input[i];
146 uint8_t out;
147
Harald Welte2f548892022-01-05 21:20:40 +0100148 out = code->next_output[state][bit];
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200149 state = code->next_state[state][bit];
150
151 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
152
153 encoder->i_idx++;
154 }
155
156 encoder->state = state;
157
158 return o_idx;
159}
160
161int
Harald Welte2f548892022-01-05 21:20:40 +0100162osmo_conv_encode_flush(struct osmo_conv_encoder *encoder, ubit_t *output)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200163{
164 const struct osmo_conv_code *code = encoder->code;
165 uint8_t state;
166 int n;
167 int i;
168 int o_idx;
169
170 n = code->K - 1;
171
172 o_idx = 0;
173 state = encoder->state;
174
Harald Welte2f548892022-01-05 21:20:40 +0100175 for (i = 0; i < n; i++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200176 uint8_t out;
177
178 if (code->next_term_output) {
Harald Welte2f548892022-01-05 21:20:40 +0100179 out = code->next_term_output[state];
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200180 state = code->next_term_state[state];
181 } else {
Harald Welte2f548892022-01-05 21:20:40 +0100182 out = code->next_output[state][0];
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200183 state = code->next_state[state][0];
184 }
185
186 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
187
188 encoder->i_idx++;
189 }
190
191 encoder->state = state;
192
193 return o_idx;
194}
195
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200196/*! All-in-one convolutional encoding function
Harald Welteba6988b2011-08-17 12:46:48 +0200197 * \param[in] code description of convolutional code to be used
198 * \param[in] input array of unpacked bits (uncoded)
199 * \param[out] output array of unpacked bits (encoded)
Sylvain Munaut03d2c892011-11-24 11:53:49 +0100200 * \return Number of produced output bits
Harald Welteba6988b2011-08-17 12:46:48 +0200201 *
202 * This is an all-in-one function, taking care of
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100203 * \ref osmo_conv_init, \ref osmo_conv_encode_load_state,
204 * \ref osmo_conv_encode_raw and \ref osmo_conv_encode_flush as needed.
Harald Welteba6988b2011-08-17 12:46:48 +0200205 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200206int
207osmo_conv_encode(const struct osmo_conv_code *code,
Harald Welte2f548892022-01-05 21:20:40 +0100208 const ubit_t *input, ubit_t *output)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200209{
210 struct osmo_conv_encoder encoder;
211 int l;
212
213 osmo_conv_encode_init(&encoder, code);
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100214
215 if (code->term == CONV_TERM_TAIL_BITING) {
216 int eidx = code->len - code->K + 1;
217 osmo_conv_encode_load_state(&encoder, &input[eidx]);
218 }
219
220 l = osmo_conv_encode_raw(&encoder, input, output, code->len);
221
222 if (code->term == CONV_TERM_FLUSH)
223 l += osmo_conv_encode_flush(&encoder, &output[l]);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200224
225 return l;
226}
227
228
229/* ------------------------------------------------------------------------ */
230/* Decoding (viterbi) */
231/* ------------------------------------------------------------------------ */
232
233#define MAX_AE 0x00ffffff
234
Tom Tsou35536802016-11-24 19:24:32 +0700235/* Forward declaration for accerlated decoding with certain codes */
236int
237osmo_conv_decode_acc(const struct osmo_conv_code *code,
Harald Welte2f548892022-01-05 21:20:40 +0100238 const sbit_t *input, ubit_t *output);
Tom Tsou35536802016-11-24 19:24:32 +0700239
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200240void
241osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
Harald Welte2f548892022-01-05 21:20:40 +0100242 const struct osmo_conv_code *code, int len,
243 int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200244{
245 int n_states;
246
247 /* Init */
248 if (len <= 0)
Harald Welte2f548892022-01-05 21:20:40 +0100249 len = code->len;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200250
251 n_states = 1 << (code->K - 1);
252
253 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
254
255 decoder->code = code;
256 decoder->n_states = n_states;
257 decoder->len = len;
258
259 /* Allocate arrays */
Harald Welte2f548892022-01-05 21:20:40 +0100260 decoder->ae = malloc(sizeof(unsigned int) * n_states);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200261 decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
262
263 decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
264
265 /* Classic reset */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100266 osmo_conv_decode_reset(decoder, start_state);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200267}
268
269void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100270osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200271{
272 int i;
273
274 /* Reset indexes */
275 decoder->o_idx = 0;
276 decoder->p_idx = 0;
277
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100278 /* Initial error */
279 if (start_state < 0) {
280 /* All states possible */
281 memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
282 } else {
283 /* Fixed start state */
Harald Welte2f548892022-01-05 21:20:40 +0100284 for (i = 0; i < decoder->n_states; i++) {
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100285 decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
286 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200287 }
288}
289
290void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100291osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
292{
293 int i;
294 unsigned int min_ae = MAX_AE;
295
296 /* Reset indexes */
297 decoder->o_idx = 0;
298 decoder->p_idx = 0;
299
300 /* Initial error normalize (remove constant) */
Harald Welte2f548892022-01-05 21:20:40 +0100301 for (i = 0; i < decoder->n_states; i++) {
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100302 if (decoder->ae[i] < min_ae)
303 min_ae = decoder->ae[i];
304 }
305
Harald Welte2f548892022-01-05 21:20:40 +0100306 for (i = 0; i < decoder->n_states; i++)
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100307 decoder->ae[i] -= min_ae;
308}
309
310void
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200311osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
312{
313 free(decoder->ae);
314 free(decoder->ae_next);
315 free(decoder->state_history);
316
317 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
318}
319
320int
321osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
Harald Welte2f548892022-01-05 21:20:40 +0100322 const sbit_t *input, int n)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200323{
324 const struct osmo_conv_code *code = decoder->code;
325
326 int i, s, b, j;
327
328 int n_states;
329 unsigned int *ae;
330 unsigned int *ae_next;
331 uint8_t *state_history;
332 sbit_t *in_sym;
333
334 int i_idx, p_idx;
335
336 /* Prepare */
337 n_states = decoder->n_states;
338
Harald Welte2f548892022-01-05 21:20:40 +0100339 ae = decoder->ae;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200340 ae_next = decoder->ae_next;
341 state_history = &decoder->state_history[n_states * decoder->o_idx];
342
Harald Welte2f548892022-01-05 21:20:40 +0100343 in_sym = alloca(sizeof(sbit_t) * code->N);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200344
345 i_idx = 0;
346 p_idx = decoder->p_idx;
347
348 /* Scan the treillis */
Harald Welte2f548892022-01-05 21:20:40 +0100349 for (i = 0; i < n; i++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200350 /* Reset next accumulated error */
Harald Welte2f548892022-01-05 21:20:40 +0100351 for (s = 0; s < n_states; s++)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200352 ae_next[s] = MAX_AE;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200353
354 /* Get input */
355 if (code->puncture) {
356 /* Hard way ... */
Harald Welte2f548892022-01-05 21:20:40 +0100357 for (j = 0; j < code->N; j++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200358 int idx = ((decoder->o_idx + i) * code->N) + j;
359 if (idx == code->puncture[p_idx]) {
360 in_sym[j] = 0; /* Undefined */
361 p_idx++;
362 } else {
363 in_sym[j] = input[i_idx];
364 i_idx++;
365 }
366 }
367 } else {
368 /* Easy, just copy N bits */
369 memcpy(in_sym, &input[i_idx], code->N);
370 i_idx += code->N;
371 }
372
373 /* Scan all state */
Harald Welte2f548892022-01-05 21:20:40 +0100374 for (s = 0; s < n_states; s++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200375 /* Scan possible input bits */
Harald Welte2f548892022-01-05 21:20:40 +0100376 for (b = 0; b < 2; b++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200377 int nae, ov, e;
378 uint8_t m;
379
380 /* Next output and state */
Harald Welte2f548892022-01-05 21:20:40 +0100381 uint8_t out = code->next_output[s][b];
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200382 uint8_t state = code->next_state[s][b];
383
384 /* New error for this path */
385 nae = ae[s]; /* start from last error */
386 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
387
Harald Welte2f548892022-01-05 21:20:40 +0100388 for (j = 0; j < code->N; j++) {
Sylvain Munautd4440d42011-11-24 16:04:58 +0100389 int is = (int)in_sym[j];
390 if (is) {
391 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
392 e = is - ov; /* raw error for this bit */
393 nae += (e * e) >> 9; /* acc the squared/scaled value */
394 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200395 m >>= 1; /* next mask bit */
396 }
397
398 /* Is it survivor ? */
399 if (ae_next[state] > nae) {
400 ae_next[state] = nae;
401 state_history[(n_states * i) + state] = s;
402 }
403 }
404 }
405
406 /* Copy accumulated error */
407 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
408 }
409
410 /* Update decoder state */
411 decoder->p_idx = p_idx;
412 decoder->o_idx += n;
413
414 return i_idx;
415}
416
417int
Harald Welte2f548892022-01-05 21:20:40 +0100418osmo_conv_decode_flush(struct osmo_conv_decoder *decoder, const sbit_t *input)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200419{
420 const struct osmo_conv_code *code = decoder->code;
421
422 int i, s, j;
423
424 int n_states;
425 unsigned int *ae;
426 unsigned int *ae_next;
427 uint8_t *state_history;
428 sbit_t *in_sym;
429
430 int i_idx, p_idx;
431
432 /* Prepare */
433 n_states = decoder->n_states;
434
Harald Welte2f548892022-01-05 21:20:40 +0100435 ae = decoder->ae;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200436 ae_next = decoder->ae_next;
437 state_history = &decoder->state_history[n_states * decoder->o_idx];
438
Harald Welte2f548892022-01-05 21:20:40 +0100439 in_sym = alloca(sizeof(sbit_t) * code->N);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200440
441 i_idx = 0;
442 p_idx = decoder->p_idx;
443
444 /* Scan the treillis */
Harald Welte2f548892022-01-05 21:20:40 +0100445 for (i = 0; i < code->K - 1; i++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200446 /* Reset next accumulated error */
Harald Welte2f548892022-01-05 21:20:40 +0100447 for (s = 0; s < n_states; s++)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200448 ae_next[s] = MAX_AE;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200449
450 /* Get input */
451 if (code->puncture) {
452 /* Hard way ... */
Harald Welte2f548892022-01-05 21:20:40 +0100453 for (j = 0; j < code->N; j++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200454 int idx = ((decoder->o_idx + i) * code->N) + j;
455 if (idx == code->puncture[p_idx]) {
456 in_sym[j] = 0; /* Undefined */
457 p_idx++;
458 } else {
459 in_sym[j] = input[i_idx];
460 i_idx++;
461 }
462 }
463 } else {
464 /* Easy, just copy N bits */
465 memcpy(in_sym, &input[i_idx], code->N);
466 i_idx += code->N;
467 }
468
469 /* Scan all state */
Harald Welte2f548892022-01-05 21:20:40 +0100470 for (s = 0; s < n_states; s++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200471 int nae, ov, e;
472 uint8_t m;
473
474 /* Next output and state */
475 uint8_t out;
476 uint8_t state;
477
478 if (code->next_term_output) {
Harald Welte2f548892022-01-05 21:20:40 +0100479 out = code->next_term_output[s];
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200480 state = code->next_term_state[s];
481 } else {
Harald Welte2f548892022-01-05 21:20:40 +0100482 out = code->next_output[s][0];
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200483 state = code->next_state[s][0];
484 }
485
486 /* New error for this path */
487 nae = ae[s]; /* start from last error */
488 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
489
Harald Welte2f548892022-01-05 21:20:40 +0100490 for (j = 0; j < code->N; j++) {
Sylvain Munaut1dd7c842011-04-28 22:30:30 +0200491 int is = (int)in_sym[j];
492 if (is) {
493 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
494 e = is - ov; /* raw error for this bit */
495 nae += (e * e) >> 9; /* acc the squared/scaled value */
496 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200497 m >>= 1; /* next mask bit */
498 }
499
500 /* Is it survivor ? */
501 if (ae_next[state] > nae) {
502 ae_next[state] = nae;
503 state_history[(n_states * i) + state] = s;
504 }
505 }
506
507 /* Copy accumulated error */
508 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
509 }
510
511 /* Update decoder state */
512 decoder->p_idx = p_idx;
513 decoder->o_idx += code->K - 1;
514
515 return i_idx;
516}
517
518int
Sylvain Munautd5974e92021-12-21 19:45:34 +0100519osmo_conv_decode_get_best_end_state(struct osmo_conv_decoder *decoder)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200520{
521 const struct osmo_conv_code *code = decoder->code;
522
Sylvain Munautd5974e92021-12-21 19:45:34 +0100523 int min_ae, min_state;
524 int s;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200525
Sylvain Munautd5974e92021-12-21 19:45:34 +0100526 /* If flushed, we _know_ the end state */
527 if (code->term == CONV_TERM_FLUSH)
528 return 0;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200529
Sylvain Munautd5974e92021-12-21 19:45:34 +0100530 /* Search init */
531 min_state = -1;
532 min_ae = MAX_AE;
533
534 /* If tail biting, we search for the minimum path metric that
535 * gives a circular traceback (i.e. start_state == end_state */
536 if (code->term == CONV_TERM_TAIL_BITING) {
537 int t, n, i;
538 uint8_t *sh_ptr;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200539
Harald Welte2f548892022-01-05 21:20:40 +0100540 for (s = 0; s < decoder->n_states; s++) {
Sylvain Munautd5974e92021-12-21 19:45:34 +0100541 /* Check if that state traces back to itself */
542 n = decoder->o_idx;
543 sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
544 t = s;
545
Harald Welte2f548892022-01-05 21:20:40 +0100546 for (i = n - 1; i >= 0; i--) {
Sylvain Munautd5974e92021-12-21 19:45:34 +0100547 t = sh_ptr[t];
548 sh_ptr -= decoder->n_states;
549 }
550
551 if (s != t)
552 continue;
553
554 /* If it does, consider it */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100555 if (decoder->ae[s] < min_ae) {
556 min_ae = decoder->ae[s];
557 min_state = s;
558 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200559 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200560
Sylvain Munautd5974e92021-12-21 19:45:34 +0100561 if (min_ae < MAX_AE)
562 return min_state;
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100563 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200564
Sylvain Munautd5974e92021-12-21 19:45:34 +0100565 /* Finally, just the lowest path metric */
566 for (s = 0; s < decoder->n_states; s++) {
567 /* Is it smaller ? */
568 if (decoder->ae[s] < min_ae) {
569 min_ae = decoder->ae[s];
570 min_state = s;
571 }
572 }
573
574 return min_state;
575}
576
577int
578osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
579 ubit_t *output, int has_flush, int end_state)
580{
581 const struct osmo_conv_code *code = decoder->code;
582
583 int min_ae;
584 uint8_t min_state, cur_state;
585 int i, n;
586
587 uint8_t *sh_ptr;
588
589 /* End state ? */
590 if (end_state < 0)
591 end_state = osmo_conv_decode_get_best_end_state(decoder);
592
593 if (end_state < 0)
594 return -1;
595
596 min_state = (uint8_t) end_state;
597 min_ae = decoder->ae[end_state];
598
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200599 /* Traceback */
600 cur_state = min_state;
601
602 n = decoder->o_idx;
603
604 sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
605
606 /* No output for the K-1 termination input bits */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100607 if (has_flush) {
Harald Welte2f548892022-01-05 21:20:40 +0100608 for (i = 0; i < code->K - 1; i++) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200609 cur_state = sh_ptr[cur_state];
610 sh_ptr -= decoder->n_states;
611 }
612 n -= code->K - 1;
613 }
614
Harald Welte2f548892022-01-05 21:20:40 +0100615 /* Generate output backward */
616 for (i = n - 1; i >= 0; i--) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200617 min_state = cur_state;
618 cur_state = sh_ptr[cur_state];
619
620 sh_ptr -= decoder->n_states;
621
622 if (code->next_state[cur_state][0] == min_state)
623 output[i] = 0;
624 else
625 output[i] = 1;
626 }
627
628 return min_ae;
629}
630
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200631/*! All-in-one convolutional decoding function
Harald Welteba6988b2011-08-17 12:46:48 +0200632 * \param[in] code description of convolutional code to be used
633 * \param[in] input array of soft bits (coded)
634 * \param[out] output array of unpacked bits (decoded)
635 *
636 * This is an all-in-one function, taking care of
637 * \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
Sylvain Munautd5974e92021-12-21 19:45:34 +0100638 * \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_best_end_state,
639 * \ref osmo_conv_decode_get_output and \ref osmo_conv_decode_deinit.
Harald Welteba6988b2011-08-17 12:46:48 +0200640 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200641int
642osmo_conv_decode(const struct osmo_conv_code *code,
Harald Welte2f548892022-01-05 21:20:40 +0100643 const sbit_t *input, ubit_t *output)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200644{
645 struct osmo_conv_decoder decoder;
646 int rv, l;
647
Tom Tsou35536802016-11-24 19:24:32 +0700648 /* Use accelerated implementation for supported codes */
649 if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))
650 return osmo_conv_decode_acc(code, input, output);
651
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100652 osmo_conv_decode_init(&decoder, code, 0, 0);
653
654 if (code->term == CONV_TERM_TAIL_BITING) {
655 osmo_conv_decode_scan(&decoder, input, code->len);
656 osmo_conv_decode_rewind(&decoder);
657 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200658
659 l = osmo_conv_decode_scan(&decoder, input, code->len);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200660
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100661 if (code->term == CONV_TERM_FLUSH)
Vadim Yanitskiy6e6978a2017-06-12 03:47:34 +0700662 osmo_conv_decode_flush(&decoder, &input[l]);
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100663
664 rv = osmo_conv_decode_get_output(&decoder, output,
665 code->term == CONV_TERM_FLUSH, /* has_flush */
Sylvain Munautd5974e92021-12-21 19:45:34 +0100666 -1 /* end_state */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100667 );
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200668
669 osmo_conv_decode_deinit(&decoder);
670
671 return rv;
672}
Harald Welteba6988b2011-08-17 12:46:48 +0200673
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200674/*! @} */