From 19e70e64b98c50eb8bcc6221d43e3c3b615d88ca Mon Sep 17 00:00:00 2001
From: Piotr Krysik <perper@o2.pl>
Date: Thu, 28 May 2009 19:44:12 +0200
Subject: added decoder to the repository

---
 src/lib/decoder/Makefile.am   |  34 +++++
 src/lib/decoder/burst_types.h | 213 +++++++++++++++++++++++++++
 src/lib/decoder/sch.c         | 333 ++++++++++++++++++++++++++++++++++++++++++
 src/lib/decoder/sch.h         |  17 +++
 src/lib/decoder/system.h      |  11 ++
 5 files changed, 608 insertions(+)
 create mode 100644 src/lib/decoder/Makefile.am
 create mode 100644 src/lib/decoder/burst_types.h
 create mode 100644 src/lib/decoder/sch.c
 create mode 100644 src/lib/decoder/sch.h
 create mode 100644 src/lib/decoder/system.h

(limited to 'src/lib')

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
+
-- 
cgit v1.2.3