aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorpiotr <Piotr Krysik pkrysik@elka.pw.edu.pl>2014-07-20 23:48:32 +0200
committerpiotr <Piotr Krysik pkrysik@elka.pw.edu.pl>2014-07-20 23:48:32 +0200
commitfaacc72413cb64544b8e46beded071ff91826d82 (patch)
treea364be32dfff1433d9d1b7a9ec3480bb54fb0a2a /lib
parent9d5d86362eed527236366023ab0fa4e1b03ac6e7 (diff)
Added typical signalization channels (CCCH, BCCH, SDCCH) decoder and demapper for BCCH.
The implementation is quite dirty at this moment.
Diffstat (limited to 'lib')
-rw-r--r--lib/CMakeLists.txt6
-rw-r--r--lib/burst_printer/bursts_printer_impl.cc4
-rw-r--r--lib/decoding/cch.c553
-rw-r--r--lib/decoding/cch.h59
-rw-r--r--lib/decoding/control_channels_decoder_impl.cc147
-rw-r--r--lib/decoding/control_channels_decoder_impl.h48
-rw-r--r--lib/decoding/fire_crc.c179
-rw-r--r--lib/decoding/fire_crc.h47
-rw-r--r--lib/decoding/interleave.c71
-rw-r--r--lib/decoding/interleave.h28
-rw-r--r--lib/demapping/get_bcch_or_ccch_bursts_impl.cc100
-rw-r--r--lib/demapping/get_bcch_or_ccch_bursts_impl.h44
-rw-r--r--lib/receiver/gsmtap.h72
-rw-r--r--lib/receiver/receiver_impl.h2
14 files changed, 1284 insertions, 76 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 931e0c1..79fa57a 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -30,7 +30,11 @@ list(APPEND gsm_sources
receiver/viterbi_detector.cc
receiver/sch.c
burst_printer/bursts_printer_impl.cc
- )
+ demapping/get_bcch_or_ccch_bursts_impl.cc
+ decoding/control_channels_decoder_impl.cc
+ decoding/cch.c
+ decoding/fire_crc.c
+)
add_library(gnuradio-gsm SHARED ${gsm_sources})
target_link_libraries(gnuradio-gsm ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES}
diff --git a/lib/burst_printer/bursts_printer_impl.cc b/lib/burst_printer/bursts_printer_impl.cc
index dbb7023..c37838b 100644
--- a/lib/burst_printer/bursts_printer_impl.cc
+++ b/lib/burst_printer/bursts_printer_impl.cc
@@ -23,10 +23,10 @@
#endif
#include <gnuradio/io_signature.h>
-#include "bursts_printer_impl.h"
-#include <gsmtap.h>
+#include <gsm/gsmtap.h>
#include <iterator>
#include <algorithm>
+#include "bursts_printer_impl.h"
namespace gr {
namespace gsm {
diff --git a/lib/decoding/cch.c b/lib/decoding/cch.c
new file mode 100644
index 0000000..16db5eb
--- /dev/null
+++ b/lib/decoding/cch.c
@@ -0,0 +1,553 @@
+//#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;*/
+/*}*/
diff --git a/lib/decoding/cch.h b/lib/decoding/cch.h
new file mode 100644
index 0000000..efd5615
--- /dev/null
+++ b/lib/decoding/cch.h
@@ -0,0 +1,59 @@
+//TODO: this file shouldn't be part of the GSM Receiver
+#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
diff --git a/lib/decoding/control_channels_decoder_impl.cc b/lib/decoding/control_channels_decoder_impl.cc
new file mode 100644
index 0000000..544e6bb
--- /dev/null
+++ b/lib/decoding/control_channels_decoder_impl.cc
@@ -0,0 +1,147 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 <+YOU OR YOUR COMPANY+>.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gnuradio/io_signature.h>
+#include <gsm/gsmtap.h>
+#include "control_channels_decoder_impl.h"
+
+namespace gr {
+ namespace gsm {
+
+ control_channels_decoder::sptr
+ control_channels_decoder::make()
+ {
+ return gnuradio::get_initial_sptr
+ (new control_channels_decoder_impl());
+ }
+
+ /*
+ * The private constructor
+ */
+ control_channels_decoder_impl::control_channels_decoder_impl()
+ : gr::block("control_channels_decoder",
+ gr::io_signature::make(0, 0, 0),
+ gr::io_signature::make(0, 0, 0)),
+ d_collected_bursts_num(0)
+ {
+ //initialize de/interleaver
+ int j, k, B;
+ for (k = 0; k < CONV_SIZE; k++)
+ {
+ B = k % 4;
+ j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
+ interleave_trans[k] = B * 114 + j; //114=57 + 57
+ }
+
+ FC_init(&fc_ctx, 40, 184);
+ message_port_register_in(pmt::mp("bursts"));
+ set_msg_handler(pmt::mp("bursts"), boost::bind(&control_channels_decoder_impl::decode, this, _1));
+// message_port_register_out(pmt::mp(""));
+ }
+
+ /*
+ * Our virtual destructor.
+ */
+ control_channels_decoder_impl::~control_channels_decoder_impl()
+ {
+ }
+
+ void control_channels_decoder_impl::decode(pmt::pmt_t msg)
+ {
+ unsigned char iBLOCK[BLOCKS*iBLOCK_SIZE], hl, hn, conv_data[CONV_SIZE], decoded_data[PARITY_OUTPUT_SIZE];
+ d_bursts[d_collected_bursts_num] = msg;
+ d_collected_bursts_num++;
+ //get convecutive bursts
+ pmt::pmt_t header_blob = pmt::car(msg);
+ gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(header_blob);
+
+ if(d_collected_bursts_num==4)
+ {
+ d_collected_bursts_num=0;
+ //reorganize data
+ for(int ii = 0; ii < 4; ii++)
+ {
+ pmt::pmt_t burst_content = pmt::cdr(d_bursts[ii]);
+ int8_t * burst_bits = (int8_t *)pmt::blob_data(burst_content);
+
+ for(int jj = 0; jj < 57; jj++)
+ {
+ iBLOCK[ii*iBLOCK_SIZE+jj] = burst_bits[jj + 3];
+ iBLOCK[ii*iBLOCK_SIZE+jj+57] = burst_bits[jj + 88]; //88 = 3+57+1+26+1
+ }
+ }
+ //deinterleave
+ for (int k = 0; k < CONV_SIZE; k++)
+ {
+ conv_data[k] = iBLOCK[interleave_trans[k]];
+ }
+ //convolutional code decode
+ int errors = conv_decode(decoded_data, conv_data);
+ //std::cout << "Errors:" << errors << " " << parity_check(decoded_data) << std::endl;
+ // 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[PARITY_OUTPUT_SIZE];
+ if (FC_check_crc(&fc_ctx, decoded_data, crc_result) == 0)
+ {
+ //("error: sacch: parity error (errors=%d fn=%d)\n", errors, ctx->fn);
+ //std::cout << "Uncorrectable errors!" << std::endl;
+ errors = -1;
+ } else {
+ //DEBUGF("Successfully corrected parity bits! (errors=%d fn=%d)\n", errors, ctx->fn);
+ //std::cout << "Corrected some errors" << std::endl;
+ memcpy(decoded_data, crc_result, PARITY_OUTPUT_SIZE);
+ errors = 0;
+ }
+ } else {
+ //std::cout << "Everything correct" << std::endl;
+ }
+ //compress bits
+ unsigned char outmsg[27];
+ unsigned char sbuf_len=224;
+ int i, j, c, pos=0;
+ for(i = 0; i < sbuf_len; i += 8) {
+ for(j = 0, c = 0; (j < 8) && (i + j < sbuf_len); j++){
+ c |= (!!decoded_data[i + j]) << j;
+ }
+ outmsg[pos++] = c & 0xff;
+ }
+
+ //printf("%6d %d:", (0 + 1), 0);
+ int jj=0;
+ while (jj < 23){
+ printf(" %02x", outmsg[jj]);//decoded_data[jj]);
+ jj++;
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+ return;
+ }
+ } /* namespace gsm */
+} /* namespace gr */
+
diff --git a/lib/decoding/control_channels_decoder_impl.h b/lib/decoding/control_channels_decoder_impl.h
new file mode 100644
index 0000000..41404fa
--- /dev/null
+++ b/lib/decoding/control_channels_decoder_impl.h
@@ -0,0 +1,48 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 <+YOU OR YOUR COMPANY+>.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GSM_CONTROL_CHANNELS_DECODER_IMPL_H
+#define INCLUDED_GSM_CONTROL_CHANNELS_DECODER_IMPL_H
+
+#include <gsm/control_channels_decoder.h>
+#include "fire_crc.h"
+#include "cch.h"
+
+namespace gr {
+ namespace gsm {
+
+ class control_channels_decoder_impl : public control_channels_decoder
+ {
+ private:
+ unsigned int d_collected_bursts_num;
+ pmt::pmt_t d_bursts[4];
+ unsigned short interleave_trans[CONV_SIZE];
+ FC_CTX fc_ctx;
+ void decode(pmt::pmt_t msg);
+ public:
+ control_channels_decoder_impl();
+ ~control_channels_decoder_impl();
+ };
+
+ } // namespace gsm
+} // namespace gr
+
+#endif /* INCLUDED_GSM_CONTROL_CHANNELS_DECODER_IMPL_H */
+
diff --git a/lib/decoding/fire_crc.c b/lib/decoding/fire_crc.c
new file mode 100644
index 0000000..7cdfc0b
--- /dev/null
+++ b/lib/decoding/fire_crc.c
@@ -0,0 +1,179 @@
+//TODO: this file shouldn't be part of the GSM Receiver
+/* -*- c++ -*- */
+/*
+ * Copyright 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#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");
+}
+
+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;
+}
+
+
diff --git a/lib/decoding/fire_crc.h b/lib/decoding/fire_crc.h
new file mode 100644
index 0000000..aa6319c
--- /dev/null
+++ b/lib/decoding/fire_crc.h
@@ -0,0 +1,47 @@
+//TODO: this file shouldn't be part of the GSM Receiver
+/* -*- c++ -*- */
+/*
+ * Copyright 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#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
diff --git a/lib/decoding/interleave.c b/lib/decoding/interleave.c
new file mode 100644
index 0000000..8388a6f
--- /dev/null
+++ b/lib/decoding/interleave.c
@@ -0,0 +1,71 @@
+//TODO: this file shouldn't be part of the GSM Receiver
+#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]];
+ }
+}
+
diff --git a/lib/decoding/interleave.h b/lib/decoding/interleave.h
new file mode 100644
index 0000000..a50434a
--- /dev/null
+++ b/lib/decoding/interleave.h
@@ -0,0 +1,28 @@
+//TODO: this file shouldn't be part of the GSM Receiver
+/*
+ * $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
diff --git a/lib/demapping/get_bcch_or_ccch_bursts_impl.cc b/lib/demapping/get_bcch_or_ccch_bursts_impl.cc
new file mode 100644
index 0000000..4e8d369
--- /dev/null
+++ b/lib/demapping/get_bcch_or_ccch_bursts_impl.cc
@@ -0,0 +1,100 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 <+YOU OR YOUR COMPANY+>.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gnuradio/io_signature.h>
+#include <gsm/gsmtap.h>
+#include "get_bcch_or_ccch_bursts_impl.h"
+
+namespace gr {
+ namespace gsm {
+
+ get_bcch_or_ccch_bursts::sptr
+ get_bcch_or_ccch_bursts::make()
+ {
+ return gnuradio::get_initial_sptr
+ (new get_bcch_or_ccch_bursts_impl());
+ }
+
+ /*
+ * The private constructor
+ */
+ get_bcch_or_ccch_bursts_impl::get_bcch_or_ccch_bursts_impl()
+ : gr::block("get_bcch_or_ccch_bursts",
+ gr::io_signature::make(0, 0, 0),
+ gr::io_signature::make(0, 0, 0))
+ {
+ message_port_register_in(pmt::mp("bursts"));
+ set_msg_handler(pmt::mp("bursts"), boost::bind(&get_bcch_or_ccch_bursts_impl::filter_ccch, this, _1));
+ message_port_register_out(pmt::mp("bursts"));
+ }
+
+ /*
+ * Our virtual destructor.
+ */
+ get_bcch_or_ccch_bursts_impl::~get_bcch_or_ccch_bursts_impl()
+ {
+ }
+
+ void get_bcch_or_ccch_bursts_impl::filter_ccch(pmt::pmt_t msg)
+ {
+ pmt::pmt_t header_blob = pmt::car(msg);
+ pmt::pmt_t content = pmt::cdr(msg);
+ gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(header_blob);
+ uint32_t frame_nr = header->frame_number;
+
+ uint32_t fn_mod51 = header->frame_number % 51;
+ const int fn51_start = 6;
+ const int fn51_stop = 9;
+
+ if(header->timeslot==0){
+ if(fn_mod51>=fn51_start && fn_mod51<=fn51_stop){
+ uint32_t ii = fn_mod51-fn51_start;
+ d_frame_numbers[ii]=header->frame_number;
+ d_bursts[ii] = msg;
+ }
+
+ if(fn_mod51==fn51_stop){
+ //check for a situation where some BCCH bursts were lost
+ //in this situation frame numbers won't be consecutive
+ bool frames_are_consecutive = true;
+ for(int jj=1; jj<4; jj++)
+ {
+ if((d_frame_numbers[jj]-d_frame_numbers[jj-1])!=1){
+ frames_are_consecutive = false;
+ }
+ }
+ if(frames_are_consecutive)
+ {
+ //send bursts to the output
+ for(int jj=0; jj<4; jj++)
+ {
+ message_port_pub(pmt::mp("bursts"), d_bursts[jj]);
+ }
+ }
+ }
+ }
+ }
+ } /* namespace gsm */
+} /* namespace gr */
+
diff --git a/lib/demapping/get_bcch_or_ccch_bursts_impl.h b/lib/demapping/get_bcch_or_ccch_bursts_impl.h
new file mode 100644
index 0000000..c3c4c59
--- /dev/null
+++ b/lib/demapping/get_bcch_or_ccch_bursts_impl.h
@@ -0,0 +1,44 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 <+YOU OR YOUR COMPANY+>.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GSM_GET_BCCH_OR_CCCH_BURSTS_IMPL_H
+#define INCLUDED_GSM_GET_BCCH_OR_CCCH_BURSTS_IMPL_H
+
+#include <gsm/get_bcch_or_ccch_bursts.h>
+
+namespace gr {
+ namespace gsm {
+
+ class get_bcch_or_ccch_bursts_impl : public get_bcch_or_ccch_bursts
+ {
+ private:
+ uint32_t d_frame_numbers[4];
+ pmt::pmt_t d_bursts[4];
+ public:
+ get_bcch_or_ccch_bursts_impl();
+ ~get_bcch_or_ccch_bursts_impl();
+ void filter_ccch(pmt::pmt_t msg);
+ };
+
+ } // namespace gsm
+} // namespace gr
+
+#endif /* INCLUDED_GSM_GET_BCCH_OR_CCCH_BURSTS_IMPL_H */
+
diff --git a/lib/receiver/gsmtap.h b/lib/receiver/gsmtap.h
deleted file mode 100644
index bf8226b..0000000
--- a/lib/receiver/gsmtap.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef _GSMTAP_H
-#define _GSMTAP_H
-
-/* gsmtap header, pseudo-header in front of the actua GSM payload */
-
-/* GSMTAP is a generic header format for GSM protocol captures,
- * it uses the IANA-assigned UDP port number 4729 and carries
- * payload in various formats of GSM interfaces such as Um MAC
- * blocks or Um bursts.
- *
- * Example programs generating GSMTAP data are airprobe
- * (http://airprobe.org/) or OsmocomBB (http://bb.osmocom.org/)
- */
-
-#include <stdint.h>
-
-#define GSMTAP_VERSION 0x02
-
-#define GSMTAP_TYPE_UM 0x01 /* A Layer 2 MAC block (23 bytes) */
-#define GSMTAP_TYPE_ABIS 0x02
-#define GSMTAP_TYPE_UM_BURST 0x03 /* raw burst bits */
-
-#define GSMTAP_BURST_UNKNOWN 0x00
-#define GSMTAP_BURST_FCCH 0x01
-#define GSMTAP_BURST_PARTIAL_SCH 0x02
-#define GSMTAP_BURST_SCH 0x03
-#define GSMTAP_BURST_CTS_SCH 0x04
-#define GSMTAP_BURST_COMPACT_SCH 0x05
-#define GSMTAP_BURST_NORMAL 0x06
-#define GSMTAP_BURST_DUMMY 0x07
-#define GSMTAP_BURST_ACCESS 0x08
-#define GSMTAP_BURST_NONE 0x09
-
-#define GSMTAP_CHANNEL_UNKNOWN 0x00
-#define GSMTAP_CHANNEL_BCCH 0x01
-#define GSMTAP_CHANNEL_CCCH 0x02
-#define GSMTAP_CHANNEL_RACH 0x03
-#define GSMTAP_CHANNEL_AGCH 0x04
-#define GSMTAP_CHANNEL_PCH 0x05
-#define GSMTAP_CHANNEL_SDCCH 0x06
-#define GSMTAP_CHANNEL_SDCCH4 0x07
-#define GSMTAP_CHANNEL_SDCCH8 0x08
-#define GSMTAP_CHANNEL_TCH_F 0x09
-#define GSMTAP_CHANNEL_TCH_H 0x0a
-#define GSMTAP_CHANNEL_ACCH 0x80
-
-#define GSMTAP_ARFCN_F_PCS 0x8000
-#define GSMTAP_ARFCN_F_UPLINK 0x4000
-#define GSMTAP_ARFCN_MASK 0x3fff
-
-#define GSMTAP_UDP_PORT 4729 /* officially registered with IANA */
-
-struct gsmtap_hdr {
- uint8_t version; /* version, set to GSMTAP_VERSION */
- uint8_t hdr_len; /* length in number of 32bit words */
- uint8_t type; /* see GSMTAP_TYPE_* */
- uint8_t timeslot; /* timeslot (0..7 on Um) */
-
- uint16_t arfcn; /* ARFCN (frequency) */
- int8_t signal_dbm; /* signal level in dBm */
- int8_t snr_db; /* signal/noise ratio in dB */
-
- uint32_t frame_number; /* GSM Frame Number (FN) */
-
- uint8_t sub_type; /* Type of burst/channel, see above */
- uint8_t antenna_nr; /* Antenna Number */
- uint8_t sub_slot; /* sub-slot within timeslot */
- uint8_t res; /* reserved for future use (RFU) */
-
-} __attribute__((packed));
-
-#endif /* _GSMTAP_H */
diff --git a/lib/receiver/receiver_impl.h b/lib/receiver/receiver_impl.h
index 42e6d01..200a951 100644
--- a/lib/receiver/receiver_impl.h
+++ b/lib/receiver/receiver_impl.h
@@ -22,9 +22,9 @@
#define INCLUDED_GSM_RECEIVER_IMPL_H
#include <gsm/receiver.h>
+#include <gsm/gsmtap.h>
#include <gsm_constants.h>
#include <receiver_config.h>
-#include <gsmtap.h>
namespace gr {
namespace gsm {