SCH decoding with libosmocore
diff --git a/lib/receiver/sch.c b/lib/receiver/sch.c
index 3273237..a75673f 100644
--- a/lib/receiver/sch.c
+++ b/lib/receiver/sch.c
@@ -1,280 +1,73 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
+/* -*- c++ -*- */
+/*
+ * @file
+ * @author Piotr Krysik <ptrkrysik@gmail.com>
+ * @section LICENSE
+ *
+ * Gr-gsm 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.
+ *
+ * Gr-gsm 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 gr-gsm; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
 #include <string.h>
 #include "gsm_constants.h"
 
-#define DEBUGF(a...)	{ \
-    fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \
-    fprintf(stderr, a); \
-} while (0)
+#include <osmocom/coding/gsm0503_coding.h>
+#include <osmocom/core/utils.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)
+static int ubits2sbits(ubit_t *ubits, sbit_t *sbits, int count)
 {
+    int i;
 
-  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;
-        }
-      }
+    for (i = 0; i < count; i++) {
+	    if (*ubits == 0x23) {
+		    ubits++;
+		    sbits++;
+		    continue;
+	    }
+	    if ((*ubits++) & 1)
+		    *sbits++ = -127;
+	    else
+		    *sbits++ = 127;
     }
 
-    // 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;
+    return count;
 }
 
-
 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];
+  int t1, t2, t3p, t3, ncc, bcc;
+
+  uint8_t result[4];
+  ubit_t bursts_u[SCH_DATA_LEN*2];
+  sbit_t bursts_s[SCH_DATA_LEN*2];
 
   // extract encoded data from synchronization burst
   /* buf, 39 bit */
   /* buf + 39 + 64 = 103, 39 */
-  memcpy(data, buf, SCH_DATA_LEN);
-  memcpy(data + SCH_DATA_LEN, buf + SCH_DATA_LEN + N_SYNC_BITS, SCH_DATA_LEN);
+  memcpy(bursts_u, buf, SCH_DATA_LEN);
+  memcpy(bursts_u + SCH_DATA_LEN, buf + SCH_DATA_LEN + N_SYNC_BITS, SCH_DATA_LEN);
 
-  // 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");
+  ubits2sbits(bursts_u, bursts_s, SCH_DATA_LEN*2);
+  if(gsm0503_sch_decode(result, bursts_s)==-1){
     return 1;
   }
-
+  
   // Synchronization channel information, 44.018 page 171. (V7.2.0)
+  uint8_t decoded_data[25];
+  osmo_pbit2ubit_ext(decoded_data, 0, result, 0, 25, 1);
   ncc =
     (decoded_data[ 7] << 2)  |
     (decoded_data[ 6] << 1)  |
diff --git a/lib/receiver/sch.h b/lib/receiver/sch.h
index 7b5a657..5164c89 100644
--- a/lib/receiver/sch.h
+++ b/lib/receiver/sch.h
@@ -1,3 +1,24 @@
+/* -*- c++ -*- */
+/*
+ * @file
+ * @author Piotr Krysik <ptrkrysik@gmail.com>
+ * @section LICENSE
+ *
+ * Gr-gsm 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.
+ *
+ * Gr-gsm 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 gr-gsm; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
 
 #ifndef __SCH_H__
 #define __SCH_H__ 1