diff options
author | Harald Welte <laforge@gnumonks.org> | 2008-12-01 10:28:04 +0530 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2008-12-01 10:28:04 +0530 |
commit | 10f2fcca8dd1be2719bccefa16fd9dac9a76c749 (patch) | |
tree | 0b521a2ccc7d0d81a89e08b05650dec2421777d2 /gsmstack | |
parent | fd405f799425b6832a0c9cc7a56b07f43288b8b1 (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
Diffstat (limited to 'gsmstack')
-rw-r--r-- | gsmstack/cch.c | 321 | ||||
-rw-r--r-- | gsmstack/conv.c | 206 | ||||
-rw-r--r-- | gsmstack/conv.h | 24 | ||||
-rw-r--r-- | gsmstack/interleave.c | 48 | ||||
-rw-r--r-- | gsmstack/interleave.h | 19 | ||||
-rw-r--r-- | gsmstack/tch.c | 145 |
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; +} |