#include <ao_fec.h>
#include <stdio.h>
+/*
+ * byte order repeats through 3 2 1 0
+ *
+ * bit-pair order repeats through
+ *
+ * 1/0 3/2 5/4 7/6
+ *
+ * So, the over all order is:
+ *
+ * 3,1/0 2,1/0 1,1/0 0,1/0
+ * 3,3/2 2,3/2 1,3/2 0,3/2
+ * 3,5/4 2,5/4 1,5/4 0,5/4
+ * 3,7/6 2,7/6 1,7/6 0,7/6
+ *
+ * The raw bit order is thus
+ *
+ * 1e/1f 16/17 0e/0f 06/07
+ * 1c/1d 14/15 0c/0d 04/05
+ * 1a/1b 12/13 0a/0b 02/03
+ * 18/19 10/11 08/09 00/01
+ */
+
+static inline uint16_t ao_interleave_index(uint16_t i) {
+ uint8_t l = i & 0x1e;
+ uint16_t h = i & ~0x1e;
+ uint8_t o = 0x1e ^ (((l >> 2) & 0x6) | ((l << 2) & 0x18));
+ return h | o;
+}
+
struct ao_soft_sym {
uint8_t a, b;
};
#define NUM_HIST 8
#define MOD_HIST(b) ((b) & 7)
+#define V_0 0xc0
+#define V_1 0x40
+
static const struct ao_soft_sym ao_fec_decode_table[NUM_STATE][2] = {
/* next 0 1 state */
- { { 0x00, 0x00 }, { 0xff, 0xff } } , /* 000 */
- { { 0x00, 0xff }, { 0xff, 0x00 } }, /* 001 */
- { { 0xff, 0xff }, { 0x00, 0x00 } }, /* 010 */
- { { 0xff, 0x00 }, { 0x00, 0xff } }, /* 011 */
- { { 0xff, 0xff }, { 0x00, 0x00 } }, /* 100 */
- { { 0xff, 0x00 }, { 0x00, 0xff } }, /* 101 */
- { { 0x00, 0x00 }, { 0xff, 0xff } }, /* 110 */
- { { 0x00, 0xff }, { 0xff, 0x00 } } /* 111 */
+ { { V_0, V_0 }, { V_1, V_1 } } , /* 000 */
+ { { V_0, V_1 }, { V_1, V_0 } }, /* 001 */
+ { { V_1, V_1 }, { V_0, V_0 } }, /* 010 */
+ { { V_1, V_0 }, { V_0, V_1 } }, /* 011 */
+ { { V_1, V_1 }, { V_0, V_0 } }, /* 100 */
+ { { V_1, V_0 }, { V_0, V_1 } }, /* 101 */
+ { { V_0, V_0 }, { V_1, V_1 } }, /* 110 */
+ { { V_0, V_1 }, { V_1, V_0 } } /* 111 */
};
static inline uint8_t
*/
uint8_t
-ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out)
+ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len)
{
static uint16_t cost[2][NUM_STATE]; /* path cost */
static uint16_t bits[2][NUM_STATE]; /* save bits to quickly output them */
uint8_t n; /* next cost/bits index */
uint8_t state; /* state index */
uint8_t bit; /* original encoded bit index */
+ const uint8_t *whiten = ao_fec_whiten_table;
+ uint16_t interleave; /* input byte array index */
+ struct ao_soft_sym s; /* input symbol pair */
p = 0;
for (state = 0; state < NUM_STATE; state++) {
for (i = 0; i < len; i += 2) {
b = i/2;
n = p ^ 1;
- struct ao_soft_sym s = { .a = in[i], .b = in[i+1] };
+
+ /* Fetch one pair of input bytes, de-interleaving
+ * the input.
+ */
+ interleave = ao_interleave_index(i);
+ s.a = in[interleave];
+ s.b = in[interleave+1];
/* Reset next costs to 'impossibly high' values so that
* the first path through this state is cheaper than this
p = n;
/* A loop is needed to handle the last output byte. It
- * won't have a full NUM_HIST bits of future data to
- * perform full error correction, but we might as well
- * give the best possible answer anyways.
+ * won't have any bits of future data to perform full
+ * error correction, but we might as well give the
+ * best possible answer anyways.
*/
while ((b - o) >= (8 + NUM_HIST) || (i + 2 >= len && b > o)) {
}
#if 0
- printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x\n",
- i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff);
+ printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x whiten %0x\n",
+ i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten);
#endif
- out[o >> 3] = bits[p][min_state] >> dist;
+ if (out_len) {
+ *out++ = (bits[p][min_state] >> dist) ^ *whiten++;
+ --out_len;
+ }
o += 8;
}
}