From 4c0ce874481a4ec895bf55211aa53ff190572e4f Mon Sep 17 00:00:00 2001
From: Dieter Spaar <spaar@mirider.augusta.de>
Date: Thu, 29 Jul 2010 21:24:18 +0200
Subject: Add SACCH support for TCH/F

---
 gsm-receiver/src/lib/decoder/gsmstack.c |  8 +++++-
 gsm-receiver/src/lib/gsm_constants.h    |  2 +-
 gsm-receiver/src/lib/gsm_receiver_cf.cc | 44 +++++++++++++++++++++++----------
 3 files changed, 39 insertions(+), 15 deletions(-)

(limited to 'gsm-receiver/src')

diff --git a/gsm-receiver/src/lib/decoder/gsmstack.c b/gsm-receiver/src/lib/decoder/gsmstack.c
index e5734b9..c1d967e 100644
--- a/gsm-receiver/src/lib/decoder/gsmstack.c
+++ b/gsm-receiver/src/lib/decoder/gsmstack.c
@@ -183,6 +183,9 @@ get_chan_type(enum TIMESLOT_TYPE type, int fn, uint8_t *ss)
           *ss = ((fn % 102) > 51) ? 7 :  3;
       }
   }
+  else if (type == TST_TCHF) {
+    chan_type = GSMTAP_CHANNEL_TCH_F | GSMTAP_CHANNEL_ACCH;
+  }
 
   return chan_type;
 }
@@ -239,9 +242,12 @@ GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn, int
 
 	memset(ctx->msg, 0, sizeof(ctx->msg));
 
-	if (ts_ctx->type == TST_TCHF && type == NORMAL) {
+	if (ts_ctx->type == TST_TCHF && type == NORMAL &&
+	    (fn % 26) != 12 && (fn % 26) != 25) {
 		/* Dieter: we came here because the burst might contain FACCH bits */
 		ctx->fn = fn;
+
+		/* get burst index to TCH bursts only */
 		ts_ctx->burst_count2 = fn % 26;
 
 		if (ts_ctx->burst_count2 >= 12)
diff --git a/gsm-receiver/src/lib/gsm_constants.h b/gsm-receiver/src/lib/gsm_constants.h
index b6cef2f..f6048f2 100644
--- a/gsm-receiver/src/lib/gsm_constants.h
+++ b/gsm-receiver/src/lib/gsm_constants.h
@@ -54,7 +54,7 @@ const unsigned BCCH_FRAMES[] = {2, 3, 4, 5};          //!!the receiver shouldn't
 /* Dieter: xxxx_FIRST marks the first burst of a frame */
 const unsigned TEST_CCH_FRAMES[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 42, 43, 44, 45, 46, 47, 48, 49};
 const unsigned TEST_CCH_FIRST[] =  {1, 0, 0, 0, 1, 0, 0, 0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0};
-const unsigned TRAFFIC_CHANNEL_F[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
+const unsigned TRAFFIC_CHANNEL_F[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}; /* 12, 25: SACCH or IDLE */
 const unsigned TEST51[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50};
 const unsigned SDCCH_SACCH_8_FRAMES[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
 const unsigned SDCCH_SACCH_8_FIRST[] =  {1, 0, 0, 0, 1, 0, 0, 0, 1, 0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  0};
diff --git a/gsm-receiver/src/lib/gsm_receiver_cf.cc b/gsm-receiver/src/lib/gsm_receiver_cf.cc
index 9feabef..2660bdc 100644
--- a/gsm-receiver/src/lib/gsm_receiver_cf.cc
+++ b/gsm-receiver/src/lib/gsm_receiver_cf.cc
@@ -187,20 +187,30 @@ void gsm_receiver_cf::process_normal_burst(burst_counter burst_nr, const unsigne
 #endif
     decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod());
 
-    int i;
-    for (i = 0; i< 148; i++)
-      decrypted_data_float[i] = decrypted_data[i];
-
-    GSM::Time time(burst_nr.get_frame_nr(), ts);
-    GSM::RxBurst rxbrst(decrypted_data_float, time);
-    if (ts - TIMESLOT1 >= 0 && ts - TIMESLOT1 < N_TCH_DECODER) {
-        if ( d_tch_decoder[ts - TIMESLOT1]->processBurst( rxbrst ) == true) {
-          fwrite(d_tch_decoder[ts - TIMESLOT1]->get_voice_frame(), 1 , 33, d_gsm_file);
-        }
-        else if (rxbrst.Hl() || rxbrst.Hu()) {
-        /* Stolen bits are set, might be FACCH */
-          GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst);
+    if (burst_nr.get_t2() == 12 || burst_nr.get_t2() == 25) { /* SACCH of Full Rate TCH */
+      if (ts % 2 == 0) /* SACH position and start depends on the timeslot */
+        first_burst = (burst_nr.get_frame_nr() % 104) == (12 + 26 * (ts / 2));
+      else
+        first_burst = (burst_nr.get_frame_nr() % 104) == (25 + 26 * ((ts - 1) / 2));
+#if 0 /* dump cipher, plain and keystream bits */
+      dump_bits(burst_binary, decrypted_data, burst_nr, first_burst);
+#endif
+      GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst);
+    } else {
+      int i;
+      for (i = 0; i< 148; i++)
+	decrypted_data_float[i] = decrypted_data[i];
+
+      GSM::Time time(burst_nr.get_frame_nr(), ts);
+      GSM::RxBurst rxbrst(decrypted_data_float, time);
+      if (ts - TIMESLOT1 >= 0 && ts - TIMESLOT1 < N_TCH_DECODER) {
+	if ( d_tch_decoder[ts - TIMESLOT1]->processBurst( rxbrst ) == true)
+	  fwrite(d_tch_decoder[ts - TIMESLOT1]->get_voice_frame(), 1 , 33, d_gsm_file);
+	else if(rxbrst.Hl() || rxbrst.Hu()) {
+	  /* Stolen bits are set, might be FACCH */
+	  GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst);
         }
+      }
     }
   }
 
@@ -249,6 +259,14 @@ void gsm_receiver_cf::configure_receiver()
     if (d_gs_ctx.ts_ctx[ts].type == TST_TCHF) {
       d_channel_conf.set_multiframe_type(ts, multiframe_26);
       d_channel_conf.set_burst_types(ts, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
+      /* SACH position depends on the timeslot */
+      if (ts % 2 == 0) {
+	d_channel_conf.set_single_burst_type(ts, 12, normal_burst); /* SACCH for even timeslots */
+	d_channel_conf.set_single_burst_type(ts, 25, empty); /* IDLE for even timeslots */
+      } else {
+	d_channel_conf.set_single_burst_type(ts, 12, empty); /* IDLE for odd timeslots */
+	d_channel_conf.set_single_burst_type(ts, 25, normal_burst); /* SACCH for odd timeslots */
+      }
     }
     else if (d_gs_ctx.ts_ctx[ts].type == TST_SDCCH8) {
       d_channel_conf.set_multiframe_type(ts, multiframe_51);
-- 
cgit v1.2.3