summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2008-12-01 10:28:04 +0530
committerHarald Welte <laforge@gnumonks.org>2008-12-01 10:28:04 +0530
commit10f2fcca8dd1be2719bccefa16fd9dac9a76c749 (patch)
tree0b521a2ccc7d0d81a89e08b05650dec2421777d2
parentfd405f799425b6832a0c9cc7a56b07f43288b8b1 (diff)
[gsmdecode] import {interleave,conv}.[ch] from gsm-tvoid
* change convolutional decode to cope with TCH * add tch.c file with reordering/decoding for TCH/F
-rw-r--r--gsmstack/cch.c321
-rw-r--r--gsmstack/conv.c206
-rw-r--r--gsmstack/conv.h24
-rw-r--r--gsmstack/interleave.c48
-rw-r--r--gsmstack/interleave.h19
-rw-r--r--gsmstack/tch.c145
6 files changed, 473 insertions, 290 deletions
diff --git a/gsmstack/cch.c b/gsmstack/cch.c
index 7a1fd66..d3a2619 100644
--- a/gsmstack/cch.c
+++ b/gsmstack/cch.c
@@ -1,4 +1,3 @@
-
/* This file was taken from gsm-tvoid */
#include "system.h"
@@ -12,6 +11,7 @@
#include "burst_types.h"
#include "cch.h"
+#include "conv.h"
#include "fire_crc.h"
/*
@@ -88,251 +88,6 @@ static int parity_check(unsigned char *d) {
return memcmp(buf + DATA_BLOCK_SIZE, parity_remainder, PARITY_SIZE);
}
-
-/*
- * Convolutional encoding and Viterbi decoding for the GSM SACCH channel.
- */
-
-/*
- * Convolutional encoding:
- *
- * G_0 = 1 + x^3 + x^4
- * G_1 = 1 + x + x^3 + x^4
- *
- * i.e.,
- *
- * c_{2k} = u_k + u_{k - 3} + u_{k - 4}
- * c_{2k + 1} = u_k + u_{k - 1} + u_{k - 3} + u_{k - 4}
- */
-#define K 5
-#define MAX_ERROR (2 * CONV_INPUT_SIZE + 1)
-
-
-/*
- * Given the current state and input bit, what are the output bits?
- *
- * encode[current_state][input_bit]
- */
-static const unsigned int encode[1 << (K - 1)][2] = {
- {0, 3}, {3, 0}, {3, 0}, {0, 3},
- {0, 3}, {3, 0}, {3, 0}, {0, 3},
- {1, 2}, {2, 1}, {2, 1}, {1, 2},
- {1, 2}, {2, 1}, {2, 1}, {1, 2}
-};
-
-
-/*
- * Given the current state and input bit, what is the next state?
- *
- * next_state[current_state][input_bit]
- */
-static const unsigned int next_state[1 << (K - 1)][2] = {
- {0, 8}, {0, 8}, {1, 9}, {1, 9},
- {2, 10}, {2, 10}, {3, 11}, {3, 11},
- {4, 12}, {4, 12}, {5, 13}, {5, 13},
- {6, 14}, {6, 14}, {7, 15}, {7, 15}
-};
-
-
-/*
- * Given the previous state and the current state, what input bit caused
- * the transition? If it is impossible to transition between the two
- * states, the value is 2.
- *
- * prev_next_state[previous_state][current_state]
- */
-static const unsigned int prev_next_state[1 << (K - 1)][1 << (K - 1)] = {
- { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
- { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
- { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
- { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
- { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
- { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
- { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
- { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
- { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
- { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
- { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
- { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
- { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
- { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
- { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1},
- { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1}
-};
-
-
-static inline unsigned int hamming_distance2(unsigned int w) {
-
- return (w & 1) + !!(w & 2);
-}
-
-
-/*
-static void conv_encode(unsigned char *data, unsigned char *output) {
-
- unsigned int i, state = 0, o;
-
- // encode data
- for(i = 0; i < CONV_INPUT_SIZE; i++) {
- o = encode[state][data[i]];
- state = next_state[state][data[i]];
- *output++ = !!(o & 2);
- *output++ = o & 1;
- }
-}
- */
-
-
-static int conv_decode(unsigned char *output, unsigned char *data) {
-
- int i, t;
- unsigned int rdata, state, nstate, b, o, distance, accumulated_error,
- min_state, min_error, cur_state;
-
- unsigned int ae[1 << (K - 1)];
- unsigned int nae[1 << (K - 1)]; // next accumulated error
- unsigned int state_history[1 << (K - 1)][CONV_INPUT_SIZE + 1];
-
- // initialize accumulated error, assume starting state is 0
- for(i = 0; i < (1 << (K - 1)); i++)
- ae[i] = nae[i] = MAX_ERROR;
- ae[0] = 0;
-
- // build trellis
- for(t = 0; t < CONV_INPUT_SIZE; t++) {
-
- // get received data symbol
- rdata = (data[2 * t] << 1) | data[2 * t + 1];
-
- // for each state
- for(state = 0; state < (1 << (K - 1)); state++) {
-
- // make sure this state is possible
- if(ae[state] >= MAX_ERROR)
- continue;
-
- // find all states we lead to
- for(b = 0; b < 2; b++) {
-
- // get next state given input bit b
- nstate = next_state[state][b];
-
- // find output for this transition
- o = encode[state][b];
-
- // calculate distance from received data
- distance = hamming_distance2(rdata ^ o);
-
- // choose surviving path
- accumulated_error = ae[state] + distance;
- if(accumulated_error < nae[nstate]) {
-
- // save error for surviving state
- nae[nstate] = accumulated_error;
-
- // update state history
- state_history[nstate][t + 1] = state;
- }
- }
- }
-
- // get accumulated error ready for next time slice
- for(i = 0; i < (1 << (K - 1)); i++) {
- ae[i] = nae[i];
- nae[i] = MAX_ERROR;
- }
- }
-
- // the final state is the state with the fewest errors
- min_state = (unsigned int)-1;
- min_error = MAX_ERROR;
- for(i = 0; i < (1 << (K - 1)); i++) {
- if(ae[i] < min_error) {
- min_state = i;
- min_error = ae[i];
- }
- }
-
- // trace the path
- cur_state = min_state;
- for(t = CONV_INPUT_SIZE; t >= 1; t--) {
- min_state = cur_state;
- cur_state = state_history[cur_state][t]; // get previous
- output[t - 1] = prev_next_state[cur_state][min_state];
- }
-
- // return the number of errors detected (hard-decision)
- return min_error;
-}
-
-
-/*
- * GSM SACCH interleaving and burst mapping
- *
- * Interleaving:
- *
- * Given 456 coded input bits, form 4 blocks of 114 bits:
- *
- * i(B, j) = c(n, k) k = 0, ..., 455
- * n = 0, ..., N, N + 1, ...
- * B = B_0 + 4n + (k mod 4)
- * j = 2(49k mod 57) + ((k mod 8) div 4)
- *
- * Mapping on Burst:
- *
- * e(B, j) = i(B, j)
- * e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56
- * e(B, 57) = h_l(B)
- * e(B, 58) = h_n(B)
- *
- * Where h_l(B) and h_n(B) are bits in burst B indicating flags.
- */
-
-/*
-static void interleave(unsigned char *data, unsigned char *iBLOCK) {
-
- int j, k, B;
-
- // for each bit in input data
- for(k = 0; k < CONV_SIZE; k++) {
- B = k % 4;
- j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
- iBLOCK[B * iBLOCK_SIZE + j] = data[k];
- }
-}
- */
-
-
-#if 0
-static void decode_interleave(unsigned char *data, unsigned char *iBLOCK) {
-
- int j, k, B;
-
- for(k = 0; k < CONV_SIZE; k++) {
- B = k % 4;
- j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
- data[k] = iBLOCK[B * iBLOCK_SIZE + j];
- }
-}
-
-#endif
-
-/*
-static void burstmap(unsigned char *iBLOCK, unsigned char *eBLOCK,
- unsigned char hl, unsigned char hn) {
-
- int j;
-
- for(j = 0; j < 57; j++) {
- eBLOCK[j] = iBLOCK[j];
- eBLOCK[j + 59] = iBLOCK[j + 57];
- }
- eBLOCK[57] = hl;
- eBLOCK[58] = hn;
-}
- */
-
-
static void decode_burstmap(unsigned char *iBLOCK, unsigned char *eBLOCK,
unsigned char *hl, unsigned char *hn) {
@@ -380,16 +135,42 @@ int get_ns_l3_len(unsigned char *data, unsigned int datalen) {
#endif
+/*
+ * decode_cch
+ *
+ * Decode a "common" control channel. Most control channels use
+ * the same burst, interleave, Viterbi and parity configuration.
+ * The documentation for the control channels defines SACCH first
+ * and then just keeps referring to that.
+ *
+ * The current (investigated) list is as follows:
+ *
+ * BCCH Norm
+ * BCCH Ext
+ * PCH
+ * AGCH
+ * CBCH (SDCCH/4)
+ * CBCH (SDCCH/8)
+ * SDCCH/4
+ * SACCH/C4
+ * SDCCH/8
+ * SACCH/C8
+ *
+ * We provide two functions, one for where all four bursts are
+ * contiguous, and one where they aren't.
+ */
-static unsigned char *decode_sacch(GS_CTX *ctx, unsigned char *burst, unsigned int *datalen) {
+static unsigned char *decode_cch(GS_CTX *ctx, unsigned char *burst,
+ unsigned int *datalen)
+{
int errors, len, data_size;
unsigned char conv_data[CONV_SIZE], iBLOCK[BLOCKS][iBLOCK_SIZE],
- hl, hn, decoded_data[PARITY_OUTPUT_SIZE];
+ hl, hn, decoded_data[PARITY_OUTPUT_SIZE];
FC_CTX fc_ctx;
data_size = sizeof ctx->msg;
- if(datalen)
+ if (datalen)
*datalen = 0;
// unmap the bursts
@@ -400,10 +181,9 @@ static unsigned char *decode_sacch(GS_CTX *ctx, unsigned char *burst, unsigned i
// remove interleave
interleave_decode(&ctx->interleave_ctx, conv_data, (unsigned char *)iBLOCK);
- //decode_interleave(conv_data, (unsigned char *)iBLOCK);
// Viterbi decode
- errors = conv_decode(decoded_data, conv_data);
+ errors = conv_decode(decoded_data, conv_data, CONV_INPUT_SIZE_CCH);
if (errors) {
DEBUGF("conv_decode: %d\n", errors);
return NULL;
@@ -442,42 +222,3 @@ static unsigned char *decode_sacch(GS_CTX *ctx, unsigned char *burst, unsigned i
*datalen = (unsigned int)len;
return ctx->msg;
}
-
-
-/*
- * decode_cch
- *
- * Decode a "common" control channel. Most control channels use
- * the same burst, interleave, Viterbi and parity configuration.
- * The documentation for the control channels defines SACCH first
- * and then just keeps referring to that.
- *
- * The current (investigated) list is as follows:
- *
- * BCCH Norm
- * BCCH Ext
- * PCH
- * AGCH
- * CBCH (SDCCH/4)
- * CBCH (SDCCH/8)
- * SDCCH/4
- * SACCH/C4
- * SDCCH/8
- * SACCH/C8
- *
- * We provide two functions, one for where all four bursts are
- * contiguous, and one where they aren't.
- */
-unsigned char *decode_cch(GS_CTX *ctx, unsigned char *burst, unsigned int *datalen) {
-
- return decode_sacch(ctx, burst, datalen);
-}
-
-
-#if 0
-unsigned char *decode_cch(GS_CTX *ctx, unsigned char *e, unsigned int *datalen) {
-
- return decode_sacch(ctx, e, e + eBLOCK_SIZE, e + 2 * eBLOCK_SIZE,
- e + 3 * eBLOCK_SIZE, datalen);
-}
-#endif
diff --git a/gsmstack/conv.c b/gsmstack/conv.c
new file mode 100644
index 0000000..5b7ab65
--- /dev/null
+++ b/gsmstack/conv.c
@@ -0,0 +1,206 @@
+/* This file was taken from gsm-tvoid */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <math.h>
+
+//#include "burst_types.h"
+#include "conv.h"
+//#include "fire_crc.h"
+
+
+/*
+ * Convolutional encoding and Viterbi decoding for the GSM CCH+TCH channel.
+ */
+
+/* The class 1 bits are encoded with the 1/2 rate convolutional code defined by
+ * the polynomials:
+ * G0 = 1 + D3+ D4
+ * G1 = 1 + D + D3+ D4
+ * The coded bits {c(0), c(1),..., c(455)} are then defined by:
+ * class 1: c(2k) = u(k) + u(k-3) + u(k-4)
+ * c(2k+1) = u(k) + u(k-1) + u(k-3) + u(k-4) for k = 0,1,...,188
+ * u(k) = 0 for k < 0
+ * class 2:c(378+k) = d(182+k) for k = 0,1,....,77
+ */
+
+
+/*
+ * Convolutional encoding:
+ *
+ * G_0 = 1 + x^3 + x^4
+ * G_1 = 1 + x + x^3 + x^4
+ *
+ * i.e.,
+ *
+ * c_{2k} = u_k + u_{k - 3} + u_{k - 4}
+ * c_{2k + 1} = u_k + u_{k - 1} + u_{k - 3} + u_{k - 4}
+ */
+#define K 5
+#define MAX_ERROR(size) (2 * size + 1)
+
+
+/*
+ * Given the current state and input bit, what are the output bits?
+ *
+ * encode[current_state][input_bit]
+ */
+static const unsigned int encode[1 << (K - 1)][2] = {
+ {0, 3}, {3, 0}, {3, 0}, {0, 3},
+ {0, 3}, {3, 0}, {3, 0}, {0, 3},
+ {1, 2}, {2, 1}, {2, 1}, {1, 2},
+ {1, 2}, {2, 1}, {2, 1}, {1, 2}
+};
+
+
+/*
+ * Given the current state and input bit, what is the next state?
+ *
+ * next_state[current_state][input_bit]
+ */
+static const unsigned int next_state[1 << (K - 1)][2] = {
+ {0, 8}, {0, 8}, {1, 9}, {1, 9},
+ {2, 10}, {2, 10}, {3, 11}, {3, 11},
+ {4, 12}, {4, 12}, {5, 13}, {5, 13},
+ {6, 14}, {6, 14}, {7, 15}, {7, 15}
+};
+
+
+/*
+ * Given the previous state and the current state, what input bit caused
+ * the transition? If it is impossible to transition between the two
+ * states, the value is 2.
+ *
+ * prev_next_state[previous_state][current_state]
+ */
+static const unsigned int prev_next_state[1 << (K - 1)][1 << (K - 1)] = {
+ { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
+ { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
+ { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
+ { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
+ { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
+ { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
+ { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
+ { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
+ { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
+ { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
+ { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
+ { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
+ { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
+ { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
+ { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1},
+ { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1}
+};
+
+
+static inline unsigned int hamming_distance2(unsigned int w) {
+
+ return (w & 1) + !!(w & 2);
+}
+
+
+/*
+static void conv_encode(unsigned char *data, unsigned char *output,
+ unsigned int input_size) {
+
+ unsigned int i, state = 0, o;
+
+ // encode data
+ for(i = 0; i < input_size; i++) {
+ o = encode[state][data[i]];
+ state = next_state[state][data[i]];
+ *output++ = !!(o & 2);
+ *output++ = o & 1;
+ }
+}
+ */
+
+
+int
+conv_decode(unsigned char *output, unsigned char *data,
+ unsigned int input_size) {
+
+ int i, t;
+ unsigned int rdata, state, nstate, b, o, distance, accumulated_error,
+ min_state, min_error, cur_state;
+
+ unsigned int max_error = MAX_ERROR(input_size);
+ unsigned int ae[1 << (K - 1)];
+ unsigned int nae[1 << (K - 1)]; // next accumulated error
+ unsigned int state_history[1 << (K - 1)][CONV_MAX_INPUT_SIZE + 1];
+
+ // initialize accumulated error, assume starting state is 0
+ for(i = 0; i < (1 << (K - 1)); i++)
+ ae[i] = nae[i] = max_error;
+ ae[0] = 0;
+
+ // build trellis
+ for(t = 0; t < input_size; t++) {
+
+ // get received data symbol
+ rdata = (data[2 * t] << 1) | data[2 * t + 1];
+
+ // for each state
+ for(state = 0; state < (1 << (K - 1)); state++) {
+
+ // make sure this state is possible
+ if(ae[state] >= max_error)
+ continue;
+
+ // find all states we lead to
+ for(b = 0; b < 2; b++) {
+
+ // get next state given input bit b
+ nstate = next_state[state][b];
+
+ // find output for this transition
+ o = encode[state][b];
+
+ // calculate distance from received data
+ distance = hamming_distance2(rdata ^ o);
+
+ // choose surviving path
+ accumulated_error = ae[state] + distance;
+ if(accumulated_error < nae[nstate]) {
+
+ // save error for surviving state
+ nae[nstate] = accumulated_error;
+
+ // update state history
+ state_history[nstate][t + 1] = state;
+ }
+ }
+ }
+
+ // get accumulated error ready for next time slice
+ for(i = 0; i < (1 << (K - 1)); i++) {
+ ae[i] = nae[i];
+ nae[i] = max_error;
+ }
+ }
+
+ // the final state is the state with the fewest errors
+ min_state = (unsigned int)-1;
+ min_error = max_error;
+ for(i = 0; i < (1 << (K - 1)); i++) {
+ if(ae[i] < min_error) {
+ min_state = i;
+ min_error = ae[i];
+ }
+ }
+
+ // trace the path
+ cur_state = min_state;
+ for(t = input_size; t >= 1; t--) {
+ min_state = cur_state;
+ cur_state = state_history[cur_state][t]; // get previous
+ output[t - 1] = prev_next_state[cur_state][min_state];
+ }
+
+ // return the number of errors detected (hard-decision)
+ return min_error;
+}
diff --git a/gsmstack/conv.h b/gsmstack/conv.h
new file mode 100644
index 0000000..4bd96a1
--- /dev/null
+++ b/gsmstack/conv.h
@@ -0,0 +1,24 @@
+/* This file was taken from gsm-tvoid */
+#ifndef _GSM_CONV_H
+#define _GSM_CONV_H
+
+#define DATA_BLOCK_SIZE 184
+#define PARITY_SIZE 40
+#define FLUSH_BITS_SIZE 4
+#define PARITY_OUTPUT_SIZE (DATA_BLOCK_SIZE + PARITY_SIZE + FLUSH_BITS_SIZE)
+
+#define CONV_INPUT_SIZE_TCH_F 189
+#define CONV_INPUT_SIZE_CCH PARITY_OUTPUT_SIZE
+#define CONV_MAX_INPUT_SIZE PARITY_OUTPUT_SIZE
+#define CONV_SIZE (2 * CONV_MAX_INPUT_SIZE)
+
+#define BLOCKS 4
+#define iBLOCK_SIZE (CONV_SIZE / BLOCKS)
+#define eBLOCK_SIZE (iBLOCK_SIZE + 2)
+
+int conv_decode(unsigned char *output, unsigned char *data,
+ unsigned int input_size);
+int parity_check(unsigned char *data);
+int compress_bits(unsigned char *dbuf, int dlen, unsigned char *src, int len);
+
+#endif /* _GSM_CONV_H */
diff --git a/gsmstack/interleave.c b/gsmstack/interleave.c
new file mode 100644
index 0000000..7899274
--- /dev/null
+++ b/gsmstack/interleave.c
@@ -0,0 +1,48 @@
+/* This file was taken from gsm-tvoid */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "interleave.h"
+
+int
+interleave_init(INTERLEAVE_CTX *ictx, int size, int block_size)
+{
+ ictx->trans_size = size;
+ ictx->trans = (unsigned short *)malloc(size * sizeof *ictx->trans);
+
+// DEBUGF("size: %d\n", size);
+// DEBUGF("Block size: %d\n", block_size);
+ int j, k, B;
+ for (k = 0; k < size; k++)
+ {
+ B = k % 4;
+ j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
+ ictx->trans[k] = B * block_size + j;
+ /* Mapping: pos1 goes to pos2: pos1 -> pos2 */
+// DEBUGF("%d -> %d\n", ictx->trans[k], k);
+ }
+// exit(0);
+ return 0;
+}
+
+int
+interleave_deinit(INTERLEAVE_CTX *ictx)
+{
+ if (ictx->trans != NULL)
+ {
+ free(ictx->trans);
+ ictx->trans = NULL;
+ }
+
+ return 0;
+}
+
+void
+interleave_decode(INTERLEAVE_CTX *ictx, unsigned char *dst, unsigned char *src)
+{
+
+ int k;
+ for (k = 0; k < ictx->trans_size; k++)
+ dst[k] = src[ictx->trans[k]];
+}
+
diff --git a/gsmstack/interleave.h b/gsmstack/interleave.h
new file mode 100644
index 0000000..cfd4888
--- /dev/null
+++ b/gsmstack/interleave.h
@@ -0,0 +1,19 @@
+/* This file was taken from gsm-tvoid */
+/*
+ * $Id:$
+ */
+
+#ifndef __GSMSP_INTERLEAVE_H__
+#define __GSMSP_INTERLEAVE_H__ 1
+
+typedef struct _interleave_ctx
+{
+ unsigned short *trans;
+ int trans_size;
+} INTERLEAVE_CTX;
+
+int interleave_init(INTERLEAVE_CTX *ictx, int size, int block_size);
+int interleave_deinit(INTERLEAVE_CTX *ictx);
+void interleave_decode(INTERLEAVE_CTX *ictx, unsigned char *dst, unsigned char *src);
+
+#endif
diff --git a/gsmstack/tch.c b/gsmstack/tch.c
new file mode 100644
index 0000000..f8b4329
--- /dev/null
+++ b/gsmstack/tch.c
@@ -0,0 +1,145 @@
+
+/* GSM TCH/F channel coding
+ *
+ * (C) 2008 by Harald Welte <laforge@gnumonks.org>
+ */
+
+#include "system.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "burst_types.h"
+#include "tch.h"
+//#include "fire_crc.h"
+
+/*
+ * GSM TCH/F -- Traffic Channel (Full Rate)
+ *
+ * Input: 260 bits (182 class-1, 78 class-2 bits)
+ *
+ * 1. Rearrange according to Table 2 (TS 05.03)
+ * 2. Add 3 parity bits for first 50 class-1 bits (d0...49)
+ * 3. Add four tailing bits to class-1. (Output 182 + 3 + 4 = 189 bit)
+ * 4. Convolutional encode of class-1 (Output = 189 * 2 = 378 bit)
+ * 5. Append class-2 bits (Output = 378 + 78 = 456bit)
+ * 3. Interleave. (Output 456 bit)
+ * 4. Map on bursts. (4 x 156 bit bursts with each 2x57 bit content data)
+ */
+
+
+#if 0
+/*
+ * Parity (FIRE) for the GSM SACCH channel.
+ *
+ * g(x) = (x^23 + 1)(x^17 + x^3 + 1)
+ * = x^40 + x^26 + x^23 + x^17 + x^3 + 1
+ */
+
+static const unsigned char parity_polynomial[PARITY_SIZE + 1] = {
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0,
+ 1
+};
+
+// remainder after dividing data polynomial by g(x)
+static const unsigned char parity_remainder[PARITY_SIZE] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+
+/*
+static void parity_encode(unsigned char *d, unsigned char *p) {
+
+ int i;
+ unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q;
+
+ memcpy(buf, d, DATA_BLOCK_SIZE);
+ memset(buf + DATA_BLOCK_SIZE, 0, PARITY_SIZE);
+
+ for(q = buf; q < buf + DATA_BLOCK_SIZE; q++)
+ if(*q)
+ for(i = 0; i < PARITY_SIZE + 1; i++)
+ q[i] ^= parity_polynomial[i];
+ for(i = 0; i < PARITY_SIZE; i++)
+ p[i] = !buf[DATA_BLOCK_SIZE + i];
+}
+ */
+
+
+static int parity_check(unsigned char *d) {
+
+ unsigned int i;
+ unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q;
+
+ memcpy(buf, d, DATA_BLOCK_SIZE + PARITY_SIZE);
+
+ for(q = buf; q < buf + DATA_BLOCK_SIZE; q++)
+ if(*q)
+ for(i = 0; i < PARITY_SIZE + 1; i++)
+ q[i] ^= parity_polynomial[i];
+ return memcmp(buf + DATA_BLOCK_SIZE, parity_remainder, PARITY_SIZE);
+}
+#endif
+
+static unsigned char *decode_tch_f(GS_CTX *ctx, unsigned char *burst,
+ unsigned int *datalen)
+{
+ int errors, len, data_size;
+ unsigned char conv_data[CONV_SIZE], iBLOCK[BLOCKS][iBLOCK_SIZE],
+ hl, hn, decoded_data[PARITY_OUTPUT_SIZE];
+ //FC_CTX fc_ctx;
+
+ data_size = sizeof ctx->msg;
+ if (datalen)
+ *datalen = 0;
+
+ // unmap the bursts
+ decode_burstmap(iBLOCK[0], burst, &hl, &hn); // XXX ignore stealing bits
+ decode_burstmap(iBLOCK[1], burst + 116, &hl, &hn);
+ decode_burstmap(iBLOCK[2], burst + 116 * 2, &hl, &hn);
+ decode_burstmap(iBLOCK[3], burst + 116 * 3, &hl, &hn);
+
+ // remove interleave
+ interleave_decode(&ctx->interleave_ctx, conv_data, (unsigned char *)iBLOCK);
+ //decode_interleave(conv_data, (unsigned char *)iBLOCK);
+
+ // Viterbi decode of class-1 bits
+ errors = conv_decode(decoded_data, conv_data, CONV_INPUT_SIZE_TCH_F);
+ if (errors) {
+ DEBUGF("conv_decode: %d\n", errors);
+ return NULL;
+ }
+ // reordering + remove four tailing bits (185..188)
+ for (i = 0; i <= 90; i++) {
+ ctx->msg[2*i] = decoded_data[i];
+ ctx->msg[2*i+1] = decoded_data[184-i];
+ }
+ len = 182;
+ // check 3 bit parity (91,92,93) of class-1 bits
+ /* FIXME */
+ // append class-2 bits
+ memcpy(ctx->msg+185, conv_data+(2*CONV_INPUT_SIZE_TCH_F), 78);
+ len += 78; /* should be 260 bits now */
+
+ if (len < data_size) {
+ fprintf(stderr, "error: buf too small (%d < %d)\n",
+ sizeof(ctx->msg), len);
+ return NULL;
+ }
+
+ if (datalen)
+ *datalen = (unsigned int)len;
+ return ctx->msg;
+}
personal git repositories of Harald Welte. Your mileage may vary