diff --git a/AUTHORS b/AUTHORS index a0c987b..7702664 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,5 @@ Harald Welte Sylvain Munaut Holger Hans Peter Freyther +Jan-Pascal Kwiotek +Jannik Jürgens 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 53fe73a..040de7b 100644 --- a/src/lower_mac/tetra_lower_mac.c +++ b/src/lower_mac/tetra_lower_mac.c @@ -103,6 +103,38 @@ static const struct tetra_blk_param tetra_blk_param[] = { .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, + .type1_bits = 268, + .interleave_a = 103, + .have_crc16 = 1, + }, + [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, + }, }; struct tetra_cell_data { @@ -112,6 +144,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; @@ -151,6 +184,7 @@ 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 DPSAP_SCH_H const struct tetra_blk_param *tbp = &tetra_blk_param[type]; struct tetra_mac_state *tms = priv; @@ -181,7 +215,7 @@ 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 == DPSAP_SCH_S || type == DPSAP_SCH_H) { tetra_scramb_bits(SCRAMB_INIT, type4, tbp->type345_bits); tup->scrambling_code = SCRAMB_INIT; } else { @@ -235,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); @@ -296,6 +330,295 @@ 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_DMO_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_DMO_SCH_S; /* 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"); + uint8_t mess_type = bits_to_uint(type2 + 90 + frag_offset, 5); + + 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("\n"); + switch (mess_type) { + case 8: + printf("DM-SETUP PDU:: Timing flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset, 1)); + printf(" LCH in frame 3 flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 1, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 1, 1)); + printf(" Pre-emption flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 2, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 2, 1)); + printf("\n"); + printf("Power class: %s(%2u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 3, 3), + bits_to_uint(type2 + 90 + 5 + frag_offset + 3, 3)); + printf(" Power control flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 6, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 6, 1)); + printf(" Dual watch synchronization flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 9, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 9, 1)); + printf("\n"); + printf("Two-frequency call flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 10, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 10, 1)); + printf(" Circuit mode type: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 11, 4), + bits_to_uint(type2 + 90 + 5 + frag_offset + 11, 4)); + printf(" Priority level: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 19, 2), + bits_to_uint(type2 + 90 + 5 + frag_offset + 19, 2)); + printf("\n"); + printf("DM-SDU elements:: End-to-end encryption flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 21, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 21, 1)); + printf(" Call type flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 21 + 1, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 21 +1, 1)); + printf(" External source flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 21 + 2, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 21 + 2, 1)); + break; + case 9: + printf("DM-SETUP PRES PDU:: Power class: %s(%2u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 3, 3), + bits_to_uint(type2 + 90 + 5 + frag_offset + 3, 3)); + printf(" Power control flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 6, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 6, 1)); + printf(" Dual watch synchronization flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 9, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 9, 1)); + printf("\n"); + printf("Two-frequency call flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 10, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 10, 1)); + printf(" Circuit mode type: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 11, 4), + bits_to_uint(type2 + 90 + 5 + frag_offset + 11, 4)); + printf(" Priority level: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 19, 2), + bits_to_uint(type2 + 90 + 5 + frag_offset + 19, 2)); + printf("\n"); + printf("DM-SDU elements:: Ent-to-end encryption flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 21, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 21, 1)); + printf(" Call type flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 22, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 22, 1)); + printf(" External source flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 23, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 23, 1)); + break; + case 10: + printf("DM-CONNECT PDU:: Circuit mode type: %s(%2u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset, 4), + bits_to_uint(type2 + 90 + 5 + frag_offset, 4)); + break; + case 12: + printf("DM-CONNECT ACK PDU:: Timing flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset, 1)); + printf(" LCH in frame 3 flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 1, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 1, 1)); + printf(" Pre-emption flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 2, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 2, 1)); + printf("\n"); + printf("Power class: %s(%2u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 3, 3), + bits_to_uint(type2 + 90 + 5 + frag_offset + 3, 3)); + printf(" Power control flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 6, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 6, 1)); + printf(" Dual watch synchronization flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 9, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 9, 1)); + printf("\n"); + printf("Two-frequency call flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 10, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 10, 1)); + printf(" Circuit mode type: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 11, 4), + bits_to_uint(type2 + 90 + 5 + frag_offset + 11, 4)); + printf(" Priority level: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 19, 2), + bits_to_uint(type2 + 90 + 5 + frag_offset + 19, 2)); + printf("\n"); + printf("DM-SDU elements:: End-to-end encryption flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 21, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 21, 1)); + printf(" Call type flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 21 + 1, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 21 +1, 1)); + printf(" External source flag: %s(%u)", + osmo_ubit_dump(type2 + 90 + 5 + frag_offset + 21 + 2, 1), + bits_to_uint(type2 + 90 + 5 + frag_offset + 21 + 2, 1)); + break; + case 22: + printf("DM-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); + break; + default: + printf("Message type is not implemented"); + break; + } + printf("\n"); + //printBits(32,tcd->scramb_init); + tup->lchan = TETRA_LC_DMO_SCH_H; /* FIXME: Implement LC DMO Channel */ + break; default: /* FIXME: do something */ break; @@ -306,4 +629,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 is almost identical */ + tp_sap_udata_ind(type, bits, len, priv); +} 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 #include #include @@ -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..534563a 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..8654b4c 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) @@ -46,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] = { @@ -55,7 +60,12 @@ 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.4.3.2 Normal Training Sequence */ +/* 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 (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 }; @@ -66,7 +76,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 */ @@ -267,11 +277,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) && @@ -292,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))) { @@ -304,10 +315,43 @@ int tetra_find_train_seq(const uint8_t *in, unsigned int end_of_in, *offset = (cur - in); return TETRA_TRAIN_EXT; } +#endif } 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]; @@ -320,6 +364,12 @@ 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: + /* Split SB1 and SB2 */ + /* send two parts of the burst via TP-SAP into lower MAC */ + 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 */ @@ -341,5 +391,16 @@ 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_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+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_sync.c b/src/phy/tetra_burst_sync.c index e363c74..5acd0ba 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; @@ -74,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) { @@ -112,7 +114,7 @@ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int } else { /* 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"); @@ -120,31 +122,58 @@ 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: - if (train_seq_offs == 214) - 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); + if (train_seq_offs == 214) { + *scounter = 0; + rc = check_tmo_or_dmo(trs->bitbuf, rc); + if (rc == TETRA_TRAIN_SYNC) { + 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("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, "\n#### SYNC burst at offset %u?!?\n", train_seq_offs); trs->state = RX_S_UNLOCKED; } break; - case TETRA_TRAIN_NORM_1: - case TETRA_TRAIN_NORM_2: - case TETRA_TRAIN_NORM_3: - if (train_seq_offs == 244) + 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("TETRA_TRAIN_NORM_%u_DMO\n", 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) { + *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, "#### SYNC burst at offset %u?!?\n", train_seq_offs); + } else { + 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++; diff --git a/src/tetra_common.h b/src/tetra_common.h index 98327ba..2ba110b 100644 --- a/src/tetra_common.h +++ b/src/tetra_common.h @@ -36,6 +36,10 @@ enum tetra_log_chan { TETRA_LC_BSCH, TETRA_LC_BNCH, + TETRA_LC_DMO_SCH_S, + TETRA_LC_DMO_SCH_H, + TETRA_LC_DMO_SCH_F, + /* FIXME: QAM */ }; uint32_t bits_to_uint(const uint8_t *bits, unsigned int len); diff --git a/src/tetra_gsmtap.c b/src/tetra_gsmtap.c index f575c20..df6b8fd 100644 --- a/src/tetra_gsmtap.c +++ b/src/tetra_gsmtap.c @@ -25,6 +25,9 @@ static const uint8_t lchan2gsmtap[] = { [TETRA_LC_TCH] = GSMTAP_TETRA_TCH_F, [TETRA_LC_BSCH] = GSMTAP_TETRA_BSCH, [TETRA_LC_BNCH] = GSMTAP_TETRA_BNCH, + [TETRA_LC_DMO_SCH_S] = GSMTAP_TETRA_DMO_SCH_S, + [TETRA_LC_DMO_SCH_H] = GSMTAP_TETRA_DMO_SCH_H, + [TETRA_LC_DMO_SCH_F] = GSMTAP_TETRA_DMO_SCH_F, };