summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPiotr Krysik <perper@o2.pl>2009-05-28 19:44:12 +0200
committerPiotr Krysik <perper@o2.pl>2009-05-28 19:44:12 +0200
commit19e70e64b98c50eb8bcc6221d43e3c3b615d88ca (patch)
treef6b780159cc8123f8290f0935e739ae65414dc51
parent0a452fcc8e030f5bdb7187e1db7182cfc488aa31 (diff)
added decoder to the repository
-rw-r--r--src/lib/decoder/Makefile.am34
-rw-r--r--src/lib/decoder/burst_types.h213
-rw-r--r--src/lib/decoder/sch.c333
-rw-r--r--src/lib/decoder/sch.h17
-rw-r--r--src/lib/decoder/system.h11
5 files changed, 608 insertions, 0 deletions
diff --git a/src/lib/decoder/Makefile.am b/src/lib/decoder/Makefile.am
new file mode 100644
index 0000000..32b55e0
--- /dev/null
+++ b/src/lib/decoder/Makefile.am
@@ -0,0 +1,34 @@
+#
+# Copyright 2001,2002,2004,2005,2006,2007,2008 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) -I$(MAIN_INCLUDEDIR)
+
+noinst_LTLIBRARIES = libdecoder.la
+
+libdecoder_la_SOURCES = \
+ sch.c
+
+noinst_HEADERS = \
+ sch.h \
+ burst_types.h \
+ system.h
diff --git a/src/lib/decoder/burst_types.h b/src/lib/decoder/burst_types.h
new file mode 100644
index 0000000..990e8f1
--- /dev/null
+++ b/src/lib/decoder/burst_types.h
@@ -0,0 +1,213 @@
+// $Id: burst_types.h,v 1.5 2007/03/14 05:44:53 jl Exp $
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gsm_constants.h>
+
+static const int TB_LEN = 3;
+static const int TB_OS1 = 0;
+static const int TB_OS2 = 145;
+static const unsigned char tail_bits[] = {0, 0, 0};
+
+/*
+ * The normal burst is used to carry information on traffic and control
+ * channels.
+ */
+static const int N_TSC_NUM = 8; // number of training sequence codes
+static const int N_TSC_CODE_LEN = 26; // length of tsc
+static const int N_TSC_OS = 61; // tsc offset
+static const int N_EDATA_LEN_1 = 58; // length of first data section
+static const int N_EDATA_OS_1 = 3; // offset of first data section
+static const int N_EDATA_LEN_2 = 58; // length of second data section
+static const int N_EDATA_OS_2 = 87; // offset of second data section
+#if 0
+static const unsigned char n_tsc[][N_TSC_CODE_LEN] = {
+/* 0 */ {
+ 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1
+ },
+/* 1 */ {
+ 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1,
+ 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1
+ },
+/* 2 */ {
+ 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1,
+ 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0
+ },
+/* 3 */ {
+ 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0
+ },
+/* 4 */ {
+ 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1
+ },
+/* 5 */ {
+ 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0
+ },
+/* 6 */ {
+ 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1,
+ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1
+ },
+/* 7 */ {
+ 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0
+ }
+};
+
+#endif
+
+/*
+ * The frequency correction burst is used for frequency synchronization
+ * of the mobile. This is broadcast in TS0 together with the SCH and
+ * BCCH.
+ *
+ * Modulating the bits below causes a spike at 62.5kHz above (below for
+ * COMPACT) the center frequency. One can use this spike with a narrow
+ * band filter to accurately determine the center of the channel.
+ */
+static const int FC_CODE_LEN = 142;
+static const int FC_OS = 3;
+static const unsigned char fc_fb[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char fc_compact_fb[] = {
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
+};
+
+
+/*
+ * The synchronization burst is used for time synchronization of the
+ * mobile. The bits given below were chosen for their correlation
+ * properties. The synchronization channel (SCH) contains a long
+ * training sequence (given below) and carries the TDMA frame number and
+ * base station identity code. It is broadcast in TS0 in the frame
+ * following the frequency correction burst.
+ */
+static const int SB_CODE_LEN = 64;
+static const int SB_ETS_OS = 42;
+static const int SB_EDATA_LEN_1 = 39;
+static const int SB_EDATA_OS_1 = 3;
+static const int SB_EDATA_LEN_2 = 39;
+static const int SB_EDATA_OS_2 = 106;
+static const unsigned char sb_etsc[] = {
+ 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
+ 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1
+};
+
+static const unsigned char sb_cts_etsc[] = {
+ 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0,
+ 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1
+};
+
+static const unsigned char sb_compact_etsc[] = {
+ 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
+ 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0
+};
+
+
+/*
+ * A base tranceiver station must transmit a burst in every timeslot of
+ * every TDMA frame in channel C0. The dummy burst will be transmitted
+ * on all timeslots of all TDMA frames for which no other channel
+ * requires a burst to be transmitted.
+ */
+static const int D_CODE_LEN = 142;
+static const int D_MB_OS = 3;
+static const unsigned char d_mb[] = {
+ 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
+ 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1,
+ 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0
+};
+
+
+/*
+ * The access burst is used for random access from a mobile.
+ */
+static const int AB_ETB_CODE_LEN = 8;
+static const int AB_ETB_OS = 0;
+static const unsigned char ab_etb[] = {
+ 0, 0, 1, 1, 1, 0, 1, 0
+};
+
+static const int AB_SSB_CODE_LEN = 41;
+static const int AB_SSB_OS = 8;
+static const unsigned char ab_ssb[] = {
+ 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0, 0
+};
+
+static const unsigned char ab_ts1_ssb[] = {
+ 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0, 1, 1, 0, 1
+};
+
+static const unsigned char ab_ts2_ssb[] = {
+ 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
+ 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1,
+ 1, 0, 1, 1, 1, 0, 1, 1, 1
+};
+
+
+typedef enum {
+ burst_n_0,
+ burst_n_1,
+ burst_n_2,
+ burst_n_3,
+ burst_n_4,
+ burst_n_5,
+ burst_n_6,
+ burst_n_7,
+ burst_fc,
+ burst_fc_c,
+ burst_s,
+ burst_s_cts,
+ burst_s_c,
+ burst_d,
+ burst_a,
+ burst_a_ts1,
+ burst_a_ts2,
+ burst_not_a_burst
+} burst_t;
+
+static const int N_BURST_TYPES = ((int)(burst_not_a_burst) + 1);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/lib/decoder/sch.c b/src/lib/decoder/sch.c
new file mode 100644
index 0000000..9f570c9
--- /dev/null
+++ b/src/lib/decoder/sch.c
@@ -0,0 +1,333 @@
+#include "system.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "burst_types.h"
+
+/*
+ * Synchronization channel.
+ *
+ * Timeslot Repeat length Frame Number (mod repeat length)
+ * 0 51 1, 11, 21, 31, 41
+ */
+
+/*
+ * Parity (FIRE) for the GSM SCH.
+ *
+ * g(x) = x^10 + x^8 + x^6 + x^5 + x^4 + x^2 + 1
+ */
+#define DATA_BLOCK_SIZE 25
+#define PARITY_SIZE 10
+#define TAIL_BITS_SIZE 4
+#define PARITY_OUTPUT_SIZE (DATA_BLOCK_SIZE + PARITY_SIZE + TAIL_BITS_SIZE)
+
+static const unsigned char parity_polynomial[PARITY_SIZE + 1] = {
+ 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1
+};
+
+static const unsigned char parity_remainder[PARITY_SIZE] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+
+static void parity_encode(unsigned char *d, unsigned char *p)
+{
+
+ unsigned 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);
+}
+
+
+/*
+ * Convolutional encoding and Viterbi decoding for the GSM SCH.
+ * (Equivalent to the GSM SACCH.)
+ *
+ * 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 CONV_INPUT_SIZE PARITY_OUTPUT_SIZE
+#define CONV_SIZE (2 * CONV_INPUT_SIZE)
+#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 *data, unsigned char *output)
+{
+
+ 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;
+}
+
+
+int decode_sch(const unsigned char *buf, int * t1_o, int * t2_o, int * t3_o, int * ncc_o, int * bcc_o)
+{
+
+ int errors, t1, t2, t3p, t3, ncc, bcc;
+ unsigned char data[CONV_SIZE], decoded_data[PARITY_OUTPUT_SIZE];
+
+ // extract encoded data from synchronization burst
+ /* buf, 39 bit */
+ /* buf + 39 + 64 = 103, 39 */
+ memcpy(data, buf, SB_EDATA_LEN_1);
+ memcpy(data + SB_EDATA_LEN_1, buf + SB_EDATA_LEN_1 + N_SYNC_BITS, SB_EDATA_LEN_2);
+
+ // Viterbi decode
+ if (errors = conv_decode(data, decoded_data)) {
+ // fprintf(stderr, "error: sch: conv_decode (%d)\n", errors);
+ DEBUGF("ERR: conv_decode %d\n", errors);
+ return errors;
+ }
+
+ // check parity
+ if (parity_check(decoded_data)) {
+ // fprintf(stderr, "error: sch: parity failed\n");
+ DEBUGF("ERR: parity_check failed\n");
+ return 1;
+ }
+
+ // Synchronization channel information, 44.018 page 171. (V7.2.0)
+ ncc =
+ (decoded_data[ 7] << 2) |
+ (decoded_data[ 6] << 1) |
+ (decoded_data[ 5] << 0);
+ bcc =
+ (decoded_data[ 4] << 2) |
+ (decoded_data[ 3] << 1) |
+ (decoded_data[ 2] << 0);
+ t1 =
+ (decoded_data[ 1] << 10) |
+ (decoded_data[ 0] << 9) |
+ (decoded_data[15] << 8) |
+ (decoded_data[14] << 7) |
+ (decoded_data[13] << 6) |
+ (decoded_data[12] << 5) |
+ (decoded_data[11] << 4) |
+ (decoded_data[10] << 3) |
+ (decoded_data[ 9] << 2) |
+ (decoded_data[ 8] << 1) |
+ (decoded_data[23] << 0);
+ t2 =
+ (decoded_data[22] << 4) |
+ (decoded_data[21] << 3) |
+ (decoded_data[20] << 2) |
+ (decoded_data[19] << 1) |
+ (decoded_data[18] << 0);
+ t3p =
+ (decoded_data[17] << 2) |
+ (decoded_data[16] << 1) |
+ (decoded_data[24] << 0);
+
+ t3 = 10 * t3p + 1;
+
+ // modulo arithmetic t3 - t2 mod 26
+// tt = ((t3 + 26) - t2) % 26;
+
+// fn = (51 * 26 * t1) + (51 * tt) + t3;
+
+ /*
+ * BSIC: Base Station Identification Code
+ * BCC: Base station Color Code
+ * NCC: Network Color Code
+ *
+ * FN: Frame Number
+ */
+
+// printf("bsic: %x (bcc: %u; ncc: %u)\tFN: %u\n", bsic, bsic & 7,
+// (bsic >> 3) & 7, fn);
+
+// if (fn_o)
+// *fn_o = fn;
+// if (bsic_o)
+ if (t1_o && t2_o && t3_o && ncc_o && bcc_o) {
+ *t1_o = t1;
+ *t2_o = t2;
+ *t3_o = t3;
+ *bcc_o = bcc;
+ *ncc_o = ncc;
+ }
+
+ return 0;
+}
diff --git a/src/lib/decoder/sch.h b/src/lib/decoder/sch.h
new file mode 100644
index 0000000..199d739
--- /dev/null
+++ b/src/lib/decoder/sch.h
@@ -0,0 +1,17 @@
+
+#ifndef __GSMSTACK_H__
+#define __GSMSTACK_H__ 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ int decode_sch(const unsigned char *buf, int * t1_o, int * t2_o, int * t3_o, int * ncc, int * bcc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/lib/decoder/system.h b/src/lib/decoder/system.h
new file mode 100644
index 0000000..414730a
--- /dev/null
+++ b/src/lib/decoder/system.h
@@ -0,0 +1,11 @@
+
+#ifndef __GSMTVOID_SYSTEM_H__
+#define __GSMTVOID_SYSTEM_H__ 1
+
+#define DEBUGF(a...) { \
+ fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \
+ fprintf(stderr, a); \
+} while (0)
+
+#endif
+
personal git repositories of Harald Welte. Your mileage may vary