diff --git a/include/dsd.h b/include/dsd.h index 31ca97c..8609d06 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -478,6 +478,9 @@ typedef struct unsigned int nxdn_cipher_type; unsigned int nxdn_key; char nxdn_call_type[1024]; + char dmr_callsign[4][99]; //plenty of room in case of overflow; + char dmr_lrrp[6][9999]; + //borrow from LEH NxdnSacchRawPart_t NxdnSacchRawPart[4]; NxdnFacch1RawPart_t NxdnFacch1RawPart[2]; @@ -507,6 +510,10 @@ typedef struct TimeSlotVoiceSuperFrame_t TS1SuperFrame; TimeSlotVoiceSuperFrame_t TS2SuperFrame; + char dmr_branding[25]; + uint8_t dmr_12_rate_sf[36]; //going three frames deep + uint8_t dmr_34_rate_sf[54]; //going three frames deep + //LEH dPMR stuff dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame; @@ -776,7 +783,17 @@ uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint8_t ComputeCrc5Bit(uint8_t * DMRData); uint8_t * DmrAlgIdToStr(uint8_t AlgID); uint8_t * DmrAlgPrivacyModeToStr(uint32_t PrivacyMode); + void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +void Process1Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98], uint8_t syncdata[48], uint8_t SlotType[20]); +void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); + void Hamming_7_4_init(); void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits); @@ -827,6 +844,18 @@ void open_rtlsdr_stream(dsd_opts *opts); void cleanup_rtlsdr_stream(); void get_rtlsdr_sample(int16_t *sample); void rtlsdr_sighandler(); + +//TRELLIS +void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload); +unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits); +//unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* state, unsigned char* tribits); +bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload); +void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits); +void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points); +void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits); +void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits); +bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload); + #ifdef __cplusplus } #endif diff --git a/include/trellis.h b/include/trellis.h new file mode 100644 index 0000000..5784d96 --- /dev/null +++ b/include/trellis.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 by Jonathan Naylor, G4KLX + * + * Modifications of original code to work with OP25 + * Copyright (C) 2019 by Graham J. Norbury + * + * This program 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; version 2 of the License. + * + * This program 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. + */ + +#ifndef DMRTrellis_H +#define DMRTrellis_H + +class CDMRTrellis { +public: + CDMRTrellis(); + ~CDMRTrellis(); + + bool decode(const unsigned char* data, unsigned char* payload); + +private: + void deinterleave(const unsigned char* in, signed char* dibits) const; + void dibitsToPoints(const signed char* dibits, unsigned char* points) const; + void pointsToDibits(const unsigned char* points, signed char* dibits) const; + void bitsToTribits(const unsigned char* payload, unsigned char* tribits) const; + void tribitsToBits(const unsigned char* tribits, unsigned char* payload) const; + bool fixCode(unsigned char* points, unsigned int failPos, unsigned char* payload) const; + unsigned int checkCode(const unsigned char* points, unsigned char* tribits) const; +}; + +#endif diff --git a/src/dmr_data.c b/src/dmr_data.c index f2301f9..44ef3ed 100644 --- a/src/dmr_data.c +++ b/src/dmr_data.c @@ -96,7 +96,8 @@ processDMRdata (dsd_opts * opts, dsd_state * state) cachbits[24] = 0; fprintf(stderr, "%s ", cachbits); #endif - + //trellis bits + unsigned char trellisdibits[98]; // Current slot - First half - Data Payload - 1st part for (i = 0; i < 49; i++) { @@ -106,6 +107,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + trellisdibits[i] = dibit; info[2*i] = (1 & (dibit >> 1)); // bit 1 info[(2*i)+1] = (1 & dibit); // bit 0 } @@ -311,6 +313,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) } // Current slot - First half - Data Payload - 1st part + //trellis for (i = 0; i < 49; i++) { dibit = getDibit(opts, state); @@ -318,6 +321,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + trellisdibits[i+49] = dibit; info[(2*i) + 98] = (1 & (dibit >> 1)); // bit 1 info[(2*i) + 99] = (1 & dibit); // bit 0 } @@ -371,36 +375,42 @@ processDMRdata (dsd_opts * opts, dsd_state * state) /* Burst = CSBK */ case 0b0011: { + ProcessCSBK(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } /* Burst = MBC Header */ case 0b0100: { + //ProcessMBChData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } /* Burst = MBC */ case 0b0101: { + //ProcessMBCData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } /* Burst = DATA Header */ case 0b0110: { + ProcessDataData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } /* Burst = RATE 1/2 DATA */ case 0b0111: { + Process12Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } /* Burst = RATE 3/4 DATA */ case 0b1000: { + //Process34Data(opts, state, trellisdibits, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } @@ -413,6 +423,14 @@ processDMRdata (dsd_opts * opts, dsd_state * state) /* Burst = Rate 1 DATA */ case 0b1010: { + //Process1Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); + break; + } + + /* Burst = WTF 1101 Type DATA */ + case 0b1101: + { + //ProcessWTFData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } @@ -420,6 +438,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) default: { /* Nothing to do */ + //ProcessWTFData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } } /* End switch(burst) */ diff --git a/src/dmr_encryption.c b/src/dmr_encryption.c index 5355286..a7fb7c1 100644 --- a/src/dmr_encryption.c +++ b/src/dmr_encryption.c @@ -44,17 +44,20 @@ void ProcessDMREncryption (dsd_opts * opts, dsd_state * state) TSVoiceSupFrame = &state->TS2SuperFrame; } - TSVoiceSupFrameL = &state->TS1SuperFrame; - TSVoiceSupFrameR = &state->TS2SuperFrame; + //TSVoiceSupFrameL = &state->TS1SuperFrame; + //TSVoiceSupFrameR = &state->TS2SuperFrame; // // // for(Frame = 0; Frame < 6; Frame++) { /* 1 DMR frame contains 3 AMBE voice samples */ + //fprintf (stderr, "\n 1AMBE "); for(i = 0; i < 3; i++) { + errs = (int*)&(TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); + //fprintf (stderr, "[%02X] ", TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); errs2 = (int*)&(TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); state->errs = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement state->errs2 = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement @@ -63,23 +66,45 @@ void ProcessDMREncryption (dsd_opts * opts, dsd_state * state) TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - //errs = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); - //errs2 = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); - //state->errs = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement - //state->errs2 = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement + /* + if (state->currentslot == 0) + { + errs = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); + errs2 = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); + state->errs = TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement + state->errs2 = TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement - //errsR = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); - //errs2R = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); - //state->errs = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement - //state->errs2 = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str, + TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], + state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + state->debug_audio_errors += *errs2; + //state->debug_audio_errors += *errs2R; + + processAudio(opts, state); + playSynthesizedVoice (opts, state); + } + if (state->currentslot == 1) + { + errsR = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); + errs2R = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); + state->errs = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement + state->errs2 = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement //state->audio_out_temp_bufR = state->audio_out_temp_buf; - //mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str, - // TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], - // state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - //mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, errsR, errs2R, state->err_strR, - // TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], - // state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errsR, errs2R, state->err_strR, + TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], + state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + state->debug_audio_errors += *errs2R; + processAudio(opts, state); + playSynthesizedVoice (opts, state); + } + + mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, errsR, errs2R, state->err_strR, + TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], + state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + */ if (opts->mbe_out_f != NULL) { @@ -94,6 +119,7 @@ void ProcessDMREncryption (dsd_opts * opts, dsd_state * state) //state->debug_audio_errors += *errs2R; processAudio(opts, state); + //playSynthesizedVoice (opts, state); if (opts->wav_out_f != NULL) { diff --git a/src/dmr_sync.c b/src/dmr_sync.c index 570581e..479b140 100644 --- a/src/dmr_sync.c +++ b/src/dmr_sync.c @@ -21,6 +21,1278 @@ //#define PRINT_VOICE_LC_HEADER_BYTES //#define PRINT_TERMINAISON_LC_BYTES //#define PRINT_VOICE_BURST_BYTES + +void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + //NEED TRELLIS DECODER HERE + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[144]; + uint8_t DmrDataByte[18]; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + //BPTCDeInterleaveDMRData(info, DeInteleavedData); + //info is the dibits; is output DeInterleavedData? + //data is dibits I think, so sub info for data? only wants 98U dibits though. + //returns 'payload' which is 144 bit array, so DmrDataBit maybe? + //CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) + unsigned char tdibits_reverse[98]; + unsigned char tdibits_inverted[98]; + if (opts->payload == 1) + { + fprintf (stderr, "\n Raw Trellis Dibits\n "); + for (i = 0; i < 98; i++) + { + fprintf (stderr, "[%X]", tdibits[i]); + //tdibits_reverse[97-i] = tdibits[i]; + tdibits_reverse[97-i] = ((tdibits[i] & 1)<<1) | ((tdibits[i] & 2)>>1); + tdibits_inverted[i] = tdibits[i] ^ 2; + } + } + + unsigned char TrellisReturn[18]; + CDMRTrellisDecode(tdibits, TrellisReturn); //figure out how this works!! + if (opts->payload == 1) + { + fprintf (stderr, "\nFull 3/4 Rate Trellis Payload (reversed order)\n "); + for (i = 0; i < 18; i++) + { + fprintf (stderr, "[%02X]", TrellisReturn[17-i]); + } + } + /* Extract the BPTC 196,96 DMR data */ + //IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); + // + //CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points) ?? + // + /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ + //BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); + /* + for(i = 0, j = 0; i < 18; i++, j+=8) + { + DmrDataBit[j + 0] = (TrellisReturn[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (TrellisReturn[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (TrellisReturn[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (TrellisReturn[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (TrellisReturn[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (TrellisReturn[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (TrellisReturn[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (TrellisReturn[i] >> 0) & 0x01; + } + */ + //the reverse card + for(i = 0, j = 0; i < 18; i++, j+=8) + { + DmrDataBit[j + 0] = (TrellisReturn[17-i] >> 0) & 0x01; + DmrDataBit[j + 1] = (TrellisReturn[17-i] >> 1) & 0x01; + DmrDataBit[j + 2] = (TrellisReturn[17-i] >> 2) & 0x01; + DmrDataBit[j + 3] = (TrellisReturn[17-i] >> 3) & 0x01; + DmrDataBit[j + 4] = (TrellisReturn[17-i] >> 4) & 0x01; + DmrDataBit[j + 5] = (TrellisReturn[17-i] >> 5) & 0x01; + DmrDataBit[j + 6] = (TrellisReturn[17-i] >> 6) & 0x01; + DmrDataBit[j + 7] = (TrellisReturn[17-i] >> 7) & 0x01; + } + /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 18; i++) + { + state->dmr_34_rate_sf[i] = state->dmr_34_rate_sf[i+18]; //shift middle to left 12 to load up new round + state->dmr_34_rate_sf[i+18] = state->dmr_34_rate_sf[i+36]; //shift far right to middle 12, going three frames deep; + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + //DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + //state->dmr_34_rate_sf[i+36] = DmrDataByte[i]; //copy byte to right hand side of shift frame + state->dmr_34_rate_sf[i+36] = TrellisReturn[i]; + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + //for(i = 0; i < 24; i++) + for(i = 0; i < 16; i++) + { + //CRCExtracted = CRCExtracted << 1; + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + } + + //Look into whether or not we need to run these CRC checks for this header information + //and see if its applied the same or differently + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + //CRCExtracted = CRCExtracted ^ 0x6969; + + /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + + // + /* Convert corrected 12 bytes into 96 bits */ + + + + //Headers and Addresses + if ( (state->dmr_34_rate_sf[0] & 0x3F) == 0x05) //0x3F?? or == 0x05 + { + fprintf (stderr, "\n IP4 Header"); + } + + if ( (state->dmr_34_rate_sf[0] & 0x3F) == 0x0C) + { + fprintf (stderr, "\n Source: "); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_34_rate_sf[0] & 0x3F), state->dmr_34_rate_sf[1], state->dmr_34_rate_sf[2], state->dmr_34_rate_sf[3]); //strip first two bits off 1st byte + fprintf (stderr, " [%08d]", (state->dmr_34_rate_sf[1] <<16 ) + (state->dmr_34_rate_sf[2] << 8) + state->dmr_34_rate_sf[3] ); + fprintf (stderr, " - Port %05d", (state->dmr_34_rate_sf[8] << 8) + state->dmr_34_rate_sf[9]); + fprintf (stderr, "\n Destination:"); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_34_rate_sf[4] & 0x3F), state->dmr_34_rate_sf[5], state->dmr_34_rate_sf[6], state->dmr_34_rate_sf[7]); //strip first two bits off 4th byte?? + fprintf (stderr, " [%08d]", (state->dmr_34_rate_sf[5] <<16 ) + (state->dmr_34_rate_sf[6] << 8) + state->dmr_34_rate_sf[7] ); + fprintf (stderr, " - Port %05d", (state->dmr_34_rate_sf[10] << 8) + state->dmr_34_rate_sf[11]); + } + //LRRP + if (state->dmr_34_rate_sf[0] == 0x0 && state->dmr_34_rate_sf[4] == 0x0D) //Start LRRP now + { + fprintf (stderr, "\n Data Blocks [%d]", state->dmr_34_rate_sf[5]); + for (short i = 6; i <= 36; i++) + { + if ( state->dmr_34_rate_sf[i] == 0x34 ) //timestamp + { + fprintf (stderr, "\n LRRP - Timestamp: "); + fprintf (stderr, "%4d.", (state->dmr_34_rate_sf[i+1] << 6) + (state->dmr_34_rate_sf[i+2] >> 2) ); //4 digit year + fprintf (stderr, "%02d.", ( ((state->dmr_34_rate_sf[i+2] & 0x3) << 2) + ((state->dmr_34_rate_sf[i+3] & 0xC0) >> 6)) ); //2 digit month + fprintf (stderr, "%02d", ( (state->dmr_34_rate_sf[i+3] & 0x30) >> 1) + ((state->dmr_34_rate_sf[i+3] & 0x0E) >> 1) ); //2 digit day + fprintf (stderr, " %02d:",( (state->dmr_34_rate_sf[i+3] & 0x01) << 4) + ((state->dmr_34_rate_sf[i+4] & 0xF0) >> 4) ); //2 digit hour + fprintf (stderr, "%02d:",( (state->dmr_34_rate_sf[i+4] & 0x0F) << 2) + ((state->dmr_34_rate_sf[i+5] & 0xC0) >> 6) ); //2 digit minute + fprintf (stderr, "%02d", ( (state->dmr_34_rate_sf[i+5] & 0x3F) << 0) ); //2 digit second + } + if ( state->dmr_34_rate_sf[i] == 0x51 ) //lattitude and longitude + { + fprintf (stderr, "\n LRRP -"); + fprintf (stderr, " Lat: "); + if (state->dmr_34_rate_sf[i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + fprintf (stderr, "-"); + } + long int lrrplat; + long int lrrplon; + double lat_unit = (double)180/(double)4294967295; + double lon_unit = (double)360/(double)4294967295; + lrrplat = ( ( ((state->dmr_34_rate_sf[i+1] & 0x7F ) << 24 ) + (state->dmr_34_rate_sf[i+2] << 16) + (state->dmr_34_rate_sf[i+3] << 8) + state->dmr_34_rate_sf[i+4]) * 1 ); + lrrplon = ( ( (state->dmr_34_rate_sf[i+5] << 24 ) + (state->dmr_34_rate_sf[i+6] << 16) + (state->dmr_34_rate_sf[i+7] << 8) + state->dmr_34_rate_sf[i+8]) * 1 ); + fprintf (stderr, "%.5lf ", ((double)lrrplat) * lat_unit); + fprintf (stderr, " Lon: "); + if (state->dmr_34_rate_sf[i+5] & 0x80) //first bit indicates a sign, or hemisphere? + { + fprintf (stderr, "-"); + } + fprintf (stderr, "%.5lf", (lrrplon * lon_unit) ); + } + + + if ( state->dmr_34_rate_sf[i] == 0x6C ) + { + //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. + //fprintf (stderr, "\n LRRP - Vi %02X Vf %02X Velocity Units (hex)", state->dmr_34_rate_sf[i+1], state->dmr_34_rate_sf[i+2]); + double velocity = ( ((double)( (state->dmr_34_rate_sf[i+1] ) + state->dmr_34_rate_sf[i+2] )) / ( (double)128)); + //fprintf (stderr, "\n LRRP - %.4lf Meters Per Second", velocity); + fprintf (stderr, "\n LRRP - %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity) ); + } + if ( state->dmr_34_rate_sf[i] == 0x56 ) + { + //check for appropriate terminology here - Heading, bearing, course, or track? + fprintf (stderr, "\n LRRP - Direction %d Degrees", state->dmr_34_rate_sf[i+1] * 2); + } + } + } + //Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull 3/4 Rate Payload DmrDataByte (reverse bits)\n "); + for (i = 0; i < 18; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } + +} + +void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + //Placeholder + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[96]; + uint8_t DmrDataByte[12]; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + // Extract parameters for logging purposes + uint8_t csbk_lb = 0; + uint8_t csbk_pf = 0; + uint8_t csbk_o = 0; + uint8_t csbk_fid = 0; + uint64_t csbk_data = 0; + uint8_t csbk = 0; + + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + BPTCDeInterleaveDMRData(info, DeInteleavedData); + + /* Extract the BPTC 196,96 DMR data */ + IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); + + /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ + BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); + + /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 12; i++) + { + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + //for(i = 0; i < 24; i++) + for(i = 0; i < 16; i++) + { + CRCExtracted = CRCExtracted << 1; + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + } + + //Look into whether or not we need to run these CRC checks for this header information + //and see if its applied the same or differently + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + //CRCExtracted = CRCExtracted ^ 0x6969; + + /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + + /* Convert corrected 12 bytes into 96 bits */ + for(i = 0, j = 0; i < 12; i++, j+=8) + { + DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; + } + // + if (DmrDataByte[0] == 0x43) + { + fprintf (stderr, "\n IP4 Source IP:"); + fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[0] & 0x3F), DmrDataByte[1], DmrDataByte[2], DmrDataByte[3]); //not sure if these are right or not + fprintf (stderr, "[%d]", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + fprintf (stderr, " Destination IP:"); + fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[4] & 0x3F), DmrDataByte[5], DmrDataByte[6], DmrDataByte[7]); //not sure if these are right or not + fprintf (stderr, "[%d]", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + + if (DmrDataByte[0] == 0x01) + { + fprintf (stderr, "\n LRRP Control ACK - "); + fprintf (stderr, " Source:"); + fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + fprintf (stderr, " Destination:"); + fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + //Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull Data Rate Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } + +} + +void Process1Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + //Placeholder + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[96]; + uint8_t DmrDataByte[12]; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + // Extract parameters for logging purposes + uint8_t csbk_lb = 0; + uint8_t csbk_pf = 0; + uint8_t csbk_o = 0; + uint8_t csbk_fid = 0; + uint64_t csbk_data = 0; + uint8_t csbk = 0; + + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + BPTCDeInterleaveDMRData(info, DeInteleavedData); + + /* Extract the BPTC 196,96 DMR data */ + IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); + + /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ + BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); + + /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 12; i++) + { + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + //for(i = 0; i < 24; i++) + for(i = 0; i < 16; i++) + { + CRCExtracted = CRCExtracted << 1; + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + } + + //Look into whether or not we need to run these CRC checks for this header information + //and see if its applied the same or differently + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + //CRCExtracted = CRCExtracted ^ 0x6969; + + /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + + /* Convert corrected 12 bytes into 96 bits */ + for(i = 0, j = 0; i < 12; i++, j+=8) + { + DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; + } + // + if (DmrDataByte[0] == 0x43) + { + //fprintf (stderr, "\n IP4 Source IP:"); + //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + //fprintf (stderr, " Destination IP:"); + //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + + if (DmrDataByte[0] == 0x01) + { + //fprintf (stderr, "\n LRRP Control ACK - "); + //fprintf (stderr, " Source:"); + //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + //fprintf (stderr, " Destination:"); + //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + //Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull Rate 1 Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } + +} + +void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + //Placeholder + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[96]; + uint8_t DmrDataByte[12]; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + // Extract parameters for logging purposes + uint8_t csbk_lb = 0; + uint8_t csbk_pf = 0; + uint8_t csbk_o = 0; + uint8_t csbk_fid = 0; + uint64_t csbk_data = 0; + uint8_t csbk = 0; + + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + BPTCDeInterleaveDMRData(info, DeInteleavedData); + + /* Extract the BPTC 196,96 DMR data */ + IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); + + /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ + BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); + + /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 12; i++) + { + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + //for(i = 0; i < 24; i++) + for(i = 0; i < 16; i++) + { + CRCExtracted = CRCExtracted << 1; + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + } + + //Look into whether or not we need to run these CRC checks for this header information + //and see if its applied the same or differently + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + //CRCExtracted = CRCExtracted ^ 0x6969; + + /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + + /* Convert corrected 12 bytes into 96 bits */ + for(i = 0, j = 0; i < 12; i++, j+=8) + { + DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; + } + // + if (DmrDataByte[0] == 0x43) + { + //fprintf (stderr, "\n IP4 Source IP:"); + //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + //fprintf (stderr, " Destination IP:"); + //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + + if (DmrDataByte[0] == 0x01) + { + //fprintf (stderr, "\n LRRP Control ACK - "); + //fprintf (stderr, " Source:"); + //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + //fprintf (stderr, " Destination:"); + //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + //Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull MBC Header Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } + +} + +void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + //Placeholder + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[96]; + uint8_t DmrDataByte[12]; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + // Extract parameters for logging purposes + uint8_t csbk_lb = 0; + uint8_t csbk_pf = 0; + uint8_t csbk_o = 0; + uint8_t csbk_fid = 0; + uint64_t csbk_data = 0; + uint8_t csbk = 0; + + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + BPTCDeInterleaveDMRData(info, DeInteleavedData); + + /* Extract the BPTC 196,96 DMR data */ + IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); + + /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ + BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); + + /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 12; i++) + { + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + //for(i = 0; i < 24; i++) + for(i = 0; i < 16; i++) + { + CRCExtracted = CRCExtracted << 1; + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + } + + //Look into whether or not we need to run these CRC checks for this header information + //and see if its applied the same or differently + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + //CRCExtracted = CRCExtracted ^ 0x6969; + + /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + + /* Convert corrected 12 bytes into 96 bits */ + for(i = 0, j = 0; i < 12; i++, j+=8) + { + DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; + } + // + if (DmrDataByte[0] == 0x43) + { + //fprintf (stderr, "\n IP4 Source IP:"); + //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + //fprintf (stderr, " Destination IP:"); + //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + + if (DmrDataByte[0] == 0x01) + { + //fprintf (stderr, "\n LRRP Control ACK - "); + //fprintf (stderr, " Source:"); + //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + //fprintf (stderr, " Destination:"); + //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + //Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull MBC Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } + +} + +void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + //Placeholder + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[96]; + uint8_t DmrDataByte[12]; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + // Extract parameters for logging purposes + uint8_t csbk_lb = 0; + uint8_t csbk_pf = 0; + uint8_t csbk_o = 0; + uint8_t csbk_fid = 0; + uint64_t csbk_data = 0; + uint8_t csbk = 0; + + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + BPTCDeInterleaveDMRData(info, DeInteleavedData); + + /* Extract the BPTC 196,96 DMR data */ + IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); + + /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ + BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); + + /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 12; i++) + { + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + //for(i = 0; i < 24; i++) + for(i = 0; i < 16; i++) + { + CRCExtracted = CRCExtracted << 1; + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + } + + //Look into whether or not we need to run these CRC checks for this header information + //and see if its applied the same or differently + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + //CRCExtracted = CRCExtracted ^ 0x6969; + + /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + + /* Convert corrected 12 bytes into 96 bits */ + for(i = 0, j = 0; i < 12; i++, j+=8) + { + DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; + } + // + if (DmrDataByte[0] == 0x43) + { + //fprintf (stderr, "\n IP4 Source IP:"); + //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + //fprintf (stderr, " Destination IP:"); + //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + + if (DmrDataByte[0] == 0x01) + { + //fprintf (stderr, "\n LRRP Control ACK - "); + //fprintf (stderr, " Source:"); + //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + //fprintf (stderr, " Destination:"); + //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + //Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull WTF Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } + +} + + +void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[96]; + uint8_t DmrDataByte[12]; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + BPTCDeInterleaveDMRData(info, DeInteleavedData); + + /* Extract the BPTC 196,96 DMR data */ + IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); + + /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ + BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); + + /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 12; i++) + { + state->dmr_12_rate_sf[i] = state->dmr_12_rate_sf[i+12]; //shift middle 12 to leftmost 12 to load up new round + state->dmr_12_rate_sf[i+12] = state->dmr_12_rate_sf[i+24]; //shift far right 12 to middle 12, going three frames deep; + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + state->dmr_12_rate_sf[i+24] = DmrDataByte[i]; //copy byte to right hand side of shift frame + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + //for(i = 0; i < 24; i++) + for(i = 0; i < 16; i++) + { + CRCExtracted = CRCExtracted << 1; + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + } + + //Look into whether or not we need to run these CRC checks for this header information + //and see if its applied the same or differently + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + //CRCExtracted = CRCExtracted ^ 0x6969; + + /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + + /* Convert corrected 12 bytes into 96 bits */ + for(i = 0, j = 0; i < 12; i++, j+=8) + { + DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; + } + + //Headers and Addresses + if ( (state->dmr_12_rate_sf[0] & 0x3F) == 0x05) //0x05, or 0x45? + { + fprintf (stderr, "\n IP4 Header"); + } + //ARS? + if ( (state->dmr_12_rate_sf[0] & 0x3F) == 0x0C) + { + fprintf (stderr, "\n Source: "); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[0] & 0x3F), state->dmr_12_rate_sf[1], state->dmr_12_rate_sf[2], state->dmr_12_rate_sf[3]); //strip first two bits off 1st byte + fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[1] <<16 ) + (state->dmr_12_rate_sf[2] << 8) + state->dmr_12_rate_sf[3] ); + fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[8] << 8) + state->dmr_12_rate_sf[9]); + fprintf (stderr, "\n Destination:"); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[4] & 0x3F), state->dmr_12_rate_sf[5], state->dmr_12_rate_sf[6], state->dmr_12_rate_sf[7]); //strip first two bits off 4th byte?? + fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[5] <<16 ) + (state->dmr_12_rate_sf[6] << 8) + state->dmr_12_rate_sf[7] ); + fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[10] << 8) + state->dmr_12_rate_sf[11]); + } + //LRRP + if (state->dmr_12_rate_sf[0] == 0x0 && state->dmr_12_rate_sf[4] == 0x0D) //Start LRRP now + { + //fprintf (stderr, "\n Data Blocks [%d]", state->dmr_12_rate_sf[5]); + for (short i = 6; i <= 36; i++) + { + if ( state->dmr_12_rate_sf[i] == 0x34 ) //timestamp + { + fprintf (stderr, "\n LRRP - Timestamp: "); + fprintf (stderr, "%4d.", (state->dmr_12_rate_sf[i+1] << 6) + (state->dmr_12_rate_sf[i+2] >> 2) ); //4 digit year + fprintf (stderr, "%02d.", ( ((state->dmr_12_rate_sf[i+2] & 0x3) << 2) + ((state->dmr_12_rate_sf[i+3] & 0xC0) >> 6)) ); //2 digit month + fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[i+3] & 0x30) >> 1) + ((state->dmr_12_rate_sf[i+3] & 0x0E) >> 1) ); //2 digit day + fprintf (stderr, " %02d:",( (state->dmr_12_rate_sf[i+3] & 0x01) << 4) + ((state->dmr_12_rate_sf[i+4] & 0xF0) >> 4) ); //2 digit hour + fprintf (stderr, "%02d:",( (state->dmr_12_rate_sf[i+4] & 0x0F) << 2) + ((state->dmr_12_rate_sf[i+5] & 0xC0) >> 6) ); //2 digit minute + fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[i+5] & 0x3F) << 0) ); //2 digit second + } + if ( state->dmr_12_rate_sf[i] == 0x51 ) //lattitude and longitude + { + fprintf (stderr, "\n LRRP -"); + fprintf (stderr, " Lat: "); + if (state->dmr_12_rate_sf[i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + fprintf (stderr, "-"); + } + long int lrrplat; + long int lrrplon; + double lat_unit = (double)180/(double)4294967295; + double lon_unit = (double)360/(double)4294967295; + lrrplat = ( ( ((state->dmr_12_rate_sf[i+1] & 0x7F ) << 24 ) + (state->dmr_12_rate_sf[i+2] << 16) + (state->dmr_12_rate_sf[i+3] << 8) + state->dmr_12_rate_sf[i+4]) * 1 ); + lrrplon = ( ( (state->dmr_12_rate_sf[i+5] << 24 ) + (state->dmr_12_rate_sf[i+6] << 16) + (state->dmr_12_rate_sf[i+7] << 8) + state->dmr_12_rate_sf[i+8]) * 1 ); + fprintf (stderr, "%.5lf ", ((double)lrrplat) * lat_unit); + fprintf (stderr, " Lon: "); + if (state->dmr_12_rate_sf[i+5] & 0x80) //first bit indicates a sign, or hemisphere? + { + //fprintf (stderr, "-"); + } + fprintf (stderr, "%.5lf", (lrrplon * lon_unit) ); + //sprintf ( state->dmr_lrrp[3], "Lat: %.5lf Lon: %.5lf", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + } + + + if ( state->dmr_12_rate_sf[i] == 0x6C ) + { + //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. + //fprintf (stderr, "\n LRRP - Vi %02X Vf %02X Velocity Units (hex)", state->dmr_12_rate_sf[i+1], state->dmr_12_rate_sf[i+2]); + double velocity = ( ((double)( (state->dmr_12_rate_sf[i+1] ) + state->dmr_12_rate_sf[i+2] )) / ( (double)128)); + //fprintf (stderr, "\n LRRP - %.4lf Meters Per Second", velocity); + fprintf (stderr, "\n LRRP - %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity) ); + //sprintf ( state->dmr_lrrp[1], "Vel: %.4lf kph", (3.6 * velocity)); + } + if ( state->dmr_12_rate_sf[i] == 0x56 ) + { + //check for appropriate terminology here - Heading, bearing, course, or track? + fprintf (stderr, "\n LRRP - Direction %d Degrees", state->dmr_12_rate_sf[i+1] * 2); + //sprintf ( state->dmr_lrrp[2], "Dir: %d Deg", state->dmr_12_rate_sf[i+1] * 2); + } + } + } + + + //Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull 1/2 Rate Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } + +} + +void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + //Placeholder + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[96]; + uint8_t DmrDataByte[12]; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + // Extract parameters for logging purposes + uint8_t csbk_lb = 0; + uint8_t csbk_pf = 0; + uint8_t csbk_o = 0; + uint8_t csbk_fid = 0; + uint64_t csbk_data = 0; + uint8_t csbk = 0; + + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + BPTCDeInterleaveDMRData(info, DeInteleavedData); + + /* Extract the BPTC 196,96 DMR data */ + IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); + + /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ + BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); + + /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 12; i++) + { + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + //for(i = 0; i < 24; i++) + for(i = 0; i < 16; i++) + { + CRCExtracted = CRCExtracted << 1; + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + } + + //Look into whether or not we need to run these CRC checks for this header information + //and see if its applied the same or differently + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + //CRCExtracted = CRCExtracted ^ 0x6969; + + /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + + /* Convert corrected 12 bytes into 96 bits */ + for(i = 0, j = 0; i < 12; i++, j+=8) + { + DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; + } + + csbk_lb = ( (DmrDataByte[0] & 0x80) >> 7 ); + csbk_pf = ( (DmrDataByte[0] & 0x40) >> 6 ); + csbk_o = DmrDataByte[0] & 0x3F; //grab 6 bits out of first Byte + csbk_fid = DmrDataByte[1]; + csbk_pf = ( (DmrDataByte[1] & 0x80) >> 7); + + if ( ((csbk_o << 8) + csbk_fid) == 0x0106 ) //are the FID values attached really necessary + { + uint8_t nb1 = DmrDataByte[2] & 0x3F; //extract(csbk, 18, 24); 3F or FD? + uint8_t nb2 = DmrDataByte[3] & 0x3F; //extract(csbk, 26, 32); + uint8_t nb3 = DmrDataByte[4] & 0x3F; //extract(csbk, 34, 40); + uint8_t nb4 = DmrDataByte[5] & 0x3F; //extract(csbk, 42, 48); + uint8_t nb5 = DmrDataByte[6] & 0x3F; //extract(csbk, 50, 56); + fprintf (stderr, "\nMotoTRBO Connect Plus Neighbors\n"); + fprintf(stderr, " NB1(%02x), NB2(%02x), NB3(%02x), NB4(%02x), NB5(%02x)", nb1, nb2, nb3, nb4, nb5); + sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); + } + //ConnectPLUS Section // + if ( ((csbk_o << 8) + csbk_fid) == 0x0306 ) //are the FID values attached really necessary + { + uint32_t srcAddr = ( (DmrDataByte[2] << 16) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); //extract(csbk, 16, 40); + uint32_t grpAddr = ( (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); //extract(csbk, 40, 64); + uint8_t lcn = ( (DmrDataByte[8] & 0xF0 ) >> 4 ) ; //extract(csbk, 64, 68); 0xF0 LCN not report same as 'plus'? + uint8_t tslot = ( (DmrDataByte[8] & 0x08 ) >> 3 ); //csbk[68]; TS seems fine + fprintf (stderr, "\nMotoTRBO Connect Plus Channel Grant\n"); + fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); + + } + if ( ((csbk_o << 8) + csbk_fid) == 0x0C06 ) //are the FID values attached really necessary? + { + uint32_t srcAddr = ( (DmrDataByte[2] << 16) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); //extract(csbk, 16, 40); + uint32_t grpAddr = ( (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); //extract(csbk, 40, 64); + uint8_t lcn = ( (DmrDataByte[8] & 0xF0 ) >> 4 ) ; //extract(csbk, 64, 68); 0xF0 LCN not report same as 'plus'? + uint8_t tslot = ( (DmrDataByte[8] & 0x08 ) >> 3 ); //csbk[68]; TS seems fine + fprintf (stderr, "\nMotoTRBO Connect Plus Terminate Channel Grant\n"); //Data only shows a srcAddr?? + fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); + } + + if ( ((csbk_o << 8) + csbk_fid) == 0x0606 ) //are the FID values attached really necessary? + { + uint32_t srcAddr = ( (DmrDataByte[2] << 16) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); //extract(csbk, 16, 40); + uint32_t grpAddr = ( (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); //extract(csbk, 40, 64); + uint8_t lcn = ( (DmrDataByte[8] & 0xF0 ) >> 4 ) ; //extract(csbk, 64, 68); 0xF0 LCN not report same as 'plus'? + uint8_t tslot = ( (DmrDataByte[8] & 0x08 ) >> 3 ); //csbk[68]; TS seems fine + fprintf (stderr, "\nMotoTRBO Connect Plus Data Channel Grant\n"); //Data I have doesn't show any values for lcn or tslot + fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); + } + + if ( ((csbk_o << 8) + csbk_fid) == 0x1106 ) //are the FID values attached really necessary? + { + fprintf (stderr, "\nMotoTRBO Connect Plus Registration Request"); + sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); + } + + if ( ((csbk_o << 8) + csbk_fid) == 0x1206 ) //are the FID values attached really necessary? + { + fprintf (stderr, "\nMotoTRBO Connect Plus Registration Response"); + sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); + } + + if ( ((csbk_o << 8) + csbk_fid) == 0x1806 ) //are the FID values attached really necessary? + { + fprintf (stderr, "\nMotoTRBO Connect Plus Talkgroup Affiliation"); + sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); + } + + //CapMAX + if ( ((csbk_o << 8) + csbk_fid) == 0x1906 ) //CapMAX Aloha + { + //fprintf (stderr, "\nCapacity Max Aloha!"); + sprintf(state->dmr_branding, " MotoTRBO Capacity Max "); + } + + //CapacityPlus Section + + //CapMAX + //if ( ((csbk_o << 8) + csbk_fid) == 0x1F06 ) // + if (csbk_o == 0x1F) + { + uint32_t srcAddr = ( (DmrDataByte[2] << 16) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); //extract(csbk, 16, 40); + uint32_t grpAddr = ( (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); //extract(csbk, 40, 64); + uint8_t lcn = ( (DmrDataByte[8] & 0xF0 ) >> 4 ) ; //extract(csbk, 64, 68); 0xF0 LCN not report same as 'plus'? + uint8_t tslot = ( (DmrDataByte[8] & 0x08 ) >> 3 ); //csbk[68]; TS seems fine + fprintf (stderr, "\nMoto Capacity Plus Call Alert"); + //fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + sprintf(state->dmr_branding, " MotoTRBO Capacity Plus "); + } + + //if ( ((csbk_o << 8) + csbk_fid) == 0x2006 ) // + if (csbk_o == 0x20) + { + uint32_t srcAddr = ( (DmrDataByte[2] << 16) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); //extract(csbk, 16, 40); + uint32_t grpAddr = ( (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); //extract(csbk, 40, 64); + uint8_t lcn = ( (DmrDataByte[8] & 0xF0 ) >> 4 ) ; //extract(csbk, 64, 68); 0xF0 LCN not report same as 'plus'? + uint8_t tslot = ( (DmrDataByte[8] & 0x08 ) >> 3 ); //csbk[68]; TS seems fine + fprintf (stderr, "\nMotoTRBO Capacity Max Call Alert Ack"); + //fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + sprintf(state->dmr_branding, " MotoTRBO Capacity Plus "); + } + + //if ( ((csbk_o << 8) + csbk_fid) == 0x3B06 ) //are the FID values attached really necessary + if (csbk_o == 0x3B) + { + uint8_t nb1 = DmrDataByte[2] & 0x3F; //extract(csbk, 18, 24); 3F or FD? + uint8_t nb2 = DmrDataByte[3] & 0x3F; //extract(csbk, 26, 32); + uint8_t nb3 = DmrDataByte[4] & 0x3F; //extract(csbk, 34, 40); + uint8_t nb4 = DmrDataByte[5] & 0x3F; //extract(csbk, 42, 48); + uint8_t nb5 = DmrDataByte[6] & 0x3F; //extract(csbk, 50, 56); + fprintf (stderr, "\nMotoTRBO Capacity Plus Neighbors"); + //fprintf(stderr, " NB1(%02x), NB2(%02x), NB3(%02x), NB4(%02x), NB5(%02x)", nb1, nb2, nb3, nb4, nb5); + sprintf(state->dmr_branding, " MotoTRBO Capacity Plus "); + } + + //if ( ((csbk_o << 8) + csbk_fid) == 0x3D06 ) // + if (csbk_o == 0x3D) + { + //fprintf (stderr, "\nCapacity Plus/Hytera Preamble"); + //sprintf(state->dmr_branding, " MotoTRBO Capacity Plus "); + //sprintf(state->dmr_branding, " TIII "); //?? one of these next two seems to be on both types, maybe its a TIII thing? + } + + //if ( ((csbk_o << 8) + csbk_fid) == 0x3E06 ) // + if (csbk_o == 0x3E) + { + //fprintf (stderr, "\nCapacity Plus System Status"); + //sprintf(state->dmr_branding, " MotoTRBO Capacity Plus "); + //sprintf(state->dmr_branding, " TIII "); //?? one of these next two seems to be on both types, maybe its a TIII thing? + } + + //possible Site identifier, CSBK Aloha? + if (csbk_o == 0x19) //DmrDataByte[0] == 0x99? + { + fprintf (stderr, "\n Site ID %d-%d.%d", (DmrDataByte[2] & 0xF0 >> 4), DmrDataByte[2] & 0xF, DmrDataByte[3]); + fprintf (stderr, " DCC %d", DmrDataByte[1]); + //sprintf ( state->dmr_callsign[0], "Site ID %d-%d.%d", (DmrDataByte[2] & 0xF0 >> 4), DmrDataByte[2] & 0xF, DmrDataByte[3]); + //sprintf(state->dmr_branding, " TIII "); //?? one of these next two seems to be on both types, maybe its a TIII thing? + } + + + //Hytera XPT + if (csbk_o == 0x28) + { + fprintf (stderr, "\nHytera TIII Announcement"); + //sprintf(state->dmr_branding, " MotoTRBO Capacity Plus "); + sprintf(state->dmr_branding, " TIII "); //?? one of these next two seems to be on both types, maybe its a TIII thing? + } + //if ( ((csbk_o << 8) + csbk_fid) == 0x3606 ) // + if (csbk_o == 0x36) + { + fprintf (stderr, "\nHytera XPT"); + sprintf(state->dmr_branding, " Hytera XPT "); + } + + if (csbk_o == 0x0A) + { + fprintf (stderr, "\nHytera XPT Site State"); + sprintf(state->dmr_branding, " Hytera XPT "); + } + + //if ( ((csbk_o << 8) + csbk_fid) == 0x3706 ) // + if (csbk_o == 0x37) + { + fprintf (stderr, "\nHytera XPT"); + sprintf(state->dmr_branding, " Hytera XPT "); + } + + //Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull CSBK Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } + +} + void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { //Placeholder @@ -114,7 +1386,7 @@ void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], u state->payload_algid = DmrDataByte[0]; state->payload_keyid = DmrDataByte[2]; state->payload_mi = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) ); - if (opts->payload == 1) + if (1 == 1) //have it always print? { fprintf (stderr, "\n DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi); } @@ -235,7 +1507,15 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 /* CRC checking error, so consider the Full LC data as invalid */ TSVoiceSupFrame->FullLC.DataValidity = 0; } - + //Full, amateur callsigns and labels not on this, + if (opts->payload == 1) + { + //fprintf (stderr, "\nFull VoiceLC Payload "); + for (i = 0; i < 12; i++) + { + //fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } /* Print the destination ID (TG) and the source ID */ fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); @@ -315,6 +1595,16 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 fprintf(stderr, "Hamming Irrecoverable Errors = %u\n", IrrecoverableErrors); #endif /* PRINT_VOICE_LC_HEADER_BYTES */ + +//Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull CSBK Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + } } /* End ProcessDmrVoiceLcHeader() */ @@ -437,34 +1727,71 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 } /* Print the destination ID (TG) and the source ID */ - fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); - //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + //fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + //fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + //reset alg, keys, mi during a TLC call termination EVENT so we aren't stuck on an old value, PI header will proceed a new call if BP isn't used + state->payload_algid = 0; + state->payload_keyid = 0; + //state->payload_mfid = 0; + state->payload_mi = 0; - if((IrrecoverableErrors == 0) && CRCCorrect) + //tlc + if((IrrecoverableErrors == 0) && CRCCorrect) //amateur DMR seems to only set radio ID up here I think, figure out best way to set without messing up other DMR types { + fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); fprintf(stderr, "(CRC OK ) "); + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode == 0) //other opcodes may convey callsigns, names, etc. + /* + if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0xAF || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x04 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x05 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x06 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x07 ) //work out why amateur sets sourceid on other codes, but pro only does on whatever + */ + { + state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + state->dmr_color_code = state->color_code; + state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } //only set on good CRC value or corrected values - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; - state->dmr_color_code = state->color_code; + //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + //state->dmr_color_code = state->color_code; } else if(IrrecoverableErrors == 0) { - fprintf(stderr, "RAS (FEC OK/CRC ERR)"); + fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + fprintf(stderr, "RAS (FEC OK/CRC ERR)"); //tlc + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode == 0) //other opcodes may convey callsigns, names, etc. + /* + if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0xAF || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x04 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x05 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x06 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x07 ) //work out why amateur sets sourceid on other codes, but pro only does on whatever + */ + { + state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + state->dmr_color_code = state->color_code; + state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } //only set on good CRC value or corrected values - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; - state->dmr_color_code = state->color_code; + //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + //state->dmr_color_code = state->color_code; } - else fprintf(stderr, "(FEC FAIL/CRC ERR)"); + else fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); #ifdef PRINT_TERMINAISON_LC_BYTES fprintf(stderr, "\n"); @@ -518,6 +1845,7 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) //UNUSED_VARIABLE(opts); /* Check the current time slot */ + if(state->currentslot == 0) { TSVoiceSupFrame = &state->TS1SuperFrame; @@ -527,6 +1855,7 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) TSVoiceSupFrame = &state->TS2SuperFrame; } + /* First step : Reconstitute the BPTC 16x8 matrix */ Burst = 1; /* Burst B to E contains embedded signaling data */ k = 0; @@ -557,11 +1886,13 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) { LC_DataBytes[i] = 0; for(j = 0; j < 8; j++) + //for(j = 0; j < 10; j++) { LC_DataBytes[i] = LC_DataBytes[i] << 1; LC_DataBytes[i] = LC_DataBytes[i] | (LC_DataBit[k] & 0x01); k++; if(k >= 76) break; + //if(k >= 80) break; } } @@ -616,39 +1947,132 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) TSVoiceSupFrame->FullLC.DataValidity = 0; } + //GPS, not sure if in right place or not though + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode == 0x08) + { + long int lrrplat; + long int lrrplon; + double lat_unit = (double)180/(double)4294967295; //damned floats screweing me over lol + double lon_unit = (double)360/(double)4294967295; + //lrrplat = ( ( ((DmrDataByte[0] & 0x3F) << 24 ) + (DmrDataByte[1] << 16) + (DmrDataByte[2] << 8) + DmrDataByte[3]) * 1 ); //(0x0B4/0xFFFFFFFF) + //lrrplon = ( ( (DmrDataByte[4] << 24 ) + (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7]) * 1 ); //(0x168/0xFFFFFFFF) //0x3F, or whole thing?; + + //fprintf (stderr, " Standard GPS Coordinates?? Check Payload.\n"); + //fprintf (stderr, "Figure out what to put here"); + + } + + //ASCII HEX cheat sheet + // 20 - space; 09 - Horizontal Tab; 0A Line Feed; 0D - Carriage Feed; 00 - Null; + // 30 - 39 are 0-9 numerals + // 41 - 5A are upper case A-Z letters + // 61-7A are lower case a-z letters + // + // let's assume that something has to indicate end of valid characters? + if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x03 && TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x08 && opts->payload == 1) + { + //fprintf (stderr, "Call Sign %X [ ", TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3); + sprintf (state->dmr_callsign[TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3], ""); //blank here so it doesn't grow out of control? + for (i = 0; i < 10; i++) + { + if ( + //(LC_DataBytes[i] > 0x29 && LC_DataBytes[i] < 0x3A) || //numerals + //(LC_DataBytes[i] > 0x40 && LC_DataBytes[i] < 0x5B) || //uppers + //(LC_DataBytes[i] > 0x60 && LC_DataBytes[i] < 0x7B) || //lowers + //(LC_DataBytes[i] == 0x20) ) //space + (LC_DataBytes[i] > 0x19 && LC_DataBytes[i] < 0x7F) ) //full range of 'normal' characters? + { + //fprintf (stderr, "%c", LC_DataBytes[i]); + sprintf ( state->dmr_callsign[TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3] + + strlen(state->dmr_callsign[TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3]) , "%c", LC_DataBytes[i]); + } + } + //fprintf (stderr, "]\n"); + if (opts->use_ncurses_terminal == 1) + { + fprintf (stderr, "\n Alias Header and Blocks: [%s%s%s%s%s]", state->dmr_callsign[0], state->dmr_callsign[1], state->dmr_callsign[2], state->dmr_callsign[3], state->dmr_callsign[4] ); + } + } + /* Print the destination ID (TG) and the source ID */ - fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x09) //voice burst, was > 0x07 + { + //fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + //fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + } + //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - if((IrrecoverableErrors == 0) && CRCCorrect) + if((IrrecoverableErrors == 0) && CRCCorrect) //voice burst { - fprintf(stderr, "(CRC OK ) "); + //fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + //fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + //fprintf(stderr, "(CRC OK ) "); //only set on good CRC? - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x09) //other opcodes may convey callsigns, names, etc. was > 0x07 + /* + if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0xAF || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x04 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x05 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x06 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x07 ) //work out why amateur sets sourceid on other codes, but pro only does on whatever + */ + { + fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + fprintf(stderr, "(CRC OK ) "); + state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + state->dmr_color_code = state->color_code; + //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } + //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; - state->dmr_color_code = state->color_code; + //state->dmr_color_code = state->color_code; } else if(IrrecoverableErrors == 0) { - fprintf(stderr, "RAS (FEC OK/CRC ERR)"); + //fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + //fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + //fprintf(stderr, "RAS (FEC OK/CRC ERR)"); //voice burst //or set if was corrected - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x07) //other opcodes may convey callsigns, names, etc. + /* + if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0xAF || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x04 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x05 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x06 || + TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x07 ) //other opcodes may convey callsigns, names, etc. + */ + { + fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + fprintf(stderr, "RAS (FEC OK/CRC ERR) "); + state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + state->dmr_color_code = state->color_code; + //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } + //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; - state->dmr_color_code = state->color_code; + //state->dmr_color_code = state->color_code; } - else fprintf(stderr, "(FEC FAIL/CRC ERR)"); + else fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); #ifdef PRINT_VOICE_BURST_BYTES - fprintf(stderr, "\n"); + //fprintf(stderr, "\n"); fprintf(stderr, "VOICE BURST BYTES : "); - for(i = 0; i < 10; i++) + for(i = 0; i < 8; i++) { fprintf(stderr, "0x%02X", LC_DataBytes[i]); if(i != 9) fprintf(stderr, " - "); @@ -674,6 +2098,18 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) fprintf(stderr, "Hamming Irrecoverable Errors = %u\n", IrrecoverableErrors); #endif /* PRINT_VOICE_BURST_BYTES */ +//Full + if (opts->payload == 1) + { + fprintf (stderr, "\nFull Voice Burst Payload "); + //for (i = 0; i < 8; i++) + for (i = 0; i < 10; i++) + { + fprintf (stderr, "[%02X]", LC_DataBytes[i]); //amateur DMR hams seem to use this area to send callsigns and names using 04,05,06,07 opcodes + } + //fprintf (stderr, "\n"); + } + } /* End ProcessVoiceBurstSync() */ diff --git a/src/dmr_voice.c b/src/dmr_voice.c index fb0cf5c..5d4fe41 100644 --- a/src/dmr_voice.c +++ b/src/dmr_voice.c @@ -631,7 +631,7 @@ void processDMRvoice (dsd_opts * opts, dsd_state * state) else fprintf(stderr, "(CRC ERR) |"); //add line break //fprintf(stderr, " VOICE e: \n"); - fprintf(stderr, " VOICE \n"); + fprintf(stderr, " VOICE "); } /* Perform the SYNC DMR data embedded decoding */ diff --git a/src/dsd_audio.c b/src/dsd_audio.c index 3a28e9e..bfc5acd 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -37,9 +37,11 @@ void openPulseOutput(dsd_opts * opts) //fprintf (stderr,"digi rate out = %d\n", opts->pulse_digi_rate_out); //pa_channel_map_init_stereo(&channel_map); //ss - if (opts->monitor_input_audio == 1) + //if (opts->monitor_input_audio == 1) + if (opts->frame_dmr == 1 && opts->audio_in_type != 3) { - opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL); + //opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL); + //opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "DMR/MOTOTRBO Right", &ss, NULL, NULL, NULL); } //tt @@ -432,15 +434,20 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state) //two slot audio testing, still need to seperate channels first internally, but this will play them out of different streams /* - if(state->currentslot == 0) + if(state->currentslot == 0 && opts->audio_in_type != 3) { pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. } - if(state->currentslot == 1) + if(state->currentslot == 1 && opts->audio_in_type != 3) { pa_simple_write(opts->pulse_raw_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. //pa_simple_write(opts->pulse_raw_dev_out, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL); //Yay! It works. } + + if (opts->audio_in_type == 3) + { + pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. + } */ pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. diff --git a/src/dsd_file.c b/src/dsd_file.c index a05e960..6bfe428 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -30,7 +30,7 @@ saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d) k = 0; if (opts->payload == 1) //make opt variable later on to toggle this { - fprintf(stderr, "\n"); + fprintf(stderr, "\n IMBE "); //fprintf(stderr, "ALGID=%X KEYID=%X\n", state->payload_algid, state->payload_keyid); } @@ -70,7 +70,7 @@ saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d) k = 0; if (opts->payload == 1) //make opt variable later on to toggle this { - fprintf(stderr, "\n"); + fprintf(stderr, "\n AMBE "); } //for (i = 0; i < 6; i++) for (i = 0; i < 7; i++) //using 7 seems to break older amb files where it was 6, need to test 7 on 7 some more diff --git a/src/dsd_frame.c b/src/dsd_frame.c index da7b8a2..fe0b37c 100644 --- a/src/dsd_frame.c +++ b/src/dsd_frame.c @@ -35,14 +35,14 @@ printFrameInfo (dsd_opts * opts, dsd_state * state) } if (state->nac != 0) { - fprintf (stderr,"nac: %4X ", state->nac); + fprintf (stderr,"nac: [%4X] ", state->nac); } if (opts->verbose > 1) { - fprintf (stderr,"src: %8i ", state->lastsrc); + fprintf (stderr,"src: [%8i] ", state->lastsrc); } - fprintf (stderr,"tg: %5i ", state->lasttg); + fprintf (stderr,"tg: [%5i] ", state->lasttg); } void @@ -421,7 +421,7 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->errorbars == 1) { printFrameInfo (opts, state); - fprintf (stderr," Ignoring LDU2 not preceeded by LDU1\n"); + fprintf (stderr,"\n Ignoring LDU2 not preceeded by LDU1\n"); } state->lastp25type = 0; sprintf (state->fsubtype, " "); diff --git a/src/dsd_main.c b/src/dsd_main.c index 6bc63fc..e95ca9f 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -199,9 +199,9 @@ initOpts (dsd_opts * opts) opts->pulse_digi_in_channels = 1; //2 opts->pulse_digi_out_channels = 1; //2 - sprintf (opts->output_name, "Auto Detect"); + sprintf (opts->output_name, "Default Channel"); opts->pulse_flush = 1; //set 0 to flush, 1 for flushed - opts->use_ncurses_terminal = 0; + opts->use_ncurses_terminal = 0; opts->payload = 0; opts->EncryptionMode = MODE_UNENCRYPTED; @@ -213,7 +213,7 @@ initState (dsd_state * state) { int i, j; - + state->last_dibit = 0; state->dibit_buf = malloc (sizeof (int) * 1000000); state->dibit_buf_p = state->dibit_buf + 200; memset (state->dibit_buf, 0, sizeof (int) * 200); @@ -326,6 +326,18 @@ initState (dsd_state * state) state->payload_algid = 0; state->payload_keyid = 0; + sprintf (state->dmr_branding, " "); + sprintf (state->dmr_callsign[0], ""); + sprintf (state->dmr_callsign[1], ""); + sprintf (state->dmr_callsign[2], ""); + sprintf (state->dmr_callsign[3], ""); + sprintf (state->dmr_lrrp[0], ""); + sprintf (state->dmr_lrrp[1], ""); + sprintf (state->dmr_lrrp[2], ""); + sprintf (state->dmr_lrrp[3], ""); + sprintf (state->dmr_lrrp[4], ""); + sprintf (state->dmr_lrrp[5], ""); + state->K = 0; #ifdef TRACE_DSD @@ -360,7 +372,7 @@ usage () fprintf (stderr," -z Frame rate for datascope\n"); fprintf (stderr,"\n"); fprintf (stderr,"Input/Output options:\n"); - fprintf (stderr," -i Audio input device (default is pulse audio, - for piped stdin, rtl for rtl device)\n"); + fprintf (stderr," -i Audio input device (default is pulse audio, \n - for piped stdin, rtl for rtl device)\n"); fprintf (stderr," -o Audio output device (default is pulse audio)\n"); fprintf (stderr," -d Create mbe data files, use this directory\n"); fprintf (stderr," -r Read/Play saved mbe data from file(s)\n"); @@ -374,8 +386,8 @@ usage () fprintf (stderr," -P RTL-SDR PPM Error (default = 0)\n"); fprintf (stderr," -D RTL-SDR Device Index Number\n"); fprintf (stderr," -G RTL-SDR Device Gain (0-49) (default = 0 Auto Gain)\n"); - fprintf (stderr," -L RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)(Just have to guess really...)\n"); - fprintf (stderr," -V RTL-SDR Sample Gain Multiplier (default = 1)(1-3 recommended, still testing) \n"); + fprintf (stderr," -L RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)\n (Just have to guess really...)\n"); + fprintf (stderr," -V RTL-SDR Sample Gain Multiplier (default = 1)\n"); fprintf (stderr," -Y RTL-SDR VFO Bandwidth kHz (default = 48)(6, 8, 12, 16, 24, 48) \n"); fprintf (stderr," -U RTL-SDR UDP Remote Port (default = 6020)\n"); fprintf (stderr,"\n"); @@ -858,7 +870,12 @@ main (int argc, char **argv) opts.frame_dmr = 1; opts.frame_dpmr = 0; //borrow from LEH opts.frame_provoice = 0; //turn it on, doesn't work due to symbol rate difference - sprintf (opts.output_name, "Auto Detect"); + //adding stereo for DMR so we don't accidentally segfault + //opts.pulse_raw_rate_out = 24000; //doing tests with 2 channels at 24000 for 48000 audio default in pulse + //opts.pulse_digi_rate_out = 24000; //need to copy this to rtl type in and change rate out to 8000 + //opts.pulse_raw_out_channels = 2; + //opts.pulse_digi_out_channels = 2; //2 + sprintf (opts.output_name, "Default Channel"); } else if (optarg[0] == 'd') { @@ -979,7 +996,12 @@ main (int argc, char **argv) opts.mod_qpsk = 0; opts.mod_gfsk = 0; // state.rf_mod = 0; // + //opts.pulse_raw_rate_out = 24000; //doing tests with 2 channels at 24000 for 48000 audio default in pulse + //opts.pulse_digi_rate_out = 24000; //need to copy this to rtl type in and change rate out to 8000 + //opts.pulse_raw_out_channels = 2; + //opts.pulse_digi_out_channels = 2; //2 sprintf (opts.output_name, "DMR/MOTOTRBO"); + //sprintf (opts.output_name, "DMR/MOTOTRBO Left"); fprintf (stderr,"Decoding only DMR/MOTOTRBO frames.\n"); } else if (optarg[0] == 'm') diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index 01f2d96..3a2abd5 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -90,12 +90,15 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a imbe_d[i] = 0; } + if ((state->synctype == 0) || (state->synctype == 1)) { // 0 +P25p1 // 1 -P25p1 mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + //mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, processed_block, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + if (opts->mbe_out_f != NULL) { saveImbe4400Data (opts, state, imbe_d); @@ -104,6 +107,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a else if ((state->synctype == 14) || (state->synctype == 15)) { mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + //mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, processed_block, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + if (opts->mbe_out_f != NULL) { saveImbe4400Data (opts, state, imbe_d); diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index 6e2d0c2..23badd4 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -146,9 +146,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (state->carrier == 0) //reset these to 0 when no carrier { - //state->payload_algid = 0; - //state->payload_keyid = 0; - //state->payload_mfid = 0; + state->payload_algid = 0; + state->payload_keyid = 0; + //state->payload_mfid = 0; + state->payload_mi = 0; + + state->nxdn_key = 0; + state->nxdn_cipher_type = 0; + + sprintf(state->dmr_branding, " "); } if ( (lls == 14 || lls == 15) && (time(NULL) - call_matrix[9][5] > 5) && state->carrier == 1) //honestly have no idea how to do this for pV, just going time based? only update on carrier == 1. @@ -198,6 +204,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) //if ( (call_matrix[9][4] != dcc || call_matrix[9][2] != rd) && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR if ( (call_matrix[9][4] != dcc || call_matrix[9][2] != rd) && (lls == 12 || lls == 13) ) //DMR, needs work { + //reset amateur signs on radio id change + for (short i = 0; i < 5; i++) + { + sprintf (state->dmr_callsign[i], ""); + } //dcc = state->dmr_color_code; for (short int k = 0; k < 9; k++) { @@ -279,12 +290,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (state->carrier == 1){ //figure out method that will tell me when is active and when not active, maybe carrier but this doesn't print anyways unless activity attron(COLOR_PAIR(3)); level = (int) state->max / 164; //only update on carrier present - //reset = 1; + reset = 1; } if (state->carrier == 0 && opts->reset_state == 1 && reset == 1) { - //resetState (state); - //reset = 0; + resetState (state); + reset = 0; } @@ -335,13 +346,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (state->lastsrc > 0 && (lls == 12 || lls == 13 || lls == 0 || lls == 1)) //DMR Voice and P25P1 { rd = state->lastsrc; - //opts->p25enc = 0; + opts->p25enc = 0; } if (state->lasttg > 0 && (lls == 12 || lls == 13 || lls == 0 || lls == 1)) //DMR Voice and P25P1 { tg = state->lasttg; - //opts->p25enc = 0; + opts->p25enc = 0; } //if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) //change this to NXDN syncs later on @@ -411,10 +422,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) //printw("| NAC: [0x%X] \n", nc); printw("| TID:[%8i] RID:[%8i] ", tg, rd); printw("NAC: [0x%3X] \n", nc); - printw("| ALG: [0x%02X] ", state->payload_algid); - printw("KEY: [0x%04X] ", state->payload_keyid); - //printw("MFG: [0x%X] ", state->payload_mfid); //no way of knowing if this is accurate info yet - if (state->payload_algid != 0x80 && state->carrier == 1) + printw("| ALG:[0x%02X] ", state->payload_algid); + printw(" KEY:[0x%04X] ", state->payload_keyid); + printw(" MFID: [0x%02X] ", state->payload_mfid); //no way of knowing if this is accurate info yet + if (state->payload_algid != 0x80 && state->payload_algid != 0x0 && state->carrier == 1) { attron(COLOR_PAIR(2)); printw("**ENC**"); @@ -430,7 +441,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) //printw ("| DCC: [%i] FID: [%02X]\n", dcc, state->dmr_fid); //attron(COLOR_PAIR(3)); printw ("| DCC: [%2i] FID: [%02X] SOP: [%02X] ", dcc, state->dmr_fid, state->dmr_so); - if(state->payload_mi == 0 && state->dmr_so & 0x40) + //if(state->payload_mi == 0 && state->dmr_so & 0x40) + if(state->payload_mi == 0 && state->dmr_so == 0x40) { attron(COLOR_PAIR(5)); printw ("**BP** "); @@ -438,7 +450,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attroff(COLOR_PAIR(5)); attron(COLOR_PAIR(3)); } - if(state->payload_keyid > 0 && state->dmr_so & 0x40) + //if(state->payload_keyid > 0 && state->dmr_so & 0x40) + if(state->payload_keyid > 0 && state->dmr_so == 0x40) { attron(COLOR_PAIR(5)); printw (" ALG: [0x%02X] KEY [0x%02X] MI [0x%08X]", state->payload_algid, state->payload_keyid, state->payload_mi); @@ -446,7 +459,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attroff(COLOR_PAIR(5)); attron(COLOR_PAIR(3)); } - if(state->K > 0 && state->dmr_so & 0x40) + //if(state->K > 0 && state->dmr_so & 0x40) + if(state->K > 0 && state->dmr_so == 0x40) { attron(COLOR_PAIR(5)); //printw ("K 0x[%12llX]", state->K); //seems to get reset in ncurses for some reason? some bigger issue perhaps? other strange issues occur too with provoice @@ -455,8 +469,19 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } printw("\n"); - printw ("| TID: [%8i] RID: [%8i]", tg, rd); - if(state->dmr_so & 0x80) //1000 0000 //prints emergency on some amateru DMR repeaters with 0x8E SOP code, need to investigate + printw ("| TID: [%8i] RID: [%8i]", tg, rd); + + if (1 == 1) //figure out what to put here later on for amateur call signs + { + printw (" ["); + for (short i = 0; i < 5; i++) + { + printw ("%s", state->dmr_callsign[i]); + } + printw ("]"); + } + //if(state->dmr_so & 0x80) //1000 0000 //prints emergency on some amateru DMR repeaters with 0x8E SOP code, need to investigate + if(state->dmr_so == 0x80) { attron(COLOR_PAIR(2)); printw (" **Emergency** "); @@ -464,21 +489,23 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(3)); } - if(state->dmr_so & 0x40) //0100 0000 + //if(state->dmr_so & 0x40) //0100 0000 + if(state->dmr_so == 0x40) //0100 0000 { attron(COLOR_PAIR(2)); printw (" **ENC** "); //printw ("0x%X", state->payload_algid); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); - //if (state->K = 0) - //{ + if (state->K == 0) + { //opts->p25enc = 1; //just testing for now - //} + } } - if(state->dmr_so & 0x30) //0010 0000 + //if(state->dmr_so & 0x30) //0010 0000 + if(state->dmr_so == 0x30) //0010 0000 { attron(COLOR_PAIR(2)); printw (" **Private Call** "); @@ -511,7 +538,17 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { //printw ("| DCC: [%i]\n", dcc); printw ("| DCC: [%2i] FID: [%02X] SOP: [%02X] \n", dcc, state->dmr_fid, state->dmr_so); - printw ("| TID: [%8i] RID: [%8i]", tg, rd); + printw ("| TID: [%8i] RID: [%8i]", tg, rd); + + if (1 == 1) //figure out what to put here later on for amateur call signs + { + printw (" ["); + for (short i = 0; i < 5; i++) + { + printw ("%s", state->dmr_callsign[i]); + } + printw ("]"); + } //does this need to be in DATA type? /* if(state->dmr_so & 0x80) @@ -562,6 +599,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } } printw ("%s \n", s1last); + /* + if (state->dmr_lrrp[3] != NULL) + { + printw ("| LRRP -"); + printw (" %s", state->dmr_lrrp[3]); + printw (" %s", state->dmr_lrrp[1]); + printw (" %s\n", state->dmr_lrrp[2]); + } + */ } //dPMR @@ -573,7 +619,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (lls != -1) //is there a synctype 0? { - printw ("| %s \n", SyncTypes[lls]); + printw ("| %s ", SyncTypes[lls]); + printw ("%s", state->dmr_branding); + printw ("\n"); } printw ("------------------------------------------------------------------------------\n"); //colors off diff --git a/src/p25p1_hdu.c b/src/p25p1_hdu.c index 26ad960..5aa1d2f 100644 --- a/src/p25p1_hdu.c +++ b/src/p25p1_hdu.c @@ -453,14 +453,16 @@ processHDU(dsd_opts* opts, dsd_state* state) status = getDibit (opts, state); //TODO: Do something useful with the status bits... - if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors?? - //if (state->carrier == 1) + //if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors?? + if (state->carrier == 1) { algidhex = strtol (algid, NULL, 2); kidhex = strtol (kid, NULL, 2); state->payload_algid = algidhex; state->payload_keyid = kidhex; + //state->payload_mfid = ConvertBitIntoBytes(&mfid[0], 7); + //state->payload_mfid = strtol (mfid, NULL, 2); mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32); mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32); @@ -468,10 +470,11 @@ processHDU(dsd_opts* opts, dsd_state* state) } //if (state->errs == 0 && algidhex != 0x80) - if (opts->payload == 1) + if (1 == 1) //always print hdu alg info + //if (opts->payload == 1 && state->errs == 0) { //fprintf (stderr, " HDU ALG ID: 0x%X KEY ID: 0x%X MI: %s \n", algidhex, kidhex, mi); - fprintf (stderr, " HDU ALG ID: 0x%X KEY ID: 0x%X MI: 0x%08llX%08llX%02llX\n", algidhex, kidhex, mihex1, mihex2, mihex3); + fprintf (stderr, " HDU ALG ID: 0x%X KEY ID: 0x%X MI: 0x%08llX%08llX%02llX MFID: 0x%02X \n", algidhex, kidhex, mihex1, mihex2, mihex3, state->payload_mfid); } if (opts->p25enc == 1 && opts->payload == 0) diff --git a/src/p25p1_ldu1.c b/src/p25p1_ldu1.c index d804855..fc0519a 100644 --- a/src/p25p1_ldu1.c +++ b/src/p25p1_ldu1.c @@ -330,9 +330,14 @@ processLDU1 (dsd_opts* opts, dsd_state* state) lcinfo[54] = hex_data[ 0][4] + '0'; lcinfo[55] = hex_data[ 0][5] + '0'; + unsigned long long int lcinfohex = 0; if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, otherwise, garbage values may be collected { state->payload_mfid = strtol (mfid, NULL, 2); + + //state->payload_mfid = ConvertBitIntoBytes(&mfid[0], 7); + lcinfohex = ConvertBitIntoBytes(&lcinfo[0], 55); + //fprintf (stderr, " LDU1 LCINFO %16llX \n", lcinfohex); } processP25lcw (opts, state, lcformat, mfid, lcinfo); diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c index 72aae00..0432f6a 100644 --- a/src/p25p1_ldu2.c +++ b/src/p25p1_ldu2.c @@ -360,8 +360,8 @@ processLDU2 (dsd_opts * opts, dsd_state * state) kid[15] = hex_data[ 0][5] + '0'; - if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors?? - //if (state->carrier == 1) + //if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors?? + if (state->carrier == 1) { algidhex = strtol (algid, NULL, 2); @@ -376,7 +376,8 @@ processLDU2 (dsd_opts * opts, dsd_state * state) } //if (state->errs == 0 && algidhex != 0x80) - if (opts->payload == 1) + if (1 == 1) //always print the LDU2 alg info + //if (opts->payload == 1 && state->errs == 0) { //fprintf (stderr, " LDU2 ALG ID: 0x%X KEY ID: 0x%X MI: %s \n", algidhex, kidhex, mi); fprintf (stderr, " LDU2 ALG ID: 0x%X KEY ID: 0x%X MI: 0x%08llX%08llX%02llX\n", algidhex, kidhex, mihex1, mihex2, mihex3); diff --git a/src/trellis.cpp b/src/trellis.cpp new file mode 100644 index 0000000..3379f30 --- /dev/null +++ b/src/trellis.cpp @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2016 by Jonathan Naylor, G4KLX + * + * Modifications of original code to work with OP25 + * Copyright (C) 2019 by Graham J. Norbury + * + * This program 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; version 2 of the License. + * + * This program 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. + */ +#include "dsd.h" +//#include "trellis.h" + +#include +#include + +const unsigned int INTERLEAVE_TABLE[] = { + 0U, 1U, 8U, 9U, 16U, 17U, 24U, 25U, 32U, 33U, 40U, 41U, 48U, 49U, 56U, 57U, 64U, 65U, 72U, 73U, 80U, 81U, 88U, 89U, 96U, 97U, + 2U, 3U, 10U, 11U, 18U, 19U, 26U, 27U, 34U, 35U, 42U, 43U, 50U, 51U, 58U, 59U, 66U, 67U, 74U, 75U, 82U, 83U, 90U, 91U, + 4U, 5U, 12U, 13U, 20U, 21U, 28U, 29U, 36U, 37U, 44U, 45U, 52U, 53U, 60U, 61U, 68U, 69U, 76U, 77U, 84U, 85U, 92U, 93U, + 6U, 7U, 14U, 15U, 22U, 23U, 30U, 31U, 38U, 39U, 46U, 47U, 54U, 55U, 62U, 63U, 70U, 71U, 78U, 79U, 86U, 87U, 94U, 95U}; + +const unsigned char ENCODE_TABLE[] = { + 0U, 8U, 4U, 12U, 2U, 10U, 6U, 14U, + 4U, 12U, 2U, 10U, 6U, 14U, 0U, 8U, + 1U, 9U, 5U, 13U, 3U, 11U, 7U, 15U, + 5U, 13U, 3U, 11U, 7U, 15U, 1U, 9U, + 3U, 11U, 7U, 15U, 1U, 9U, 5U, 13U, + 7U, 15U, 1U, 9U, 5U, 13U, 3U, 11U, + 2U, 10U, 6U, 14U, 0U, 8U, 4U, 12U, + 6U, 14U, 0U, 8U, 4U, 12U, 2U, 10U}; + +const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; + +#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) +#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) + +//unsigned char state = 0U; +//unsigned int superposition = 0; +//CDMRTrellis::CDMRTrellis() +//{ +//} + +//CDMRTrellis::~CDMRTrellis() +//{ +//} + +//void CDMRTrellis::tribitsToBits(const unsigned char* tribits, unsigned char* payload) const +//void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload) const +//bool CDMRTrellis::fixCode(unsigned char* points, unsigned int failPos, unsigned char* payload) const +//bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload) const +bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload) + +{ + //unsigned int bestPos = 0U; + //unsigned int bestVal = 0U; + + for (unsigned j = 0U; j < 20U; j++) { + unsigned int bestPos = 0U; + unsigned int bestVal = 0U; + fprintf (stderr, " fail%d-", failPos); + + for (unsigned int i = 0U; i < 16U; i++) { + points[failPos] = i; + + fprintf (stderr, "i%d", i); + + unsigned char tribits[49U]; + unsigned int pos = CDMRTrellisCheckCode(points, tribits); + if (pos == 999U) { + CDMRTrellisTribitsToBits(tribits, payload); + return true; + } + + if (pos > bestPos) { + bestPos = pos; + bestVal = i; + } + } + + points[failPos] = bestVal; + failPos = bestPos; + } + + return false; +} + +void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload) + +{ + //g4klx version below + /* + for (unsigned int i = 0U; i < 48U; i++) { + unsigned char tribit = tribits[i]; + + bool b1 = (tribit & 0x04U) == 0x04U; + bool b2 = (tribit & 0x02U) == 0x02U; + bool b3 = (tribit & 0x01U) == 0x01U; + + unsigned int n = 143U - i * 3U; + /* + WRITE_BIT(payload, n, b1); + n--; + WRITE_BIT(payload, n, b2); + n--; + WRITE_BIT(payload, n, b3); + } + */ + + // boatbod version below... + // convert tribits to bits + + unsigned char bits[144]; + for (int i = 0; i < 48; i++) { + bits[(i * 3) + 0] = (tribits[i] >> 2) & 1; + bits[(i * 3) + 1] = (tribits[i] >> 1) & 1; + bits[(i * 3) + 2] = tribits[i] & 1; + } + + + // convert bits to bytes + + for (int i = 0; i < 144; i++) + payload[i/8] = (payload[i/8] << 1) | bits[i]; + +} + +//unsigned int CDMRTrellis::checkCode(const unsigned char* points, unsigned char* tribits) const +//unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits) const +/* +unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits) + +{ + //replace i with superposition; revert back if totally borked + //unsigned char state = 0U; + + //for (unsigned int i = 0U; i < 49U; i++) { + //tribits[i] = 9U; + for (superposition; superposition < 49U; superposition++) { + tribits[superposition] = 9U; + for (unsigned int j = 0U; j < 8U; j++) { + if (points[superposition] == ENCODE_TABLE[state * 8U + j]) { + tribits[superposition] = j; + break; + } + } + + if (tribits[superposition] == 9) { + return superposition; + //experiment placing fixcode right in here instead + //or we need to find a way to update state outside of this function + } + state = tribits[superposition]; + + } + //if (tribits[48U] != 0U) + //return 48U; + + return 999U; +} +*/ +unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits) +{ + unsigned char state = 0U; + + for (unsigned int i = 0U; i < 49U; i++) { + tribits[i] = 9U; + + for (unsigned int j = 0U; j < 8U; j++) { + if (points[i] == ENCODE_TABLE[state * 8U + j]) { + tribits[i] = j; + break; + } + } + + if (tribits[i] == 9U) + return i; + + state = tribits[i]; + } + + if (tribits[48U] != 0U) + return 48U; + + return 999U; +} + +//void CDMRTrellis::deinterleave(const unsigned char* data, signed char* dibits) const +//void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits) const +void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits) +{ + int n; + signed char dibit; + + for (int i = 0; i < 98; i++) { + n = i * 2; + if (n >= 98) n += 68; + bool b1 = data[n] != 0x0; + + n = i * 2 + 1; + if (n >= 98) n += 68; + bool b2 = data[n] != 0x0; + + if (!b1 && b2) + dibit = +3; + else if (!b1 && !b2) + dibit = +1; + else if (b1 && !b2) + dibit = -1; + else + dibit = -3; + + n = INTERLEAVE_TABLE[i]; + dibits[n] = dibit; + } +} + +//void CDMRTrellis::dibitsToPoints(const signed char* dibits, unsigned char* points) const +//void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points) const +void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points) +{ + for (unsigned int i = 0U; i < 49U; i++) { + if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -1) + points[i] = 0U; + else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -1) + points[i] = 1U; + else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -3) + points[i] = 2U; + else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -3) + points[i] = 3U; + else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -1) + points[i] = 4U; + else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -1) + points[i] = 5U; + else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -3) + points[i] = 6U; + else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -3) + points[i] = 7U; + else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +3) + points[i] = 8U; + else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +3) + points[i] = 9U; + else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +1) + points[i] = 10U; + else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +1) + points[i] = 11U; + else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +3) + points[i] = 12U; + else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +3) + points[i] = 13U; + else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +1) + points[i] = 14U; + else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +1) + points[i] = 15U; + } +} + +//void CDMRTrellis::pointsToDibits(const unsigned char* points, signed char* dibits) const +//void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits) const +void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits) +{ + for (unsigned int i = 0U; i < 49U; i++) { + switch (points[i]) { + case 0U: + dibits[i * 2U + 0U] = +1; + dibits[i * 2U + 1U] = -1; + break; + case 1U: + dibits[i * 2U + 0U] = -1; + dibits[i * 2U + 1U] = -1; + break; + case 2U: + dibits[i * 2U + 0U] = +3; + dibits[i * 2U + 1U] = -3; + break; + case 3U: + dibits[i * 2U + 0U] = -3; + dibits[i * 2U + 1U] = -3; + break; + case 4U: + dibits[i * 2U + 0U] = -3; + dibits[i * 2U + 1U] = -1; + break; + case 5U: + dibits[i * 2U + 0U] = +3; + dibits[i * 2U + 1U] = -1; + break; + case 6U: + dibits[i * 2U + 0U] = -1; + dibits[i * 2U + 1U] = -3; + break; + case 7U: + dibits[i * 2U + 0U] = +1; + dibits[i * 2U + 1U] = -3; + break; + case 8U: + dibits[i * 2U + 0U] = -3; + dibits[i * 2U + 1U] = +3; + break; + case 9U: + dibits[i * 2U + 0U] = +3; + dibits[i * 2U + 1U] = +3; + break; + case 10U: + dibits[i * 2U + 0U] = -1; + dibits[i * 2U + 1U] = +1; + break; + case 11U: + dibits[i * 2U + 0U] = +1; + dibits[i * 2U + 1U] = +1; + break; + case 12U: + dibits[i * 2U + 0U] = +1; + dibits[i * 2U + 1U] = +3; + break; + case 13U: + dibits[i * 2U + 0U] = -1; + dibits[i * 2U + 1U] = +3; + break; + case 14U: + dibits[i * 2U + 0U] = +3; + dibits[i * 2U + 1U] = +1; + break; + default: + dibits[i * 2U + 0U] = -3; + dibits[i * 2U + 1U] = +1; + break; + } + } +} + +//void CDMRTrellis::bitsToTribits(const unsigned char* payload, unsigned char* tribits) const +//void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits) const +void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits) +{ + for (unsigned int i = 0U; i < 48U; i++) { + unsigned int n = 143U - i * 3U; + + bool b1 = READ_BIT(payload, n) != 0x00U; + n--; + bool b2 = READ_BIT(payload, n) != 0x00U; + n--; + bool b3 = READ_BIT(payload, n) != 0x00U; + + unsigned char tribit = 0U; + tribit |= b1 ? 4U : 0U; + tribit |= b2 ? 2U : 0U; + tribit |= b3 ? 1U : 0U; + + //tribits[i] = tribit; + } + + tribits[48U] = 0U; +} + +//bool CDMRTrellis::decode(const unsigned char* data, unsigned char* payload) +bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) +{ + assert(data != NULL); + assert(payload != NULL); + if (1 == 1) + { + fprintf (stderr, "\n Raw Trellis Dibits inside Decoder\n "); + for (short i = 0; i < 98; i++) + { + fprintf (stderr, "[%0d]", data[i]); + } + } + signed char dibits[98U]; + CDMRTrellisDeinterleave(data, dibits); + if (1 == 1) + { + fprintf (stderr, "\n Trellis Deinterleaved Dibits inside Decoder (converted to signed)\n "); + for (short i = 0; i < 98; i++) + { + fprintf (stderr, "[%d]", dibits[i]); //signed char, values should be -3, -1, 1, 3 only + } + } + unsigned char points[49U]; + CDMRTrellisDibitsToPoints(dibits, points); + if (1 == 1) + { + fprintf (stderr, "\n Trellis Points inside Decoder (no higher than 15U?)\n "); + for (short i = 0; i < 49; i++) + { + fprintf (stderr, "[%02u]", points[i]); + } + } + // Check the original code + unsigned char tribits[49U]; + unsigned int failPos = CDMRTrellisCheckCode(points, tribits); + + + + + if (failPos == 999U) { + CDMRTrellisTribitsToBits(tribits, payload); + if (1 == 1) + { + fprintf (stderr, "\nTrellis Payload Tribits to Bits failPos == 999U\n "); + for (short i = 0; i < 18; i++) + { + fprintf (stderr, "[%02u]", payload[i]); + } + } + return true; + } + + unsigned char savePoints[49U]; + for (unsigned int i = 0U; i < 49U; i++) + savePoints[i] = points[i]; + + bool ret = CDMRTrellisFixCode(points, failPos, payload); + if (ret){ + + if (1 == 1) + { + fprintf (stderr, "\n Trellis Tribits inside Decoder\n "); + for (short i = 0; i < 49; i++) + { + fprintf (stderr, "[%0u]", tribits[i]); //shouldn't have any values greater that 0x7? + } + } + + if (1 == 1) + { + fprintf (stderr, "\nTrellis Payload Tribits to Bits fix return true\n "); //this one seems to be happening + for (short i = 0; i < 18; i++) + { + fprintf (stderr, "[%02X]", payload[i]); + } + } + return true; } + + if (failPos == 0U) + { + if (1 == 1) + { + fprintf (stderr, "\nTrellis Payload Tribits to Bits failPos == 0U\n "); + for (short i = 0; i < 18; i++) + { + fprintf (stderr, "[%02X]", payload[i]); + } + } + return false; } + + // Backtrack one place for a last go + return CDMRTrellisFixCode(savePoints, failPos - 1U, payload); +}