Control channels decoding with libosmocore
This commit is contained in:
parent
ea34c017b5
commit
b8d33d90f7
|
@ -1,5 +1,6 @@
|
|||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_libosmocore libosmocore)
|
||||
pkg_check_modules(PC_libosmogsm libosmogsm)
|
||||
set(LIBOSMOCORE_DEFINITIONS ${PC_LIBOSMOCORE_CFLAGS_OTHER})
|
||||
|
||||
find_path(
|
||||
|
|
|
@ -34,8 +34,6 @@ list(APPEND grgsm_sources
|
|||
demapping/universal_ctrl_chans_demapper_impl.cc
|
||||
demapping/tch_f_chans_demapper_impl.cc
|
||||
decoding/control_channels_decoder_impl.cc
|
||||
decoding/cch.c
|
||||
decoding/fire_crc.c
|
||||
decoding/tch_f_decoder_impl.cc
|
||||
decoding/AmrCoder.cpp
|
||||
decoding/BitVector.cpp
|
||||
|
|
|
@ -1,558 +0,0 @@
|
|||
/*
|
||||
The Hacker's Choice - http://www.thc.org
|
||||
Part of THC's GSM SCANNER PROJECT
|
||||
*/
|
||||
|
||||
//#include "system.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
//#include <exception>
|
||||
//#include <stdexcept>
|
||||
#include <math.h>
|
||||
//#include "burst_types.h"
|
||||
#include "cch.h"
|
||||
#include "fire_crc.h"
|
||||
|
||||
|
||||
/*
|
||||
* GSM SACCH -- Slow Associated Control Channel
|
||||
*
|
||||
* These messages are encoded exactly the same as on the BCCH.
|
||||
* (Broadcast Control Channel.)
|
||||
*
|
||||
* Input: 184 bits
|
||||
*
|
||||
* 1. Add parity and flushing bits. (Output 184 + 40 + 4 = 228 bit)
|
||||
* 2. Convolutional encode. (Output 228 * 2 = 456 bit)
|
||||
* 3. Interleave. (Output 456 bit)
|
||||
* 4. Map on bursts. (4 x 156 bit bursts with each 2x57 bit content data)
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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];
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
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)]; // accumulated error
|
||||
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) {
|
||||
|
||||
int j;
|
||||
|
||||
for(j = 0; j < 57; j++) {
|
||||
iBLOCK[j] = eBLOCK[j];
|
||||
iBLOCK[j + 57] = eBLOCK[j + 59];
|
||||
}
|
||||
*hl = eBLOCK[57];
|
||||
*hn = eBLOCK[58];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Transmitted bits are sent least-significant first.
|
||||
*/
|
||||
static int compress_bits(unsigned char *dbuf, unsigned int dbuf_len,
|
||||
unsigned char *sbuf, unsigned int sbuf_len) {
|
||||
|
||||
unsigned int i, j, c, pos = 0;
|
||||
|
||||
if(dbuf_len < ((sbuf_len + 7) >> 3))
|
||||
return -1;
|
||||
|
||||
for(i = 0; i < sbuf_len; i += 8) {
|
||||
for(j = 0, c = 0; (j < 8) && (i + j < sbuf_len); j++)
|
||||
c |= (!!sbuf[i + j]) << j;
|
||||
dbuf[pos++] = c & 0xff;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int get_ns_l3_len(unsigned char *data, unsigned int datalen) {
|
||||
|
||||
if((data[0] & 3) != 1) {
|
||||
fprintf(stderr, "error: get_ns_l3_len: pseudo-length reserved "
|
||||
"bits bad (%2.2x)\n", data[0] & 3);
|
||||
return -1;
|
||||
}
|
||||
return (data[0] >> 2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*static unsigned char *decode_sacch(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*/
|
||||
/* errors = conv_decode(decoded_data, conv_data);*/
|
||||
/* //DEBUGF("conv_decode: %d\n", errors);*/
|
||||
|
||||
/* // check parity*/
|
||||
/* // If parity check error detected try to fix it.*/
|
||||
/* if (parity_check(decoded_data))*/
|
||||
/* {*/
|
||||
/* unsigned char crc_result[224];*/
|
||||
/* if (FC_check_crc(&fc_ctx, decoded_data, crc_result) == 0)*/
|
||||
/* {*/
|
||||
/* errors = -1;*/
|
||||
/* //DEBUGF("error: sacch: parity error (%d fn=%d)\n",*/
|
||||
/* // errors, ctx->fn);*/
|
||||
/* return NULL;*/
|
||||
/* } else {*/
|
||||
/* //DEBUGF("Successfully corrected parity bits! (errors=%d fn=%d)\n",*/
|
||||
/* // errors, ctx->fn);*/
|
||||
/* memcpy(decoded_data, crc_result, sizeof crc_result);*/
|
||||
/* errors = 0;*/
|
||||
/* }*/
|
||||
/* }*/
|
||||
|
||||
/* if (errors)*/
|
||||
/* printf("WRN: errors=%d fn=%d\n", errors, ctx->fn);*/
|
||||
|
||||
/* if((len = compress_bits(ctx->msg, data_size, decoded_data,*/
|
||||
/* DATA_BLOCK_SIZE)) < 0) {*/
|
||||
/* fprintf(stderr, "error: compress_bits\n");*/
|
||||
/* return NULL;*/
|
||||
/* }*/
|
||||
/* 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;*/
|
||||
/*}*/
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*unsigned char *decode_facch(GS_CTX *ctx, unsigned char *burst, unsigned int *datalen, int offset) {*/
|
||||
|
||||
/* int errors, len, data_size;*/
|
||||
/* unsigned char conv_data[CONV_SIZE], iBLOCK[BLOCKS * 2][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);*/
|
||||
/* decode_burstmap(iBLOCK[4], burst + 116 * 4, &hl, &hn);*/
|
||||
/* decode_burstmap(iBLOCK[5], burst + 116 * 5, &hl, &hn);*/
|
||||
/* decode_burstmap(iBLOCK[6], burst + 116 * 6, &hl, &hn);*/
|
||||
/* decode_burstmap(iBLOCK[7], burst + 116 * 7, &hl, &hn);*/
|
||||
|
||||
/* // remove interleave*/
|
||||
/* if (offset == 0)*/
|
||||
/* interleave_decode(&ctx->interleave_facch_f1_ctx, conv_data, (unsigned char *)iBLOCK);*/
|
||||
/* else*/
|
||||
/* interleave_decode(&ctx->interleave_facch_f2_ctx, conv_data, (unsigned char *)iBLOCK);*/
|
||||
/* //decode_interleave(conv_data, (unsigned char *)iBLOCK);*/
|
||||
|
||||
/* // Viterbi decode*/
|
||||
/* errors = conv_decode(decoded_data, conv_data);*/
|
||||
/* //DEBUGF("conv_decode: %d\n", errors);*/
|
||||
|
||||
/* // check parity*/
|
||||
/* // If parity check error detected try to fix it.*/
|
||||
/* if (parity_check(decoded_data)) {*/
|
||||
/* FC_init(&fc_ctx, 40, 184);*/
|
||||
/* unsigned char crc_result[224];*/
|
||||
/* if (FC_check_crc(&fc_ctx, decoded_data, crc_result) == 0)*/
|
||||
/* {*/
|
||||
/* //DEBUGF("error: sacch: parity error (errors=%d fn=%d)\n", errors, ctx->fn);*/
|
||||
/* errors = -1;*/
|
||||
/* return NULL;*/
|
||||
/* } else {*/
|
||||
/* //DEBUGF("Successfully corrected parity bits! (errors=%d fn=%d)\n", errors, ctx->fn);*/
|
||||
/* memcpy(decoded_data, crc_result, sizeof crc_result);*/
|
||||
/* errors = 0;*/
|
||||
/* }*/
|
||||
/* }*/
|
||||
|
||||
/* if (errors)*/
|
||||
/* fprintf(stderr, "WRN: errors=%d fn=%d\n", errors, ctx->fn);*/
|
||||
|
||||
/* if ((len = compress_bits(ctx->msg, data_size, decoded_data,*/
|
||||
/* DATA_BLOCK_SIZE)) < 0) {*/
|
||||
/* fprintf(stderr, "error: compress_bits\n");*/
|
||||
/* return NULL;*/
|
||||
/* }*/
|
||||
/* 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;*/
|
||||
/*}*/
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
The Hacker's Choice - http://www.thc.org
|
||||
Part of THC's GSM SCANNER PROJECT
|
||||
*/
|
||||
|
||||
#ifndef __GSMSTACK_CCH_H__
|
||||
#define __GSMSTACK_CCH_H__ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//#include "gsmstack.h"
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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 PARITY_OUTPUT_SIZE
|
||||
#define CONV_SIZE (2 * CONV_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);
|
||||
int parity_check(unsigned char *d);
|
||||
//unsigned char *decode_cch(GS_CTX *ctx, unsigned char *burst, unsigned int *len);
|
||||
//unsigned char *decode_facch(GS_CTX *ctx, unsigned char *burst, unsigned int *len, int offset);
|
||||
//unsigned char *decode_cch(GS_CTX *ctx, unsigned char *, unsigned char *, unsigned char *, unsigned char *, unsigned int *len);
|
||||
//unsigned char *decode_cch(GS_CTX *ctx, unsigned char *, unsigned int *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -84,15 +84,16 @@ namespace gr {
|
|||
sbit_t bursts_s[116 * 4];
|
||||
uint8_t result[23];
|
||||
int n_errors, n_bits_total;
|
||||
int8_t header_plus_data[sizeof(gsmtap_hdr)+DATA_BYTES];
|
||||
|
||||
d_bursts[d_collected_bursts_num] = msg;
|
||||
d_collected_bursts_num++;
|
||||
//get convecutive bursts
|
||||
|
||||
//get convecutive bursts
|
||||
if(d_collected_bursts_num==4)
|
||||
{
|
||||
d_collected_bursts_num=0;
|
||||
//reorganize data
|
||||
//reorganize data from input bursts
|
||||
for(int ii = 0; ii < 4; ii++)
|
||||
{
|
||||
pmt::pmt_t header_plus_burst = pmt::cdr(d_bursts[ii]);
|
||||
|
@ -106,18 +107,17 @@ namespace gr {
|
|||
//decode
|
||||
gsm0503_xcch_decode(result, bursts_s, &n_errors, &n_bits_total);
|
||||
|
||||
//send to the output
|
||||
//extract header of the first burst of the four bursts
|
||||
pmt::pmt_t first_header_plus_burst = pmt::cdr(d_bursts[0]);
|
||||
gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(first_header_plus_burst);
|
||||
int8_t header_plus_data[sizeof(gsmtap_hdr)+DATA_BYTES];
|
||||
//copy header and data
|
||||
memcpy(header_plus_data, header, sizeof(gsmtap_hdr));
|
||||
|
||||
memcpy(header_plus_data+sizeof(gsmtap_hdr), result, DATA_BYTES);
|
||||
//set data type in the header
|
||||
((gsmtap_hdr*)header_plus_data)->type = GSMTAP_TYPE_UM;
|
||||
|
||||
pmt::pmt_t msg_binary_blob = pmt::make_blob(header_plus_data,DATA_BYTES+sizeof(gsmtap_hdr));
|
||||
pmt::pmt_t msg_out = pmt::cons(pmt::PMT_NIL, msg_binary_blob);
|
||||
|
||||
//prepare message
|
||||
pmt::pmt_t msg_out = pmt::cons(pmt::PMT_NIL, pmt::make_blob(header_plus_data,DATA_BYTES+sizeof(gsmtap_hdr)));
|
||||
//send message to the output
|
||||
message_port_pub(pmt::mp("msgs"), msg_out);
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -24,11 +24,8 @@
|
|||
#define INCLUDED_GSM_CONTROL_CHANNELS_DECODER_IMPL_H
|
||||
|
||||
#include <grgsm/decoding/control_channels_decoder.h>
|
||||
#include "fire_crc.h"
|
||||
#include "cch.h"
|
||||
extern "C" {
|
||||
#include <osmocom/coding/gsm0503_coding.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
}
|
||||
|
||||
namespace gr {
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
The Hacker's Choice - http://www.thc.org
|
||||
Part of THC's GSM SCANNER PROJECT
|
||||
*/
|
||||
|
||||
|
||||
#include "fire_crc.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define REM(x, y) (x) % (y)
|
||||
|
||||
static int FC_syndrome_shift(FC_CTX *ctx, unsigned int bit);
|
||||
|
||||
static int
|
||||
outit(int *data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%d ", data[i]);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
FC_init(FC_CTX *ctx, unsigned int crc_size, unsigned int data_size)
|
||||
{
|
||||
ctx->crc_size = crc_size;
|
||||
ctx->data_size = data_size;
|
||||
ctx->syn_start = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
FC_check_crc(FC_CTX *ctx, unsigned char *input_bits, unsigned char *control_data)
|
||||
{
|
||||
int j,error_count = 0, error_index = 0, success_flag = 0, syn_index = 0;
|
||||
unsigned int i;
|
||||
|
||||
ctx->syn_start = 0;
|
||||
// reset the syndrome register
|
||||
memset(ctx->syndrome_reg, 0, sizeof ctx->syndrome_reg);
|
||||
|
||||
// shift in the data bits
|
||||
for (i=0; i < ctx->data_size; i++) {
|
||||
error_count = FC_syndrome_shift(ctx, input_bits[i]);
|
||||
control_data[i] = input_bits[i];
|
||||
}
|
||||
|
||||
// shift in the crc bits
|
||||
for (i=0; i < ctx->crc_size; i++) {
|
||||
error_count = FC_syndrome_shift(ctx, 1-input_bits[i+ctx->data_size]);
|
||||
}
|
||||
|
||||
// Find position of error burst
|
||||
if (error_count == 0) {
|
||||
error_index = 0;
|
||||
}
|
||||
else {
|
||||
error_index = 1;
|
||||
error_count = FC_syndrome_shift(ctx, 0);
|
||||
error_index += 1;
|
||||
while (error_index < (ctx->data_size + ctx->crc_size) ) {
|
||||
error_count = FC_syndrome_shift(ctx, 0);
|
||||
error_index += 1;
|
||||
if ( error_count == 0 ) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Test for correctable errors
|
||||
//printf("error_index %d\n",error_index);
|
||||
if (error_index == 224) success_flag = 0;
|
||||
else {
|
||||
|
||||
// correct index depending on the position of the error
|
||||
if (error_index == 0) syn_index = error_index;
|
||||
else syn_index = error_index - 1;
|
||||
|
||||
// error burst lies within data bits
|
||||
if (error_index < 184) {
|
||||
//printf("error < bit 184,%d\n",error_index);
|
||||
j = error_index;
|
||||
while ( j < (error_index+12) ) {
|
||||
if (j < 184) {
|
||||
control_data[j] = control_data[j] ^
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+39-j+syn_index,40)];
|
||||
}
|
||||
else break;
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
else if ( error_index > 212 ) {
|
||||
//printf("error > bit 212,%d\n",error_index);
|
||||
j = 0;
|
||||
while ( j < (error_index - 212) ) {
|
||||
control_data[j] = control_data[j] ^
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+39-j-224+syn_index,40)];
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
// for 183 < error_index < 213 error in parity alone so ignore
|
||||
success_flag = 1;
|
||||
}
|
||||
return success_flag;
|
||||
}
|
||||
|
||||
static int
|
||||
FC_syndrome_shift(FC_CTX *ctx, unsigned int bit)
|
||||
{
|
||||
int error_count = 0;
|
||||
unsigned int i;
|
||||
|
||||
if (ctx->syn_start == 0)
|
||||
ctx->syn_start = 39;
|
||||
else ctx->syn_start -= 1;
|
||||
|
||||
int temp_syndrome_reg[sizeof ctx->syndrome_reg];
|
||||
|
||||
memcpy(temp_syndrome_reg, ctx->syndrome_reg, sizeof temp_syndrome_reg);
|
||||
|
||||
temp_syndrome_reg[REM(ctx->syn_start+3,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+3,40)] ^
|
||||
ctx->syndrome_reg[ctx->syn_start];
|
||||
temp_syndrome_reg[REM(ctx->syn_start+17,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+17,40)] ^
|
||||
ctx->syndrome_reg[ctx->syn_start];
|
||||
temp_syndrome_reg[REM(ctx->syn_start+23,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+23,40)] ^
|
||||
ctx->syndrome_reg[ctx->syn_start];
|
||||
temp_syndrome_reg[REM(ctx->syn_start+26,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+26,40)] ^
|
||||
ctx->syndrome_reg[ctx->syn_start];
|
||||
|
||||
temp_syndrome_reg[REM(ctx->syn_start+4,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+4,40)] ^ bit;
|
||||
temp_syndrome_reg[REM(ctx->syn_start+6,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+6,40)] ^ bit;
|
||||
temp_syndrome_reg[REM(ctx->syn_start+10,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+10,40)] ^ bit;
|
||||
temp_syndrome_reg[REM(ctx->syn_start+16,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+16,40)] ^ bit;
|
||||
temp_syndrome_reg[REM(ctx->syn_start+27,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+27,40)] ^ bit;
|
||||
temp_syndrome_reg[REM(ctx->syn_start+29,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+29,40)] ^ bit;
|
||||
temp_syndrome_reg[REM(ctx->syn_start+33,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+33,40)] ^ bit;
|
||||
temp_syndrome_reg[REM(ctx->syn_start+39,40)] =
|
||||
ctx->syndrome_reg[REM(ctx->syn_start+39,40)] ^ bit;
|
||||
|
||||
temp_syndrome_reg[ctx->syn_start] = ctx->syndrome_reg[ctx->syn_start] ^ bit;
|
||||
|
||||
memcpy(ctx->syndrome_reg, temp_syndrome_reg, sizeof ctx->syndrome_reg);
|
||||
|
||||
for (i = 0; i < 28; i++) {
|
||||
error_count = error_count + ctx->syndrome_reg[REM(ctx->syn_start+i,40)];
|
||||
}
|
||||
return error_count;
|
||||
}
|
||||
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
The Hacker's Choice - http://www.thc.org
|
||||
Part of THC's GSM SCANNER PROJECT
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef INCLUDED_FIRE_CRC_H
|
||||
#define INCLUDED_FIRE_CRC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int crc_size;
|
||||
unsigned int data_size;
|
||||
unsigned int syn_start;
|
||||
int syndrome_reg[40];
|
||||
} FC_CTX;
|
||||
|
||||
int FC_init(FC_CTX *ctx, unsigned int crc_size, unsigned int data_size);
|
||||
int FC_check_crc(FC_CTX *ctx, unsigned char *input_bits, unsigned char *control_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
The Hacker's Choice - http://www.thc.org
|
||||
Part of THC's GSM SCANNER PROJECT
|
||||
*/
|
||||
|
||||
#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 */
|
||||
//printf("%d -> %d\n", ictx->trans[k], k);
|
||||
}
|
||||
// exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
interleave_init_facch_f(INTERLEAVE_CTX *ictx, int size, int block_size, int block_offset)
|
||||
{
|
||||
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 + block_offset) % 8;
|
||||
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)
|
||||
{
|
||||
printf("Lol\n");
|
||||
int k;
|
||||
for (k = 0; k < ictx->trans_size; k++)
|
||||
{
|
||||
printf("k=%d, ictx->trans[k]=%d\n", k, ictx->trans[k]);
|
||||
dst[k] = src[ictx->trans[k]];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
The Hacker's Choice - http://www.thc.org
|
||||
Part of THC's GSM SCANNER PROJECT
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id:$
|
||||
*/
|
||||
|
||||
#ifndef __GSMSP_INTERLEAVE_H__
|
||||
#define __GSMSP_INTERLEAVE_H__ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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_init_facch_f(INTERLEAVE_CTX *ictx, int size, int block_size, int block_offset);
|
||||
int interleave_deinit(INTERLEAVE_CTX *ictx);
|
||||
void interleave_decode(INTERLEAVE_CTX *ictx, unsigned char *dst, unsigned char *src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue