>From 2cf3d7668771c1df56186f59ee89495e055d6d98 Mon Sep 17 00:00:00 2001
From: Jan-Pascal Kwiotek <info@igis.biz>
Date: Fri, 13 Jan 2017 17:22:28 +0100
Subject: [PATCH 1/4] Initial commit for rudimentary DMO support. Changes are
 unfortunately not commented because the development was not in Git.

---
 src/lower_mac/tetra_lower_mac.c | 149 +++++++++++++++++++++++++++++++++++++++-
 src/lower_mac/tetra_scramb.c    |   4 ++
 src/lower_mac/tetra_scramb.h    |   2 +
 src/phy/tetra_burst.c           |  27 ++++++++
 src/phy/tetra_burst.h           |   6 ++
 src/phy/tetra_burst_sync.c      |  33 +++++++--
 6 files changed, 213 insertions(+), 8 deletions(-)

diff --git a/src/lower_mac/tetra_lower_mac.c b/src/lower_mac/tetra_lower_mac.c
index 53fe73a..f948dad 100644
--- a/src/lower_mac/tetra_lower_mac.c
+++ b/src/lower_mac/tetra_lower_mac.c
@@ -73,6 +73,23 @@ static const struct tetra_blk_param tetra_blk_param[] = {
 		.interleave_a	= 101,
 		.have_crc16	= 1,
 	},
+/* DMO SYNC PDU */
+	[DMAC_SYNC] = {
+		.name		= "DMO_SB1",
+		.type345_bits 	= 120,
+		.type2_bits	= 80,
+		.type1_bits	= 60,
+		.interleave_a	= 11,
+		.have_crc16	= 1,
+	},
+	[DMAC_SYNC_SB2] = {
+		.name		= "SB2",
+		.type345_bits	= 216,
+		.type2_bits	= 144,
+		.type1_bits	= 124,
+		.interleave_a	= 101,
+		.have_crc16	= 1,
+	},
 	[TPSAP_T_NDB] = {
 		.name		= "NDB",
 		.type345_bits	= 216,
@@ -97,6 +114,14 @@ static const struct tetra_blk_param tetra_blk_param[] = {
 		.interleave_a	= 103,
 		.have_crc16	= 1,
 	},
+	[TPSAP_T_SCH_F_DMO] = {
+		.name		= "SCH/F",
+		.type345_bits	= 432,
+		.type2_bits	= 288,
+		.type1_bits	= 268,
+		.interleave_a	= 103,
+		.have_crc16	= 1,
+	},
 	[TPSAP_T_BBK] = {
 		.name		= "BBK",
 		.type345_bits	= 30,
@@ -112,6 +137,7 @@ struct tetra_cell_data {
 	struct tetra_tdma_time time;
 
 	uint32_t scramb_init;
+	uint32_t textmessage_length;
 };
 
 static struct tetra_cell_data _tcd, *tcd = &_tcd;
@@ -143,6 +169,26 @@ struct tetra_tmvsap_prim *tmvsap_prim_alloc(uint16_t prim, uint8_t op)
 	return ttp;
 }
 
+void printBits(size_t const size, void const * const ptr)
+{
+    unsigned char *b = (unsigned char*) ptr;
+    unsigned char byte;
+    int i, j;
+
+    for (i=size-1;i>=0;i--)
+    {
+        for (j=7;j>=0;j--)
+        {
+            byte = b[i] & (1<<j);
+            byte >>= j;
+            printf("%u", byte);
+        }
+    }
+    puts("");
+}
+
+
+
 /* incoming TP-SAP UNITDATA.ind  from PHY into lower MAC */
 void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned int len, void *priv)
 {
@@ -151,7 +197,8 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 	uint8_t type3dp[512*4];
 	uint8_t type3[512];
 	uint8_t type2[512];
-
+    	uint8_t frag_offset;  // for variable fields in DMO DMAC SYNC
+ 
 	const struct tetra_blk_param *tbp = &tetra_blk_param[type];
 	struct tetra_mac_state *tms = priv;
 	const char *time_str;
@@ -181,12 +228,23 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 
 	/* De-scramble, pay special attention to SB1 pre-defined scrambling */
 	memcpy(type4, bits, tbp->type345_bits);
-	if (type == TPSAP_T_SB1) {
+	if (type == TPSAP_T_SB1 || type == DMAC_SYNC  || type == DMAC_SYNC_SB2) {
+		printf("type: DMAC_SYNC\n");
+		tetra_scramb_bits(SCRAMB_INIT, type4, tbp->type345_bits);
+		tup->scrambling_code = SCRAMB_INIT;
+	} else if (type == TPSAP_T_SB2){	//jkw
+		printf("type: TPSAP_T_SB2\n");
 		tetra_scramb_bits(SCRAMB_INIT, type4, tbp->type345_bits);
 		tup->scrambling_code = SCRAMB_INIT;
+		printf("scrambling=0\n");
+	} else if (type == TPSAP_T_SCH_F_DMO ){  
+		printf("type: TPSAP_T_SCH_F_DMO %u \n",tcd->scramb_init);
+		tetra_scramb_bits(tcd->scramb_init, type4, tbp->type345_bits);
+		tup->scrambling_code = tcd->scramb_init;
 	} else {
 		tetra_scramb_bits(tcd->scramb_init, type4, tbp->type345_bits);
 		tup->scrambling_code = tcd->scramb_init;
+		printf("scrambling=1\n");
 	}
 
 	DEBUGP("%s %s type4: %s\n", tbp->name, time_str,
@@ -215,8 +273,12 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 			tup->crc_ok = 1;
 			printf("%s %s type1: %s\n", tbp->name, time_str,
 					osmo_ubit_dump(type2, tbp->type1_bits));
-		} else
+		} else {
 			printf("WRONG\n");
+			printf("%s %s type1: %s\n", tbp->name, time_str,
+				osmo_ubit_dump(type2, tbp->type1_bits));
+			//return;
+		}
 	} else if (type == TPSAP_T_BBK) {
 		/* FIXME: RM3014-decode */
 		tup->crc_ok = 1;
@@ -228,6 +290,83 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 	memcpy(msg->l1h, type2, tbp->type1_bits);
 
 	switch (type) {
+	case TPSAP_T_SCH_F_DMO:
+		printf(" Encoding: %s(%2u)", osmo_ubit_dump(type2+28, 7), bits_to_uint(type2+28, 7));
+		printf(" Message: ");
+		int i=0;
+		while (i+28+7 < tcd->textmessage_length) {
+			char message=bits_to_uint(type2+28+7+i, 8);
+			printf("%c",message);
+			i+=8;
+			if (i+28+7 > 29*8) 
+				break;
+		}
+		printf("\n");
+		break;		
+	case DMAC_SYNC:
+		printf(" System code: %s(%2u)", osmo_ubit_dump(type2, 4), bits_to_uint(type2, 4));
+		printf(" PDU type: %s(%u)", osmo_ubit_dump(type2+4, 2), bits_to_uint(type2+4, 2));
+		printf(" Comm type: %s(%u)", osmo_ubit_dump(type2+6, 2), bits_to_uint(type2+6, 2));
+		printf(" AB Channel: %s(%u)", osmo_ubit_dump(type2+10, 2), bits_to_uint(type2+10, 2));
+		printf(" Slot Num: %s(%u)", osmo_ubit_dump(type2+12, 2), bits_to_uint(type2+12, 2));
+		printf(" FN: %s(%u)", osmo_ubit_dump(type2+14, 5), bits_to_uint(type2+14, 5));
+		printf(" Encr: %s(%u)", osmo_ubit_dump(type2+19, 2), bits_to_uint(type2+19, 2));
+			printf("\n");
+			tup->lchan = TETRA_LC_BNCH;
+	break;
+			
+	case DMAC_SYNC_SB2:
+	 	frag_offset=0;
+	 	uint8_t scrambling[32];
+        
+	 	printf(" Fill bit: %s(%u)", osmo_ubit_dump(type2+10, 1), bits_to_uint(type2+10, 1));
+		printf(" Frag flag: %s(%u)", osmo_ubit_dump(type2+11, 1), bits_to_uint(type2+11, 1));
+
+		if(bits_to_uint(type2+11, 1)==1)  {
+			frag_offset=4;	 
+			printf(" Num of SCH/F: %s(%2u)", osmo_ubit_dump(type2+12, 4), bits_to_uint(type2+12, 4));
+		}
+		printf(" Frame countdown: %s(%2u)", osmo_ubit_dump(type2+12+frag_offset, 2), bits_to_uint(type2+12+frag_offset, 2));
+		printf("\n");
+
+		printf(" Dest Addr Type: %s(%2u)", osmo_ubit_dump(type2+14+frag_offset, 2), bits_to_uint(type2+14+frag_offset, 2));
+		printf(" Dest Addr: %s(%2u)", osmo_ubit_dump(type2+16+frag_offset, 24), bits_to_uint(type2+16+frag_offset, 24));
+		printf("\n");
+
+		printf(" Src Addr Type: %s(%2u)", osmo_ubit_dump(type2+40+frag_offset, 2), bits_to_uint(type2+40+frag_offset, 2));
+		printf(" Src addr: %s(%2u)", osmo_ubit_dump(type2+42+frag_offset, 24), bits_to_uint(type2+42+frag_offset, 24));
+		printf("\n");
+
+		printf(" MNI: %s(%2u)", osmo_ubit_dump(type2+66+frag_offset, 24), bits_to_uint(type2+66+frag_offset, 24));
+		printf(" Message Type: %s(%2u)", osmo_ubit_dump(type2+90+frag_offset, 5), bits_to_uint(type2+90+frag_offset, 5));
+		printf("\n");
+       		memcpy(scrambling,type2+66+frag_offset+18,6); // last 6 of mni
+		memcpy(scrambling+6,type2+42+frag_offset,24); // src addr
+		uint32_t scramb_init1 = bits_to_uint(scrambling,32);
+		scramb_init1 = scramb_init1 | 3 ; // last 2 bits have to be 1
+
+		printf("scrambling seq: %s %u\n",osmo_ubit_dump(scrambling,32), scramb_init1);
+		tcd->scramb_init =  scramb_init1;
+
+
+		printf("\nDM-SDS UDATA PDU:: SDS time remaining: %s(%2u)", osmo_ubit_dump(type2+90+5+frag_offset, 4), bits_to_uint(type2+90+5+frag_offset, 4));
+		printf(" DMSDS transaction type: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4, 1), bits_to_uint(type2+90+5+frag_offset+4, 1));
+		printf(" Priority level: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1, 2), bits_to_uint(type2+90+5+frag_offset+4+1, 2));
+			printf("\n");
+		printf(" FCS flag: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1+2, 1), bits_to_uint(type2+90+5+frag_offset+4+1+2, 1));
+		printf(" Additional addressing flag: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1+2+1, 1), bits_to_uint(type2+90+5+frag_offset+4+1+2+1, 1));
+		printf(" Short Data Type Identifier: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1+2+1+1, 4), bits_to_uint(type2+90+5+frag_offset+4+1+2+1+1,4));
+			printf("\n");
+		printf(" Length indicator: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1+2+1+1+4, 11), bits_to_uint(type2+90+5+frag_offset+4+1+2+1+1+4, 11));
+
+
+		tcd->textmessage_length =  bits_to_uint(type2+90+5+frag_offset+4+1+2+1+1+4, 11);
+
+
+		//printBits(32,tcd->scramb_init);
+		tup->lchan = TETRA_LC_BNCH;
+						
+		break;
 	case TPSAP_T_SB1:
 		printf("TMB-SAP SYNC CC %s(0x%02x) ", osmo_ubit_dump(type2+4, 6), bits_to_uint(type2+4, 6));
 		printf("TN %s(%u) ", osmo_ubit_dump(type2+10, 2), bits_to_uint(type2+10, 2));
@@ -264,6 +403,10 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 	case TPSAP_T_SCH_F:
 		tup->lchan = TETRA_LC_SCH_F;
 
+		/*dmo*/
+		printf("%s %s type1: %s\n", tbp->name, time_str,
+			osmo_ubit_dump(type2, tbp->type1_bits));
+
 		/* send voice frames for further processing --sq5bpf */
 		if (tms->cur_burst.is_traffic)
 		{
diff --git a/src/lower_mac/tetra_scramb.c b/src/lower_mac/tetra_scramb.c
index c83165a..f35123b 100644
--- a/src/lower_mac/tetra_scramb.c
+++ b/src/lower_mac/tetra_scramb.c
@@ -20,6 +20,7 @@
  *
  */
 
+#include <inttypes.h>
 #include <stdint.h>
 #include <lower_mac/tetra_scramb.h>
 
@@ -30,6 +31,9 @@
 #define GL(x)		(1<<(x-1))
 #define GALOIS_LFSR	(GL(32)|GL(26)|GL(23)|GL(22)|GL(16)|GL(12)|GL(11)|GL(10)|GL(8)|GL(7)|GL(5)|GL(4)|GL(2)|GL(1))
 
+#define SCRAMB_INIT	3
+#define SCRAMB_ZERO	0
+
 #if 1
 static uint8_t next_lfsr_bit(uint32_t *lf)
 {
diff --git a/src/lower_mac/tetra_scramb.h b/src/lower_mac/tetra_scramb.h
index 9729ac2..0befd99 100644
--- a/src/lower_mac/tetra_scramb.h
+++ b/src/lower_mac/tetra_scramb.h
@@ -12,8 +12,10 @@
 		* p(k) = 1	for k = -31, -30
  */
 #define SCRAMB_INIT	3
+#define SCRAMB_ZERO	0
 
 uint32_t tetra_scramb_get_init(uint16_t mcc, uint16_t mnc, uint8_t colour);
+uint32_t tetra_scramb_get_init_dmo(uint8_t mni,uint32_t src);
 
 int tetra_scramb_get_bits(uint32_t lfsr_init, uint8_t *out, int len);
 
diff --git a/src/phy/tetra_burst.c b/src/phy/tetra_burst.c
index 62efb72..5e3cf5e 100644
--- a/src/phy/tetra_burst.c
+++ b/src/phy/tetra_burst.c
@@ -55,6 +55,11 @@ static const uint8_t f_bits[80] = {
 	[72] = 1, [73] = 1, [74] = 1, [75] = 1,
 	[76] = 1, [77] = 1, [78] = 1, [79] = 1 };
 
+/* 9.4.3.3.3 DMO Radio Aspects preambe */
+static const uint8_t dmo_pre1_bits[12] = { 0,0,1,1,0,0,1,0,0,0,1,1 };
+static const uint8_t dmo_pre2_bits[12] = { 1,0,0,1,1,0,1,0,1,0,0,1 };
+static const uint8_t dmo_pre3_bits[12] = { 0,0,0,1,0,1,0,0,0,1,1,1 };
+
 /* 9.4.4.3.2 Normal Training Sequence */
 static const uint8_t n_bits[22] = { 1,1, 0,1, 0,0, 0,0, 1,1, 1,0, 1,0, 0,1, 1,1, 0,1, 0,0 };
 static const uint8_t p_bits[22] = { 0,1, 1,1, 1,0, 1,0, 0,1, 0,0, 0,0, 1,1, 0,1, 1,1, 1,0 };
@@ -320,6 +325,16 @@ void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_
 		tp_sap_udata_ind(TPSAP_T_SB1, burst+SB_BLK1_OFFSET, SB_BLK1_BITS, priv);
 		tp_sap_udata_ind(TPSAP_T_BBK, burst+SB_BBK_OFFSET, SB_BBK_BITS, priv);
 		tp_sap_udata_ind(TPSAP_T_SB2, burst+SB_BLK2_OFFSET, SB_BLK2_BITS, priv);
+		break;	
+	case TETRA_TRAIN_SYNC_DMO:
+		//printf("\nTETRA_TRAIN_SYNC_DMO");
+		/* Split SB1, SB2 and Broadcast Block */
+		/* send three parts of the burst via TP-SAP into lower MAC */
+		tp_sap_udata_ind(DMAC_SYNC, burst+SB_BLK1_OFFSET, SB_BLK1_BITS, priv);
+		tp_sap_udata_ind(DMAC_SYNC_SB2, burst+252, 216, priv);
+	 	//printf("\n\n############################################\n");
+		//tp_sap_udata_ind(TPSAP_T_BBK, burst+SB_BBK_OFFSET, SB_BBK_BITS, priv);
+		//tp_sap_udata_ind(TPSAP_T_SB2, burst+SB_BLK2_OFFSET, SB_BLK2_BITS, priv);
 		break;
 	case TETRA_TRAIN_NORM_2:
 		/* re-combine the broadcast block */
@@ -341,5 +356,17 @@ void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_
 		tp_sap_udata_ind(TPSAP_T_BBK, bbk_buf, NDB_BBK_BITS, priv);
 		tp_sap_udata_ind(TPSAP_T_SCH_F, ndbf_buf, 2*NDB_BLK_BITS, priv);
 		break;
+	case TETRA_TRAIN_PRE1:
+		/* re-combine the broadcast block */
+		//memcpy(bbk_buf, burst+NDB_BBK1_OFFSET, NDB_BBK1_BITS);
+		//memcpy(bbk_buf+NDB_BBK1_BITS, burst+NDB_BBK2_OFFSET, NDB_BBK2_BITS);
+		/* re-combine the two parts */
+		memcpy(ndbf_buf, burst+14, 216);
+		memcpy(ndbf_buf+216, burst+252, 216);
+		/* send two parts of the burst via TP-SAP into lower MAC */
+		//tp_sap_udata_ind(TPSAP_T_BBK, bbk_buf, NDB_BBK_BITS, priv);
+
+		tp_sap_udata_ind(TPSAP_T_SCH_F_DMO, ndbf_buf, 432, priv);
+		break;
 	}
 }
diff --git a/src/phy/tetra_burst.h b/src/phy/tetra_burst.h
index 8feb09c..60b54fb 100644
--- a/src/phy/tetra_burst.h
+++ b/src/phy/tetra_burst.h
@@ -10,6 +10,9 @@ enum tp_sap_data_type {
 	TPSAP_T_BBK,
 	TPSAP_T_SCH_HU,
 	TPSAP_T_SCH_F,
+	DMAC_SYNC,
+	DMAC_SYNC_SB2,
+	TPSAP_T_SCH_F_DMO,
 };
 
 extern void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned int len, void *priv);
@@ -25,7 +28,10 @@ enum tetra_train_seq {
 	TETRA_TRAIN_NORM_2,
 	TETRA_TRAIN_NORM_3,
 	TETRA_TRAIN_SYNC,
+	TETRA_TRAIN_SYNC_DMO,
 	TETRA_TRAIN_EXT,
+	TETRA_TRAIN_PRE1,
+	TETRA_TRAIN_PRE2,	
 };
 
 /* find a TETRA training sequence in the burst buffer indicated */
diff --git a/src/phy/tetra_burst_sync.c b/src/phy/tetra_burst_sync.c
index e363c74..ff004de 100644
--- a/src/phy/tetra_burst_sync.c
+++ b/src/phy/tetra_burst_sync.c
@@ -31,6 +31,11 @@
 #include <tetra_tdma.h>
 #include <phy/tetra_burst_sync.h>
 
+/* jkw 9.4.3.3.3 DMO Radio Aspects preambe */
+static const uint8_t dmo_pre1_bits[12] = { 0,0,1,1,0,0,1,0,0,0,1,1 };
+static const uint8_t dmo_pre2_bits[12] = { 1,0,0,1,1,0,1,0,1,0,0,1 };
+static const uint8_t dmo_pre3_bits[12] = { 0,0,0,1,0,1,0,0,0,1,1,1 };
+
 struct tetra_phy_state t_phy_state;
 
 void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_seq type, void *priv);
@@ -94,6 +99,7 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 		if (trs->bitbuf_start_bitnum + trs->bits_in_buf < trs->next_frame_start_bitnum)
 			return 0;
 		else {
+			printf("\nRX_S_KNOW_FSTART");
 			/* shift start of frame to start of bitbuf */
 			int offset = trs->next_frame_start_bitnum - trs->bitbuf_start_bitnum;
 			int bits_remaining = trs->bits_in_buf - offset;
@@ -110,6 +116,7 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 			/* not sufficient data for the full frame yet */
 			return len;
 		} else {
+			printf("\nRX_S_LOCKED");
 			/* we have successfully received (at least) one frame */
 			tetra_tdma_time_add_tn(&t_phy_state.time, 1);
 			printf("\nBURST");
@@ -127,20 +134,36 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 						  (1 << TETRA_TRAIN_SYNC), &train_seq_offs);
 			switch (rc) {
 			case TETRA_TRAIN_SYNC:
-				if (train_seq_offs == 214)
-					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv);
-				else {
+				printf("\nTETRA_TRAIN_SYNC %u %u", train_seq_offs, rc );
+
+				if (memcmp(trs->bitbuf, dmo_pre3_bits, sizeof(dmo_pre1_bits))) {
+					printf("\nfound dmo_pre3_bits");
+					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_SYNC_DMO, trs->burst_cb_priv);
+				} else if (train_seq_offs == 214) {
+					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_SYNC_DMO, trs->burst_cb_priv);
+				} else {
 					fprintf(stderr, "#### SYNC burst at offset %u?!?\n", train_seq_offs);
 					trs->state = RX_S_UNLOCKED;
-				}
+				};
 				break;
 			case TETRA_TRAIN_NORM_1:
+				printf("\nTETRA_TRAIN_NORM_1 %u %u",train_seq_offs,rc );
+				if (train_seq_offs == 230) {
+					fprintf(stdout, "#### TETRA_TRAIN_NORM_1 in DMO BURST at offset %u\n", train_seq_offs);
+					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_PRE1, trs->burst_cb_priv);
+				}
+				break;
 			case TETRA_TRAIN_NORM_2:
+				printf("\nTETRA_TRAIN_NORM_2");
+				fprintf(stdout, "####TETRA_TRAIN_NORM_2 at offset %u?!?\n", train_seq_offs);
+				break;
 			case TETRA_TRAIN_NORM_3:
+				printf("\nTETRA_TRAIN_NORM_3");
 				if (train_seq_offs == 244)
 					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv);
 				else
-					fprintf(stderr, "#### SYNC burst at offset %u?!?\n", train_seq_offs);
+					fprintf(stderr, "####2 SYNC burst at offset %u?!?\n", train_seq_offs);
+				tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv);
 				break;
 			default:
 				fprintf(stderr, "#### could not find successive burst training sequence\n");
-- 
2.7.4


>From 89276d23584c931ea74a41cdaafca2f644ac1399 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jannik=20J=C3=BCrgens?= <jjuergens@seemoo.tu-darmstadt.de>
Date: Tue, 17 Jan 2017 17:10:27 +0100
Subject: [PATCH 2/4] cleaning and rewriting parts of the code to reliable
 receive TMO and DMO burst in the physical layer

---
 AUTHORS                    |  2 ++
 src/phy/tetra_burst.c      | 61 +++++++++++++++++++++++++++++------------
 src/phy/tetra_burst.h      |  9 ++++---
 src/phy/tetra_burst_sync.c | 67 +++++++++++++++++++++++-----------------------
 4 files changed, 85 insertions(+), 54 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index a0c987b..7702664 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,3 +1,5 @@
 Harald Welte <laforge@gnumonks.org>
 Sylvain Munaut <tnt@246tNt.com>
 Holger Hans Peter Freyther <holger@freyther.de>
+Jan-Pascal Kwiotek <info@igis.biz>
+Jannik J��rgens <jjuergens@seemoo.tu-darmstadt.de>
diff --git a/src/phy/tetra_burst.c b/src/phy/tetra_burst.c
index 5e3cf5e..f41b3c8 100644
--- a/src/phy/tetra_burst.c
+++ b/src/phy/tetra_burst.c
@@ -31,6 +31,7 @@
 #define SB_BLK1_OFFSET	((6+1+40)*DQPSK4_BITS_PER_SYM)
 #define SB_BBK_OFFSET	((6+1+40+60+19)*DQPSK4_BITS_PER_SYM)
 #define SB_BLK2_OFFSET	((6+1+40+60+19+15)*DQPSK4_BITS_PER_SYM)
+#define SB_BLK2_DMO_OFFSET	((6+1+40+60+19)*DQPSK4_BITS_PER_SYM)
 
 #define SB_BLK1_BITS	(60*DQPSK4_BITS_PER_SYM)
 #define SB_BBK_BITS	(15*DQPSK4_BITS_PER_SYM)
@@ -60,7 +61,7 @@ static const uint8_t dmo_pre1_bits[12] = { 0,0,1,1,0,0,1,0,0,0,1,1 };
 static const uint8_t dmo_pre2_bits[12] = { 1,0,0,1,1,0,1,0,1,0,0,1 };
 static const uint8_t dmo_pre3_bits[12] = { 0,0,0,1,0,1,0,0,0,1,1,1 };
 
-/* 9.4.4.3.2 Normal Training Sequence */
+/* 9.4.4.3.2 Normal Training Sequence (first and second are also for DMO - 9.4.3.3.3 */
 static const uint8_t n_bits[22] = { 1,1, 0,1, 0,0, 0,0, 1,1, 1,0, 1,0, 0,1, 1,1, 0,1, 0,0 };
 static const uint8_t p_bits[22] = { 0,1, 1,1, 1,0, 1,0, 0,1, 0,0, 0,0, 1,1, 0,1, 1,1, 1,0 };
 static const uint8_t q_bits[22] = { 1,0, 1,1, 0,1, 1,1, 0,0, 0,0, 0,1, 1,0, 1,0, 1,1, 0,1 };
@@ -71,7 +72,7 @@ static const uint8_t P_bits[33] = { 1,0,1, 0,1,1, 1,1,1, 1,0,1, 0,1,0, 1,0,1, 1,
 static const uint8_t x_bits[30] = { 1,0, 0,1, 1,1, 0,1, 0,0, 0,0, 1,1, 1,0, 1,0, 0,1, 1,1, 0,1, 0,0, 0,0, 1,1 };
 static const uint8_t X_bits[45] = { 0,1,1,1,0,0,1,1,0,1,0,0,0,0,1,0,0,0,1,1,1,0,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,0 };
 
-/* 9.4.4.3.4 Synchronization training sequence */
+/* 9.4.4.3.4 Synchronization training sequence (also for DMO - 9.4.3.3.4) */
 static const uint8_t y_bits[38] = { 1,1, 0,0, 0,0, 0,1, 1,0, 0,1, 1,1, 0,0, 1,1, 1,0, 1,0, 0,1, 1,1, 0,0, 0,0, 0,1, 1,0, 0,1, 1,1 };
 
 /* 9.4.4.3.5 Tail bits */
@@ -272,11 +273,11 @@ int build_norm_c_d_burst(uint8_t *buf, const uint8_t *bkn1, const uint8_t *bb, c
 }
 
 int tetra_find_train_seq(const uint8_t *in, unsigned int end_of_in,
-			 uint32_t mask_of_train_seq, unsigned int *offset)
+			 uint32_t mask_of_train_seq, unsigned int *offset, unsigned int skip)
 {
 	const uint8_t *cur;
 
-	for (cur = in; cur < in + end_of_in; cur++) {
+	for (cur = in+skip; cur < in + end_of_in; cur++) {
 		int remain_len = (in + end_of_in) - cur;
 
 		if (mask_of_train_seq & (1 << TETRA_TRAIN_SYNC) &&
@@ -313,6 +314,38 @@ int tetra_find_train_seq(const uint8_t *in, unsigned int end_of_in,
 	return -1;
 }
 
+int check_tmo_or_dmo(const uint8_t *in, enum tetra_train_seq type)
+{
+	switch (type) {
+	case TETRA_TRAIN_SYNC:
+		/* if it is a DMO sync burst, it should contain preamble P3 */
+		if (!memcmp(in, dmo_pre3_bits, sizeof(dmo_pre3_bits)))
+			return TETRA_TRAIN_SYNC_DMO;
+		else
+			return TETRA_TRAIN_SYNC;
+		break;
+	case TETRA_TRAIN_NORM_1:
+		/* if it is a DMO normal 1 burst, it should contain preamble P1 */
+		if (!memcmp(in, dmo_pre1_bits, sizeof(dmo_pre1_bits)))
+			return TETRA_TRAIN_NORM_1_DMO;
+		else
+			return TETRA_TRAIN_NORM_1;
+		break;
+	case TETRA_TRAIN_NORM_2:
+		/* if it is a DMO normal 2 burst, it should contain preamble P2 */
+		if (!memcmp(in, dmo_pre2_bits, sizeof(dmo_pre2_bits)))
+			return TETRA_TRAIN_NORM_2_DMO;
+		else
+			return TETRA_TRAIN_NORM_2;
+		break;
+	default:
+		/* There aren't any other DMO burst types, so it must be TMO */
+		return type;
+		break;
+	}
+}
+
+/* splits the bursts in relevant blocks (depending on the type) and sends them to the upper layer */
 void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_seq type, void *priv)
 {
 	uint8_t bbk_buf[NDB_BBK_BITS];
@@ -327,14 +360,10 @@ void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_
 		tp_sap_udata_ind(TPSAP_T_SB2, burst+SB_BLK2_OFFSET, SB_BLK2_BITS, priv);
 		break;	
 	case TETRA_TRAIN_SYNC_DMO:
-		//printf("\nTETRA_TRAIN_SYNC_DMO");
-		/* Split SB1, SB2 and Broadcast Block */
-		/* send three parts of the burst via TP-SAP into lower MAC */
+		/* Split SB1 and SB2 */
+		/* send two parts of the burst via TP-SAP into lower MAC */
 		tp_sap_udata_ind(DMAC_SYNC, burst+SB_BLK1_OFFSET, SB_BLK1_BITS, priv);
-		tp_sap_udata_ind(DMAC_SYNC_SB2, burst+252, 216, priv);
-	 	//printf("\n\n############################################\n");
-		//tp_sap_udata_ind(TPSAP_T_BBK, burst+SB_BBK_OFFSET, SB_BBK_BITS, priv);
-		//tp_sap_udata_ind(TPSAP_T_SB2, burst+SB_BLK2_OFFSET, SB_BLK2_BITS, priv);
+		tp_sap_udata_ind(DMAC_SYNC_SB2, burst+SB_BLK2_DMO_OFFSET, SB_BLK2_BITS, priv);
 		break;
 	case TETRA_TRAIN_NORM_2:
 		/* re-combine the broadcast block */
@@ -356,16 +385,14 @@ void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_
 		tp_sap_udata_ind(TPSAP_T_BBK, bbk_buf, NDB_BBK_BITS, priv);
 		tp_sap_udata_ind(TPSAP_T_SCH_F, ndbf_buf, 2*NDB_BLK_BITS, priv);
 		break;
-	case TETRA_TRAIN_PRE1:
-		/* re-combine the broadcast block */
-		//memcpy(bbk_buf, burst+NDB_BBK1_OFFSET, NDB_BBK1_BITS);
-		//memcpy(bbk_buf+NDB_BBK1_BITS, burst+NDB_BBK2_OFFSET, NDB_BBK2_BITS);
+	case TETRA_TRAIN_NORM_2_DMO:
+		/* TODO: send parts of the burst via TP-SAP into lower MAC */
+		break;
+	case TETRA_TRAIN_NORM_1_DMO:
 		/* re-combine the two parts */
 		memcpy(ndbf_buf, burst+14, 216);
 		memcpy(ndbf_buf+216, burst+252, 216);
 		/* send two parts of the burst via TP-SAP into lower MAC */
-		//tp_sap_udata_ind(TPSAP_T_BBK, bbk_buf, NDB_BBK_BITS, priv);
-
 		tp_sap_udata_ind(TPSAP_T_SCH_F_DMO, ndbf_buf, 432, priv);
 		break;
 	}
diff --git a/src/phy/tetra_burst.h b/src/phy/tetra_burst.h
index 60b54fb..b6ebf62 100644
--- a/src/phy/tetra_burst.h
+++ b/src/phy/tetra_burst.h
@@ -25,17 +25,20 @@ int build_norm_c_d_burst(uint8_t *buf, const uint8_t *bkn1, const uint8_t *bb, c
 
 enum tetra_train_seq {
 	TETRA_TRAIN_NORM_1,
+	TETRA_TRAIN_NORM_1_DMO,
 	TETRA_TRAIN_NORM_2,
+	TETRA_TRAIN_NORM_2_DMO,
 	TETRA_TRAIN_NORM_3,
 	TETRA_TRAIN_SYNC,
 	TETRA_TRAIN_SYNC_DMO,
 	TETRA_TRAIN_EXT,
-	TETRA_TRAIN_PRE1,
-	TETRA_TRAIN_PRE2,	
 };
 
 /* find a TETRA training sequence in the burst buffer indicated */
 int tetra_find_train_seq(const uint8_t *in, unsigned int end_of_in,
-			 uint32_t mask_of_train_seq, unsigned int *offset);
+			 uint32_t mask_of_train_seq, unsigned int *offset, unsigned int skip);
+
+/* checks if the DMO preamble is present and returns the proper burst type */
+int check_tmo_or_dmo(const uint8_t *in, enum tetra_train_seq type);
 
 #endif /* TETRA_BURST_H */
diff --git a/src/phy/tetra_burst_sync.c b/src/phy/tetra_burst_sync.c
index ff004de..1ab340e 100644
--- a/src/phy/tetra_burst_sync.c
+++ b/src/phy/tetra_burst_sync.c
@@ -31,11 +31,6 @@
 #include <tetra_tdma.h>
 #include <phy/tetra_burst_sync.h>
 
-/* jkw 9.4.3.3.3 DMO Radio Aspects preambe */
-static const uint8_t dmo_pre1_bits[12] = { 0,0,1,1,0,0,1,0,0,0,1,1 };
-static const uint8_t dmo_pre2_bits[12] = { 1,0,0,1,1,0,1,0,1,0,0,1 };
-static const uint8_t dmo_pre3_bits[12] = { 0,0,0,1,0,1,0,0,0,1,1,1 };
-
 struct tetra_phy_state t_phy_state;
 
 void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_seq type, void *priv);
@@ -79,11 +74,13 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 		DEBUGP("-> trying to find training sequence between bit %u and %u\n",
 			trs->bitbuf_start_bitnum, trs->bits_in_buf);
 		rc = tetra_find_train_seq(trs->bitbuf, trs->bits_in_buf,
-					  (1 << TETRA_TRAIN_SYNC), &train_seq_offs);
+					  (1 << TETRA_TRAIN_SYNC), &train_seq_offs, 0);
 		if (rc < 0)
 			return rc;
 		printf("found SYNC training sequence in bit #%u\n", train_seq_offs);
 		trs->state = RX_S_KNOW_FSTART;
+		/* for DMO image that the 34 bits guard at the beginning of a burst */
+		/* belongs to the previous burst */
 		trs->next_frame_start_bitnum = trs->bitbuf_start_bitnum + train_seq_offs + 296;
 #if 0
 		if (train_seq_offs < 214) {
@@ -99,7 +96,7 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 		if (trs->bitbuf_start_bitnum + trs->bits_in_buf < trs->next_frame_start_bitnum)
 			return 0;
 		else {
-			printf("\nRX_S_KNOW_FSTART");
+			DEBUGP("\nRX_S_KNOW_FSTART");
 			/* shift start of frame to start of bitbuf */
 			int offset = trs->next_frame_start_bitnum - trs->bitbuf_start_bitnum;
 			int bits_remaining = trs->bits_in_buf - offset;
@@ -116,7 +113,7 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 			/* not sufficient data for the full frame yet */
 			return len;
 		} else {
-			printf("\nRX_S_LOCKED");
+			DEBUGP("\nRX_S_LOCKED");
 			/* we have successfully received (at least) one frame */
 			tetra_tdma_time_add_tn(&t_phy_state.time, 1);
 			printf("\nBURST");
@@ -127,43 +124,45 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 			sprintf(tmpstr,"TETMON_begin FUNC:BURST RX:%i TETMON_end",tetra_hack_rxid);
 			sendto(tetra_hack_live_socket, (char *)&tmpstr, 128, 0, (struct sockaddr *)&tetra_hack_live_sockaddr, tetra_hack_socklen);
 
-
+			/* skip the first 200 bits, because normally the first training sequence can be found in bit 214 */
 			rc = tetra_find_train_seq(trs->bitbuf, trs->bits_in_buf,
 						  (1 << TETRA_TRAIN_NORM_1)|
 						  (1 << TETRA_TRAIN_NORM_2)|
-						  (1 << TETRA_TRAIN_SYNC), &train_seq_offs);
+						  (1 << TETRA_TRAIN_SYNC), &train_seq_offs, 200);
 			switch (rc) {
 			case TETRA_TRAIN_SYNC:
-				printf("\nTETRA_TRAIN_SYNC %u %u", train_seq_offs, rc );
-
-				if (memcmp(trs->bitbuf, dmo_pre3_bits, sizeof(dmo_pre1_bits))) {
-					printf("\nfound dmo_pre3_bits");
-					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_SYNC_DMO, trs->burst_cb_priv);
-				} else if (train_seq_offs == 214) {
-					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_SYNC_DMO, trs->burst_cb_priv);
+				if (train_seq_offs == 214) {
+					rc = check_tmo_or_dmo(trs->bitbuf, rc);
+					if (rc == TETRA_TRAIN_SYNC) {
+						printf("\nTETRA_TRAIN_SYNC_TMO");
+						tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_SYNC, trs->burst_cb_priv);
+					} else {
+						printf("\nTETRA_TRAIN_SYNC_DMO");
+						tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_SYNC_DMO, trs->burst_cb_priv);
+					}
 				} else {
 					fprintf(stderr, "#### SYNC burst at offset %u?!?\n", train_seq_offs);
 					trs->state = RX_S_UNLOCKED;
-				};
-				break;
-			case TETRA_TRAIN_NORM_1:
-				printf("\nTETRA_TRAIN_NORM_1 %u %u",train_seq_offs,rc );
-				if (train_seq_offs == 230) {
-					fprintf(stdout, "#### TETRA_TRAIN_NORM_1 in DMO BURST at offset %u\n", train_seq_offs);
-					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_PRE1, trs->burst_cb_priv);
 				}
 				break;
-			case TETRA_TRAIN_NORM_2:
-				printf("\nTETRA_TRAIN_NORM_2");
-				fprintf(stdout, "####TETRA_TRAIN_NORM_2 at offset %u?!?\n", train_seq_offs);
-				break;
-			case TETRA_TRAIN_NORM_3:
-				printf("\nTETRA_TRAIN_NORM_3");
-				if (train_seq_offs == 244)
+			case (TETRA_TRAIN_NORM_1 || TETRA_TRAIN_NORM_2):
+				if (train_seq_offs == 230) {
+					rc = check_tmo_or_dmo(trs->bitbuf, rc);
+					if (rc == TETRA_TRAIN_NORM_1_DMO || rc == TETRA_TRAIN_NORM_2_DMO) {
+						printf("\nTETRA_TRAIN_NORM_%u_DMO", rc);
+						tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv);
+						break;
+					} else {
+						fprintf(stderr, "#### TRAIN NORM %u DMO burst at offset %u?!?\n", rc, train_seq_offs);
+						trs->state = RX_S_UNLOCKED;
+					}
+				} else if (train_seq_offs == 244) {
+					printf("\nTETRA_TRAIN_NORM_%u", rc);
 					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv);
-				else
-					fprintf(stderr, "####2 SYNC burst at offset %u?!?\n", train_seq_offs);
-				tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv);
+				} else {
+					fprintf(stderr, "#### TRAIN NORM %u burst at offset %u?!?\n", rc, train_seq_offs);
+					trs->state = RX_S_UNLOCKED;
+				}
 				break;
 			default:
 				fprintf(stderr, "#### could not find successive burst training sequence\n");
-- 
2.7.4


>From ffc80d5280177359e7db21be578d94e6267c203e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jannik=20J=C3=BCrgens?= <jjuergens@seemoo.tu-darmstadt.de>
Date: Mon, 23 Jan 2017 11:49:45 +0100
Subject: [PATCH 3/4] Bugfix: adding a counter to avoid searching for a new
 sync burst when only three slots are empty

---
 src/phy/tetra_burst_sync.c | 32 ++++++++++++++++++++------------
 src/phy/tetra_burst_sync.h |  2 +-
 src/tetra-rx.c             |  3 ++-
 3 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/src/phy/tetra_burst_sync.c b/src/phy/tetra_burst_sync.c
index 1ab340e..71a311e 100644
--- a/src/phy/tetra_burst_sync.c
+++ b/src/phy/tetra_burst_sync.c
@@ -51,7 +51,7 @@ static void make_bitbuf_space(struct tetra_rx_state *trs, unsigned int len)
 }
 
 /* input a raw bitstream into the tetra burst synchronizaer */
-int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int len)
+int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int len, int *scounter)
 {
 	int rc;
 	unsigned int train_seq_offs;
@@ -116,9 +116,8 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 			DEBUGP("\nRX_S_LOCKED");
 			/* we have successfully received (at least) one frame */
 			tetra_tdma_time_add_tn(&t_phy_state.time, 1);
-			printf("\nBURST");
+			printf("\n\nBURST: ");
 			DEBUGP(": %s", osmo_ubit_dump(trs->bitbuf, TETRA_BITS_PER_TS));
-			printf("\n");
 
 			/* log the burst frames. useful for scanning etc --sq5bpf */
 			sprintf(tmpstr,"TETMON_begin FUNC:BURST RX:%i TETMON_end",tetra_hack_rxid);
@@ -132,24 +131,27 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 			switch (rc) {
 			case TETRA_TRAIN_SYNC:
 				if (train_seq_offs == 214) {
+					*scounter = 0;
 					rc = check_tmo_or_dmo(trs->bitbuf, rc);
 					if (rc == TETRA_TRAIN_SYNC) {
-						printf("\nTETRA_TRAIN_SYNC_TMO");
+						printf("TETRA_TRAIN_SYNC_TMO\n");
 						tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_SYNC, trs->burst_cb_priv);
 					} else {
-						printf("\nTETRA_TRAIN_SYNC_DMO");
+						printf("TETRA_TRAIN_SYNC_DMO\n");
 						tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, TETRA_TRAIN_SYNC_DMO, trs->burst_cb_priv);
 					}
 				} else {
-					fprintf(stderr, "#### SYNC burst at offset %u?!?\n", train_seq_offs);
+					fprintf(stderr, "\n#### SYNC burst at offset %u?!?\n", train_seq_offs);
 					trs->state = RX_S_UNLOCKED;
 				}
 				break;
-			case (TETRA_TRAIN_NORM_1 || TETRA_TRAIN_NORM_2):
+			case (TETRA_TRAIN_NORM_1): /* fall through */
+			case (TETRA_TRAIN_NORM_2):
 				if (train_seq_offs == 230) {
+					*scounter = 0;
 					rc = check_tmo_or_dmo(trs->bitbuf, rc);
 					if (rc == TETRA_TRAIN_NORM_1_DMO || rc == TETRA_TRAIN_NORM_2_DMO) {
-						printf("\nTETRA_TRAIN_NORM_%u_DMO", rc);
+						printf("TETRA_TRAIN_NORM_%u_DMO\n", rc);
 						tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv);
 						break;
 					} else {
@@ -157,16 +159,22 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int
 						trs->state = RX_S_UNLOCKED;
 					}
 				} else if (train_seq_offs == 244) {
-					printf("\nTETRA_TRAIN_NORM_%u", rc);
+					*scounter = 0;
+					printf("TETRA_TRAIN_NORM_%u\n", rc);
 					tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv);
 				} else {
-					fprintf(stderr, "#### TRAIN NORM %u burst at offset %u?!?\n", rc, train_seq_offs);
+					fprintf(stderr, "\n#### TRAIN NORM %u burst at offset %u?!?\n", rc, train_seq_offs);
 					trs->state = RX_S_UNLOCKED;
 				}
 				break;
 			default:
-				fprintf(stderr, "#### could not find successive burst training sequence\n");
-				trs->state = RX_S_UNLOCKED;
+				(*scounter)++;
+				if (*scounter >= 4) {
+					fprintf(stderr, "#### could not find successive burst training sequence\n");
+					trs->state = RX_S_UNLOCKED;
+				} else {
+					fprintf(stderr, "#### slot is empty, checking next %d slots before searching a new synchronization burst\n", 4-(*scounter));
+				}
 				break;
 			}
 
diff --git a/src/phy/tetra_burst_sync.h b/src/phy/tetra_burst_sync.h
index 7862461..11f6224 100644
--- a/src/phy/tetra_burst_sync.h
+++ b/src/phy/tetra_burst_sync.h
@@ -21,6 +21,6 @@ struct tetra_rx_state {
 
 
 /* input a raw bitstream into the tetra burst synchronizaer */
-int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int len);
+int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int len, int *scounter);
 
 #endif /* TETRA_BURST_SYNC_H */
diff --git a/src/tetra-rx.c b/src/tetra-rx.c
index 42045b5..2387b4d 100644
--- a/src/tetra-rx.c
+++ b/src/tetra-rx.c
@@ -117,6 +117,7 @@ int main(int argc, char **argv)
 	float filter_goal=0;
 	int ccounter=0;
 	char tmpstr2[64];
+	int scounter = 0;	//slot counter
 
 	tetra_hack_reassemble_fragments=0;
 	tetra_hack_all_sds_as_text=0;
@@ -260,7 +261,7 @@ int main(int argc, char **argv)
 				break;
 			}
 		}
-		tetra_burst_sync_in(trs, buf, len);
+		tetra_burst_sync_in(trs, buf, len, &scounter);
 
 		if (accept_float) {	
 			ccounter++;
-- 
2.7.4


>From 485c52642a153f9ea1f0f86f0a74d166e0433078 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jannik=20J=C3=BCrgens?= <jjuergens@seemoo.tu-darmstadt.de>
Date: Mon, 23 Jan 2017 12:00:45 +0100
Subject: [PATCH 4/4] clean code and improve dmo support in the lower mac layer

---
 src/conv_enc_test.c             |   5 +
 src/lower_mac/tetra_lower_mac.c | 343 +++++++++++++++++++++++-----------------
 src/phy/tetra_burst.c           |  19 ++-
 src/phy/tetra_burst.h           |   9 +-
 4 files changed, 222 insertions(+), 154 deletions(-)

diff --git a/src/conv_enc_test.c b/src/conv_enc_test.c
index 303ef31..e714ec6 100644
--- a/src/conv_enc_test.c
+++ b/src/conv_enc_test.c
@@ -49,6 +49,11 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 {
 }
 
+/* incoming DP-SAP UNITDATA.ind  from PHY into lower MAC */
+void dp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned int len, void *priv)
+{
+}
+
 static void decode_schf(const uint8_t *bits)
 {
 	uint8_t type4[1024];
diff --git a/src/lower_mac/tetra_lower_mac.c b/src/lower_mac/tetra_lower_mac.c
index f948dad..da8599e 100644
--- a/src/lower_mac/tetra_lower_mac.c
+++ b/src/lower_mac/tetra_lower_mac.c
@@ -73,23 +73,6 @@ static const struct tetra_blk_param tetra_blk_param[] = {
 		.interleave_a	= 101,
 		.have_crc16	= 1,
 	},
-/* DMO SYNC PDU */
-	[DMAC_SYNC] = {
-		.name		= "DMO_SB1",
-		.type345_bits 	= 120,
-		.type2_bits	= 80,
-		.type1_bits	= 60,
-		.interleave_a	= 11,
-		.have_crc16	= 1,
-	},
-	[DMAC_SYNC_SB2] = {
-		.name		= "SB2",
-		.type345_bits	= 216,
-		.type2_bits	= 144,
-		.type1_bits	= 124,
-		.interleave_a	= 101,
-		.have_crc16	= 1,
-	},
 	[TPSAP_T_NDB] = {
 		.name		= "NDB",
 		.type345_bits	= 216,
@@ -114,7 +97,29 @@ static const struct tetra_blk_param tetra_blk_param[] = {
 		.interleave_a	= 103,
 		.have_crc16	= 1,
 	},
-	[TPSAP_T_SCH_F_DMO] = {
+	[TPSAP_T_BBK] = {
+		.name		= "BBK",
+		.type345_bits	= 30,
+		.type2_bits	= 30,
+		.type1_bits	= 14,
+	},
+	[DPSAP_SCH_S] = {		//DMO Synchronization Burst Block 1
+		.name		= "SCH/S",
+		.type345_bits 	= 120,
+		.type2_bits	= 80,
+		.type1_bits	= 60,
+		.interleave_a	= 11,
+		.have_crc16	= 1,
+	},
+	[DPSAP_SCH_H] = {		//DMO Synchronization Burst Block 2
+		.name		= "SCH/H",
+		.type345_bits	= 216,
+		.type2_bits	= 144,
+		.type1_bits	= 124,
+		.interleave_a	= 101,
+		.have_crc16	= 1,
+	},
+	[DPSAP_SCH_F] = {		//DMO Normal Burst Block 1+2
 		.name		= "SCH/F",
 		.type345_bits	= 432,
 		.type2_bits	= 288,
@@ -122,11 +127,13 @@ static const struct tetra_blk_param tetra_blk_param[] = {
 		.interleave_a	= 103,
 		.have_crc16	= 1,
 	},
-	[TPSAP_T_BBK] = {
-		.name		= "BBK",
-		.type345_bits	= 30,
-		.type2_bits	= 30,
-		.type1_bits	= 14,
+	[DPSAP_STCH] = {		//DMO Normal Burst with Slot Flag
+		.name		= "STCH",
+		.type345_bits	= 216,
+		.type2_bits	= 144,
+		.type1_bits	= 124,
+		.interleave_a	= 101,
+		.have_crc16	= 1,
 	},
 };
 
@@ -169,26 +176,6 @@ struct tetra_tmvsap_prim *tmvsap_prim_alloc(uint16_t prim, uint8_t op)
 	return ttp;
 }
 
-void printBits(size_t const size, void const * const ptr)
-{
-    unsigned char *b = (unsigned char*) ptr;
-    unsigned char byte;
-    int i, j;
-
-    for (i=size-1;i>=0;i--)
-    {
-        for (j=7;j>=0;j--)
-        {
-            byte = b[i] & (1<<j);
-            byte >>= j;
-            printf("%u", byte);
-        }
-    }
-    puts("");
-}
-
-
-
 /* incoming TP-SAP UNITDATA.ind  from PHY into lower MAC */
 void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned int len, void *priv)
 {
@@ -197,8 +184,8 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 	uint8_t type3dp[512*4];
 	uint8_t type3[512];
 	uint8_t type2[512];
-    	uint8_t frag_offset;  // for variable fields in DMO DMAC SYNC
- 
+	uint8_t frag_offset; 	// for variable fields in DPSAP_SCH_H
+
 	const struct tetra_blk_param *tbp = &tetra_blk_param[type];
 	struct tetra_mac_state *tms = priv;
 	const char *time_str;
@@ -228,23 +215,12 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 
 	/* De-scramble, pay special attention to SB1 pre-defined scrambling */
 	memcpy(type4, bits, tbp->type345_bits);
-	if (type == TPSAP_T_SB1 || type == DMAC_SYNC  || type == DMAC_SYNC_SB2) {
-		printf("type: DMAC_SYNC\n");
-		tetra_scramb_bits(SCRAMB_INIT, type4, tbp->type345_bits);
-		tup->scrambling_code = SCRAMB_INIT;
-	} else if (type == TPSAP_T_SB2){	//jkw
-		printf("type: TPSAP_T_SB2\n");
+	if (type == TPSAP_T_SB1 || type == DPSAP_SCH_S  || type == DPSAP_SCH_H) {
 		tetra_scramb_bits(SCRAMB_INIT, type4, tbp->type345_bits);
 		tup->scrambling_code = SCRAMB_INIT;
-		printf("scrambling=0\n");
-	} else if (type == TPSAP_T_SCH_F_DMO ){  
-		printf("type: TPSAP_T_SCH_F_DMO %u \n",tcd->scramb_init);
-		tetra_scramb_bits(tcd->scramb_init, type4, tbp->type345_bits);
-		tup->scrambling_code = tcd->scramb_init;
 	} else {
 		tetra_scramb_bits(tcd->scramb_init, type4, tbp->type345_bits);
 		tup->scrambling_code = tcd->scramb_init;
-		printf("scrambling=1\n");
 	}
 
 	DEBUGP("%s %s type4: %s\n", tbp->name, time_str,
@@ -273,12 +249,8 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 			tup->crc_ok = 1;
 			printf("%s %s type1: %s\n", tbp->name, time_str,
 					osmo_ubit_dump(type2, tbp->type1_bits));
-		} else {
+		} else
 			printf("WRONG\n");
-			printf("%s %s type1: %s\n", tbp->name, time_str,
-				osmo_ubit_dump(type2, tbp->type1_bits));
-			//return;
-		}
 	} else if (type == TPSAP_T_BBK) {
 		/* FIXME: RM3014-decode */
 		tup->crc_ok = 1;
@@ -290,83 +262,6 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 	memcpy(msg->l1h, type2, tbp->type1_bits);
 
 	switch (type) {
-	case TPSAP_T_SCH_F_DMO:
-		printf(" Encoding: %s(%2u)", osmo_ubit_dump(type2+28, 7), bits_to_uint(type2+28, 7));
-		printf(" Message: ");
-		int i=0;
-		while (i+28+7 < tcd->textmessage_length) {
-			char message=bits_to_uint(type2+28+7+i, 8);
-			printf("%c",message);
-			i+=8;
-			if (i+28+7 > 29*8) 
-				break;
-		}
-		printf("\n");
-		break;		
-	case DMAC_SYNC:
-		printf(" System code: %s(%2u)", osmo_ubit_dump(type2, 4), bits_to_uint(type2, 4));
-		printf(" PDU type: %s(%u)", osmo_ubit_dump(type2+4, 2), bits_to_uint(type2+4, 2));
-		printf(" Comm type: %s(%u)", osmo_ubit_dump(type2+6, 2), bits_to_uint(type2+6, 2));
-		printf(" AB Channel: %s(%u)", osmo_ubit_dump(type2+10, 2), bits_to_uint(type2+10, 2));
-		printf(" Slot Num: %s(%u)", osmo_ubit_dump(type2+12, 2), bits_to_uint(type2+12, 2));
-		printf(" FN: %s(%u)", osmo_ubit_dump(type2+14, 5), bits_to_uint(type2+14, 5));
-		printf(" Encr: %s(%u)", osmo_ubit_dump(type2+19, 2), bits_to_uint(type2+19, 2));
-			printf("\n");
-			tup->lchan = TETRA_LC_BNCH;
-	break;
-			
-	case DMAC_SYNC_SB2:
-	 	frag_offset=0;
-	 	uint8_t scrambling[32];
-        
-	 	printf(" Fill bit: %s(%u)", osmo_ubit_dump(type2+10, 1), bits_to_uint(type2+10, 1));
-		printf(" Frag flag: %s(%u)", osmo_ubit_dump(type2+11, 1), bits_to_uint(type2+11, 1));
-
-		if(bits_to_uint(type2+11, 1)==1)  {
-			frag_offset=4;	 
-			printf(" Num of SCH/F: %s(%2u)", osmo_ubit_dump(type2+12, 4), bits_to_uint(type2+12, 4));
-		}
-		printf(" Frame countdown: %s(%2u)", osmo_ubit_dump(type2+12+frag_offset, 2), bits_to_uint(type2+12+frag_offset, 2));
-		printf("\n");
-
-		printf(" Dest Addr Type: %s(%2u)", osmo_ubit_dump(type2+14+frag_offset, 2), bits_to_uint(type2+14+frag_offset, 2));
-		printf(" Dest Addr: %s(%2u)", osmo_ubit_dump(type2+16+frag_offset, 24), bits_to_uint(type2+16+frag_offset, 24));
-		printf("\n");
-
-		printf(" Src Addr Type: %s(%2u)", osmo_ubit_dump(type2+40+frag_offset, 2), bits_to_uint(type2+40+frag_offset, 2));
-		printf(" Src addr: %s(%2u)", osmo_ubit_dump(type2+42+frag_offset, 24), bits_to_uint(type2+42+frag_offset, 24));
-		printf("\n");
-
-		printf(" MNI: %s(%2u)", osmo_ubit_dump(type2+66+frag_offset, 24), bits_to_uint(type2+66+frag_offset, 24));
-		printf(" Message Type: %s(%2u)", osmo_ubit_dump(type2+90+frag_offset, 5), bits_to_uint(type2+90+frag_offset, 5));
-		printf("\n");
-       		memcpy(scrambling,type2+66+frag_offset+18,6); // last 6 of mni
-		memcpy(scrambling+6,type2+42+frag_offset,24); // src addr
-		uint32_t scramb_init1 = bits_to_uint(scrambling,32);
-		scramb_init1 = scramb_init1 | 3 ; // last 2 bits have to be 1
-
-		printf("scrambling seq: %s %u\n",osmo_ubit_dump(scrambling,32), scramb_init1);
-		tcd->scramb_init =  scramb_init1;
-
-
-		printf("\nDM-SDS UDATA PDU:: SDS time remaining: %s(%2u)", osmo_ubit_dump(type2+90+5+frag_offset, 4), bits_to_uint(type2+90+5+frag_offset, 4));
-		printf(" DMSDS transaction type: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4, 1), bits_to_uint(type2+90+5+frag_offset+4, 1));
-		printf(" Priority level: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1, 2), bits_to_uint(type2+90+5+frag_offset+4+1, 2));
-			printf("\n");
-		printf(" FCS flag: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1+2, 1), bits_to_uint(type2+90+5+frag_offset+4+1+2, 1));
-		printf(" Additional addressing flag: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1+2+1, 1), bits_to_uint(type2+90+5+frag_offset+4+1+2+1, 1));
-		printf(" Short Data Type Identifier: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1+2+1+1, 4), bits_to_uint(type2+90+5+frag_offset+4+1+2+1+1,4));
-			printf("\n");
-		printf(" Length indicator: %s(%u)", osmo_ubit_dump(type2+90+5+frag_offset+4+1+2+1+1+4, 11), bits_to_uint(type2+90+5+frag_offset+4+1+2+1+1+4, 11));
-
-
-		tcd->textmessage_length =  bits_to_uint(type2+90+5+frag_offset+4+1+2+1+1+4, 11);
-
-
-		//printBits(32,tcd->scramb_init);
-		tup->lchan = TETRA_LC_BNCH;
-						
-		break;
 	case TPSAP_T_SB1:
 		printf("TMB-SAP SYNC CC %s(0x%02x) ", osmo_ubit_dump(type2+4, 6), bits_to_uint(type2+4, 6));
 		printf("TN %s(%u) ", osmo_ubit_dump(type2+10, 2), bits_to_uint(type2+10, 2));
@@ -374,7 +269,7 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 		printf("MN %s(%2u) ", osmo_ubit_dump(type2+17, 6), bits_to_uint(type2+17, 6));
 		printf("MCC %s(%u) ", osmo_ubit_dump(type2+31, 10), bits_to_uint(type2+31, 10));
 		printf("MNC %s(%u)\n", osmo_ubit_dump(type2+41, 14), bits_to_uint(type2+41, 14));
-		/* obtain information from SYNC PDU */
+		/* obtain information from SYNC PDU - 21.4.4.2 */
 		tcd->colour_code = bits_to_uint(type2+4, 6);
 		tcd->time.tn = bits_to_uint(type2+10, 2);
 		tcd->time.fn = bits_to_uint(type2+12, 5);
@@ -403,10 +298,6 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 	case TPSAP_T_SCH_F:
 		tup->lchan = TETRA_LC_SCH_F;
 
-		/*dmo*/
-		printf("%s %s type1: %s\n", tbp->name, time_str,
-			osmo_ubit_dump(type2, tbp->type1_bits));
-
 		/* send voice frames for further processing --sq5bpf */
 		if (tms->cur_burst.is_traffic)
 		{
@@ -439,6 +330,163 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 		}
 			/* sq5bpf: koniec */
 		break;
+	case DPSAP_SCH_F:
+		/* 396-3 9.2 */
+		if (bits_to_uint(type2, 2) == 0) {
+			printf("MAC PDU type: DMAC-DATA PDU %s(%2u) ", osmo_ubit_dump(type2, 2), bits_to_uint(type2, 2));
+		} else if(bits_to_uint(type2, 2) == 3) {
+			printf("MAC PDU type: DMAC-U-Signal PDU %s(%2u) ", osmo_ubit_dump(type2, 2), bits_to_uint(type2, 2));
+		} else if(bits_to_uint(type2, 2) == 1) {
+			if(bits_to_uint(type2+2, 1) == 0) {
+				printf("MAC PDU type: DMAC-FRAG PDU %s(%2u) ", osmo_ubit_dump(type2, 2), bits_to_uint(type2, 2));
+			} else {
+				printf("MAC PDU type: DMAC-END PDU %s(%2u) ",
+						osmo_ubit_dump(type2, 2), bits_to_uint(type2, 2));
+				printf("MAC PDU subtype: %s(%2u) ",
+						osmo_ubit_dump(type2 + 2, 1),
+						bits_to_uint(type2 + 2, 1));
+				/* 392-2 29.4.2.4 and 29.5.2.3 */
+				printf("Protocol identifier: %s(%2u) ",
+						osmo_ubit_dump(type2 + 4, 8),
+						bits_to_uint(type2 + 4, 8));
+				printf("Message type: %s(%2u) ", osmo_ubit_dump(type2 + 12, 4),
+						bits_to_uint(type2 + 12, 4));
+				if (bits_to_uint(type2 + 12, 4) == 0) {
+					/* SDS TRANSFER */
+					printf("Delivery report request: %s(%2u) ",
+							osmo_ubit_dump(type2 + 16, 2),
+							bits_to_uint(type2 + 16, 2));
+					printf("Encoding: %s(%2u) ", osmo_ubit_dump(type2 + 28, 7),
+							bits_to_uint(type2 + 28, 7));
+					printf("Message: ");
+					int i = 0;
+					while (i + 28 + 7 < tcd->textmessage_length) {
+						char message = bits_to_uint(type2 + 28 + 7 + i, 8);
+						printf("%c", message);
+						i += 8;
+						if (i + 28 + 7 > 29 * 8)
+							break;
+					}
+				}
+			}
+		}
+		printf("\n");
+		tup->lchan = TETRA_LC_SCH_F;	/* FIXME: Implement LC DMO Channel */
+		break;
+	case DPSAP_SCH_S:
+		/* 396-3 9.1.1 Table 21 */
+		printf(" System code: %s(%2u)", osmo_ubit_dump(type2, 4),
+				bits_to_uint(type2, 4));
+		printf(" PDU type: %s(%u)", osmo_ubit_dump(type2 + 4, 2),
+				bits_to_uint(type2 + 4, 2));
+		printf(" Comm type: %s(%u)", osmo_ubit_dump(type2 + 6, 2),
+				bits_to_uint(type2 + 6, 2));
+		printf(" AB Channel: %s(%u)", osmo_ubit_dump(type2 + 10, 2),
+				bits_to_uint(type2 + 10, 2));
+		printf(" Slot Num: %s(%u)", osmo_ubit_dump(type2 + 12, 2),
+				bits_to_uint(type2 + 12, 2));
+		printf(" FN: %s(%u)", osmo_ubit_dump(type2 + 14, 5),
+				bits_to_uint(type2 + 14, 5));
+		printf(" Encr: %s(%u)", osmo_ubit_dump(type2 + 19, 2),
+				bits_to_uint(type2 + 19, 2));
+		printf("\n");
+
+		/* obtain information from SYNC PDU - 21.4.4.2 */
+		tcd->time.tn = bits_to_uint(type2+12, 2);
+		tcd->time.fn = bits_to_uint(type2+14, 5);
+
+		/* update the PHY layer time */
+		memcpy(&t_phy_state.time, &tcd->time, sizeof(t_phy_state.time));
+
+		tup->lchan = TETRA_LC_BSCH;	/* FIXME: Implement LC DMO Channel */
+		break;
+	case DPSAP_SCH_H:
+		/* 396-3 9.1.1 Table 22 */
+		frag_offset = 0;
+		uint8_t scrambling[32];
+
+		printf(" Fill bit: %s(%u)", osmo_ubit_dump(type2 + 10, 1),
+				bits_to_uint(type2 + 10, 1));
+		printf(" Frag flag: %s(%u)", osmo_ubit_dump(type2 + 11, 1),
+				bits_to_uint(type2 + 11, 1));
+
+		if (bits_to_uint(type2 + 11, 1) == 1) {
+			frag_offset = 4;
+			printf(" Num of SCH/F: %s(%2u)", osmo_ubit_dump(type2 + 12, 4),
+					bits_to_uint(type2 + 12, 4));
+		}
+		printf(" Frame countdown: %s(%2u)",
+				osmo_ubit_dump(type2 + 12 + frag_offset, 2),
+				bits_to_uint(type2 + 12 + frag_offset, 2));
+		printf("\n");
+
+		printf(" Dest Addr Type: %s(%2u)",
+				osmo_ubit_dump(type2 + 14 + frag_offset, 2),
+				bits_to_uint(type2 + 14 + frag_offset, 2));
+		printf(" Dest Addr: %s(%2u)",
+				osmo_ubit_dump(type2 + 16 + frag_offset, 24),
+				bits_to_uint(type2 + 16 + frag_offset, 24));
+		printf("\n");
+
+		printf(" Src Addr Type: %s(%2u)",
+				osmo_ubit_dump(type2 + 40 + frag_offset, 2),
+				bits_to_uint(type2 + 40 + frag_offset, 2));
+		printf(" Src addr: %s(%2u)",
+				osmo_ubit_dump(type2 + 42 + frag_offset, 24),
+				bits_to_uint(type2 + 42 + frag_offset, 24));
+		printf("\n");
+
+		printf(" MNI: %s(%2u)", osmo_ubit_dump(type2 + 66 + frag_offset, 24),
+				bits_to_uint(type2 + 66 + frag_offset, 24));
+		printf(" Message Type: %s(%2u)",
+				osmo_ubit_dump(type2 + 90 + frag_offset, 5),
+				bits_to_uint(type2 + 90 + frag_offset, 5));
+		printf("\n");
+		memcpy(scrambling, type2 + 66 + frag_offset + 18, 6); // last 6 of mni
+		memcpy(scrambling + 6, type2 + 42 + frag_offset, 24); // src addr
+		uint32_t scramb_init1 = bits_to_uint(scrambling, 32);
+		scramb_init1 = scramb_init1 | 3; // last 2 bits have to be 1
+
+		printf("scrambling seq: %s %u\n", osmo_ubit_dump(scrambling, 32),
+				scramb_init1);
+		tcd->scramb_init = scramb_init1;
+
+		printf("\nDM-SDS UDATA PDU:: SDS time remaining: %s(%2u)",
+				osmo_ubit_dump(type2 + 90 + 5 + frag_offset, 4),
+				bits_to_uint(type2 + 90 + 5 + frag_offset, 4));
+		printf(" DMSDS transaction type: %s(%u)",
+				osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 4, 1),
+				bits_to_uint(type2 + 90 + 5 + frag_offset + 4, 1));
+		printf(" Priority level: %s(%u)",
+				osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 4 + 1, 2),
+				bits_to_uint(type2 + 90 + 5 + frag_offset + 4 + 1, 2));
+		printf("\n");
+		printf(" FCS flag: %s(%u)",
+				osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 4 + 1 + 2, 1),
+				bits_to_uint(type2 + 90 + 5 + frag_offset + 4 + 1 + 2, 1));
+		printf(" Additional addressing flag: %s(%u)",
+				osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 4 + 1 + 2 + 1, 1),
+				bits_to_uint(type2 + 90 + 5 + frag_offset + 4 + 1 + 2 + 1, 1));
+		printf(" Short Data Type Identifier: %s(%u)",
+				osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 4 + 1 + 2 + 1 + 1,
+						4),
+				bits_to_uint(type2 + 90 + 5 + frag_offset + 4 + 1 + 2 + 1 + 1,
+						4));
+		printf("\n");
+		printf(" Length indicator: %s(%u)",
+				osmo_ubit_dump(
+						type2 + 90 + 5 + frag_offset + 4 + 1 + 2 + 1 + 1 + 4,
+						11),
+				bits_to_uint(
+						type2 + 90 + 5 + frag_offset + 4 + 1 + 2 + 1 + 1 + 4,
+						11));
+
+		tcd->textmessage_length = bits_to_uint(
+				type2 + 90 + 5 + frag_offset + 4 + 1 + 2 + 1 + 1 + 4, 11);
+
+		//printBits(32,tcd->scramb_init);
+		tup->lchan = TETRA_LC_SCH_HD;	/* FIXME: Implement LC DMO Channel */
+		break;
 	default:
 		/* FIXME: do something */
 		break;
@@ -449,4 +497,9 @@ void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned
 	upper_mac_prim_recv(&ttp->oph, tms);
 }
 
-
+/* incoming DP-SAP UNITDATA.ind  from PHY into lower MAC */
+void dp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned int len, void *priv)
+{
+	/* call TMO Physical Layer SAP because the code would be almost identical */
+	tp_sap_udata_ind(type, bits, len, priv);
+}
diff --git a/src/phy/tetra_burst.c b/src/phy/tetra_burst.c
index f41b3c8..8654b4c 100644
--- a/src/phy/tetra_burst.c
+++ b/src/phy/tetra_burst.c
@@ -47,6 +47,10 @@
 #define NDB_BLK_BITS	(108*DQPSK4_BITS_PER_SYM)
 #define NDB_BBK_BITS	SB_BBK_BITS
 
+#define DNB_BLK_BITS 	(108*DQPSK4_BITS_PER_SYM)
+
+#define DNB_BLK1_OFFSET ((6+1)*DQPSK4_BITS_PER_SYM)
+#define DNB_BLK2_OFFSET ((6+1+108+11)*DQPSK4_BITS_PER_SYM)
 
 /* 9.4.4.3.1 Frequency Correction Field */
 static const uint8_t f_bits[80] = {
@@ -298,6 +302,7 @@ int tetra_find_train_seq(const uint8_t *in, unsigned int end_of_in,
 			*offset = (cur - in);
 			return TETRA_TRAIN_NORM_2;
 		}
+#if 0	/* not used */
 		if (mask_of_train_seq & (1 << TETRA_TRAIN_NORM_3) &&
 		    remain_len >= sizeof(q_bits) &&
 		    !memcmp(cur, q_bits, sizeof(q_bits))) {
@@ -310,6 +315,7 @@ int tetra_find_train_seq(const uint8_t *in, unsigned int end_of_in,
 			*offset = (cur - in);
 			return TETRA_TRAIN_EXT;
 		}
+#endif
 	}
 	return -1;
 }
@@ -362,8 +368,8 @@ void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_
 	case TETRA_TRAIN_SYNC_DMO:
 		/* Split SB1 and SB2 */
 		/* send two parts of the burst via TP-SAP into lower MAC */
-		tp_sap_udata_ind(DMAC_SYNC, burst+SB_BLK1_OFFSET, SB_BLK1_BITS, priv);
-		tp_sap_udata_ind(DMAC_SYNC_SB2, burst+SB_BLK2_DMO_OFFSET, SB_BLK2_BITS, priv);
+		dp_sap_udata_ind(DPSAP_SCH_S, burst+SB_BLK1_OFFSET, SB_BLK1_BITS, priv);
+		dp_sap_udata_ind(DPSAP_SCH_H, burst+SB_BLK2_DMO_OFFSET, SB_BLK2_BITS, priv);
 		break;
 	case TETRA_TRAIN_NORM_2:
 		/* re-combine the broadcast block */
@@ -387,13 +393,14 @@ void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_
 		break;
 	case TETRA_TRAIN_NORM_2_DMO:
 		/* TODO: send parts of the burst via TP-SAP into lower MAC */
+		fprintf(stderr, "#### TETRA_TRAIN_NORM_2_DMO bursts are not implemented\n");
 		break;
 	case TETRA_TRAIN_NORM_1_DMO:
 		/* re-combine the two parts */
-		memcpy(ndbf_buf, burst+14, 216);
-		memcpy(ndbf_buf+216, burst+252, 216);
-		/* send two parts of the burst via TP-SAP into lower MAC */
-		tp_sap_udata_ind(TPSAP_T_SCH_F_DMO, ndbf_buf, 432, priv);
+		memcpy(ndbf_buf, burst+DNB_BLK1_OFFSET, DNB_BLK_BITS);
+		memcpy(ndbf_buf+DNB_BLK_BITS, burst+DNB_BLK2_OFFSET, DNB_BLK_BITS);
+		/* send part of the burst via TP-SAP into lower MAC */
+		dp_sap_udata_ind(DPSAP_SCH_F, ndbf_buf, DNB_BLK_BITS*2, priv);
 		break;
 	}
 }
diff --git a/src/phy/tetra_burst.h b/src/phy/tetra_burst.h
index b6ebf62..4b75fb3 100644
--- a/src/phy/tetra_burst.h
+++ b/src/phy/tetra_burst.h
@@ -10,13 +10,16 @@ enum tp_sap_data_type {
 	TPSAP_T_BBK,
 	TPSAP_T_SCH_HU,
 	TPSAP_T_SCH_F,
-	DMAC_SYNC,
-	DMAC_SYNC_SB2,
-	TPSAP_T_SCH_F_DMO,
+	DPSAP_SCH_S,
+	DPSAP_SCH_H,
+	DPSAP_SCH_F,
+	DPSAP_STCH,
 };
 
 extern void tp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned int len, void *priv);
 
+extern void dp_sap_udata_ind(enum tp_sap_data_type type, const uint8_t *bits, unsigned int len, void *priv);
+
 /* 9.4.4.2.6 Synchronization continuous downlink burst */
 int build_sync_c_d_burst(uint8_t *buf, const uint8_t *sb, const uint8_t *bb, const uint8_t *bkn);
 
-- 
2.7.4

