diff --git a/include/dsd.h b/include/dsd.h index 9443a0f..312a0b7 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -138,48 +138,6 @@ typedef struct uint8_t bytes[3]; } rs_12_9_checksum_t; -typedef struct -{ - char VoiceFrame[3][72]; /* 3 x 72 bit of voice per time slot frame */ - char Sync[48]; /* 48 bit of data or SYNC per time slot frame */ -}TimeSlotRawVoiceFrame_t; - - -typedef struct -{ - char DeInterleavedVoiceSample[3][4][24]; /* 3 x (4 x 24) deinterleaved bit of voice per time slot frame */ -}TimeSlotDeinterleavedVoiceFrame_t; - - -typedef struct -{ - int errs1[3]; /* 3 x errors #1 computed when demodulate the AMBE voice bit of the frame */ - int errs2[3]; /* 3 x errors #2 computed when demodulate the AMBE voice bit of the frame */ - char AmbeBit[3][49]; /* 3 x 49 bit of AMBE voice of the frame */ -}TimeSlotAmbeVoiceFrame_t; - -typedef struct -{ - unsigned int ProtectFlag; - unsigned int Reserved; - unsigned int FullLinkControlOpcode; - unsigned int FeatureSetID; - unsigned int ServiceOptions; - unsigned int GroupAddress; /* Destination ID or TG (in Air Interface format) */ - unsigned int SourceAddress; /* Source ID (in Air Interface format) */ - unsigned int DataValidity; /* 0 = All Full LC data are incorrect ; 1 = Full LC data are correct (CRC checked OK) */ - unsigned int LeftOvers; //what is the 8 bits for that isn't used -}FullLinkControlPDU_t; - -typedef struct -{ - TimeSlotRawVoiceFrame_t TimeSlotRawVoiceFrame[6]; /* A voice superframe contains 6 timeslot voice frame */ - TimeSlotDeinterleavedVoiceFrame_t TimeSlotDeinterleavedVoiceFrame[6]; - TimeSlotAmbeVoiceFrame_t TimeSlotAmbeVoiceFrame[6]; - FullLinkControlPDU_t FullLC; -} TimeSlotVoiceSuperFrame_t; - - //dPMR /* Could only be 2 or 4 */ #define NB_OF_DPMR_VOICE_FRAME_TO_DECODE 2 @@ -321,6 +279,7 @@ typedef struct int inverted_dpmr; int frame_dpmr; + short int dmr_mono; short int dmr_stereo; short int lrrp_file_output; @@ -528,12 +487,8 @@ typedef struct char slot1light[8]; char slot2light[8]; int directmode; - TimeSlotVoiceSuperFrame_t TS1SuperFrame; - TimeSlotVoiceSuperFrame_t TS2SuperFrame; char dmr_branding[25]; - uint8_t dmr_12_rate_sf[2][288]; //was 84, expanded to 288 to prevent possible crash if more comes in than expected - uint8_t dmr_34_rate_sf[2][288]; //was 96, expanded to 288 to prevent possible crash if more comes in than expected int dmr_stereo_payload[144]; //load up 144 dibit buffer for every single DMR TDMA frame uint8_t data_header_blocks[2]; //collect number of blocks to follow from data header per slot uint8_t data_header_padding[2]; //collect number of padding octets in last block per slot @@ -542,27 +497,23 @@ typedef struct uint8_t data_block_counter[2]; //counter for number of data blocks collected uint8_t data_p_head[2]; //flag for dmr proprietary header to follow + //new stuff below here + uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot + uint8_t dmr_pdu_sf[2][288]; //unified pdu 'superframe' //[slot][byte] + uint8_t data_block_crc_valid[2][25]; //flag each individual block as good crc on confirmed data + char dmr_embedded_signalling[2][6][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure) + + char dmr_cach_fragment[4][17]; //unsure of size, will need to check/verify + int dmr_cach_counter; //counter for dmr_cach_fragments 0-3; not sure if needed yet. + + //dmr talker alias new/fixed stuff + uint8_t dmr_alias_format[2]; //per slot + uint8_t dmr_alias_len[2]; //per slot + char dmr_alias_block_segment[2][4][7][16]; //2 slots, by 4 blocks, by up to 7 alias bytes that are up to 16-bit chars + dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame; - //These flags are used to known the DMR frame - //printing format (hex or binary) - int printDMRRawVoiceFrameHex; - int printDMRRawVoiceFrameBin; - int printDMRRawDataFrameHex; - int printDMRRawDataFrameBin; - int printDMRAmbeVoiceSampleHex; - int printDMRAmbeVoiceSampleBin; - - //These flags are used to known the dPMR frame - //orinting format (hex or binary) - int printdPMRRawVoiceFrameHex; - int printdPMRRawVoiceFrameBin; - int printdPMRRawDataFrameHex; - int printdPMRRawDataFrameBin; - int printdPMRAmbeVoiceSampleHex; - int printdPMRAmbeVoiceSampleBin; - unsigned char * dpmr_caller_id; unsigned char * dpmr_target_id; int dpmr_color_code; @@ -572,6 +523,8 @@ typedef struct short int dmr_ms_mode; unsigned int dmrburstL; unsigned int dmrburstR; + int dropL; + int dropR; unsigned long long int R; unsigned long long int RR; unsigned long long int H; @@ -654,6 +607,11 @@ typedef struct uint32_t nxdn_location_sys_code; uint16_t nxdn_location_site_code; + //dmr late entry mi + uint64_t late_entry_mi_fragment[2][7][3]; + + //char dmr_branding[25]; //may need higher value? + char dmr_branding_sub[25]; //Roman DMR End Call Alert Beep int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag @@ -733,13 +691,7 @@ typedef struct /* * function prototypes */ -void processDMRdata (dsd_opts * opts, dsd_state * state); -void processDMRvoice (dsd_opts * opts, dsd_state * state); -void dmrBSBootstrap (dsd_opts * opts, dsd_state * state); -void dmrBS (dsd_opts * opts, dsd_state * state); -void dmrMS (dsd_opts * opts, dsd_state * state); -void dmrMSData (dsd_opts * opts, dsd_state * state); -void dmrMSBootstrap (dsd_opts * opts, dsd_state * state); + void processdPMRvoice (dsd_opts * opts, dsd_state * state); void processAudio (dsd_opts * opts, dsd_state * state); void processAudioR (dsd_opts * opts, dsd_state * state); @@ -799,8 +751,7 @@ void resumeScan (dsd_opts * opts, dsd_state * state); int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync); void upsample (dsd_state * state, float invalue); void processDSTAR (dsd_opts * opts, dsd_state * state); -void processNXDNVoice (dsd_opts * opts, dsd_state * state); -void processNXDNData (dsd_opts * opts, dsd_state * state); + void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo); void processHDU (dsd_opts * opts, dsd_state * state); void processLDU1 (dsd_opts * opts, dsd_state * state); @@ -836,14 +787,14 @@ void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[3 void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType); void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]); -//OP25 NXDN CRC functions +//OP25 NXDN CRC functions static inline int load_i(const uint8_t val[], int len); static uint8_t crc6(const uint8_t buf[], int len); static uint16_t crc12f(const uint8_t buf[], int len); static uint16_t crc15(const uint8_t buf[], int len); static uint16_t crc16cac(const uint8_t buf[], int len); -/* NXDN functions */ +/* NXDN Convolution functions */ void CNXDNConvolution_start(void); void CNXDNConvolution_decode(uint8_t s0, uint8_t s1); void CNXDNConvolution_chainback(unsigned char* out, unsigned int nBits); @@ -867,8 +818,6 @@ void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message void nxdn_location_id_handler (dsd_state * state, uint32_t location_id); void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state); -void printdPMRAmbeVoiceSample(dsd_opts * opts, dsd_state * state); -void printdPMRRawVoiceFrame (dsd_opts * opts, dsd_state * state); //dPMR functions void ScrambledPMRBit(uint32_t * LfsrValue, uint8_t * BufferIn, uint8_t * BufferOut, uint32_t NbOfBitToScramble); @@ -878,9 +827,6 @@ uint8_t CRC8BitdPMR(uint8_t * BufferIn, uint32_t BitLength); void ConvertAirInterfaceID(uint32_t AI_ID, uint8_t ID[8]); int32_t GetdPmrColorCode(uint8_t ChannelCodeBit[24]); -void ProcessDMR (dsd_opts * opts, dsd_state * state); -void DMRDataFrameProcess(dsd_opts * opts, dsd_state * state); -void DMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state); //BPTC (Block Product Turbo Code) functions void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output); uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3]); @@ -893,26 +839,49 @@ uint8_t rs_12_9_check_syndrome(rs_12_9_poly_t *syndrome); rs_12_9_correct_errors_result_t rs_12_9_correct_errors(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome, uint8_t *errors_found); rs_12_9_checksum_t *rs_12_9_calc_checksum(rs_12_9_codeword_t *codeword); -//SYNC DMR data extraction functions -void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); -void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); -void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state); +//DMR CRC Functions uint16_t ComputeCrcCCITT(uint8_t * DMRData); uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask); 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 ProcessReservedData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); -void ProcessUnifiedData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +//new simplified dmr functions +void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst); +void dmr_data_sync (dsd_opts * opts, dsd_state * state); +void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors); +void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type); +void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors); +void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]); +uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]); + +//Embedded Alias and GPS +void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]); +void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]); +void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]); + +//"DMR STEREO" +void dmrBSBootstrap (dsd_opts * opts, dsd_state * state); +void dmrBS (dsd_opts * opts, dsd_state * state); +void dmrMS (dsd_opts * opts, dsd_state * state); +void dmrMSData (dsd_opts * opts, dsd_state * state); +void dmrMSBootstrap (dsd_opts * opts, dsd_state * state); + +//dmr data header and multi block types (header, 1/2, 3/4, 1, Unified) +void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors); +void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type); +void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[]); +void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[]); +uint8_t dmr_lrrp_check (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[]); + +//dmr alg stuff +void dmr_alg_reset (dsd_opts * opts, dsd_state * state); +void dmr_alg_refresh (dsd_opts * opts, dsd_state * state); +void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, char ambe_fr[4][24], char ambe_fr2[4][24], char ambe_fr3[4][24]); +void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state); + +//DMR FEC/CRC from Boatbod - OP25 +bool Hamming17123(uint8_t* d); +uint8_t crc8(uint8_t bits[], unsigned int len); +bool crc8_ok(uint8_t bits[], unsigned int len); //LFSR code courtesy of https://github.com/mattames/LFSR/ void LFSR(dsd_state * state); diff --git a/src/dmr_block.c b/src/dmr_block.c new file mode 100644 index 0000000..a38eb78 --- /dev/null +++ b/src/dmr_block.c @@ -0,0 +1,392 @@ +/*------------------------------------------------------------------------------- + * dmr_block.c + * DMR Data Header and Data Block Assembly/Handling + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + +#include "dsd.h" + +void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors) +{ + uint32_t i, j, k; + uint8_t slot = state->currentslot; + + //clear out unified pdu 'superframe' slot + for (short int i = 0; i < 288; i++) + { + state->dmr_pdu_sf[slot][i] = 0; + } + + //TODO: ONLY RUN ON GOOD CRC? + + //collect relevant data header info, figure out format, and grab appropriate info from it + if (state->data_p_head[slot] == 0) + { + fprintf (stderr, "%s ", KGRN); + state->data_block_counter[slot] = 1; //reset block counter to 1 + state->data_header_format[slot] = dheader[0]; //collect the entire byte, we can check group or individual, response requested as well on this + state->data_header_sap[slot] = (dheader[1] & 0xF0) >> 4; + + if ( (state->data_header_format[slot] & 0xF) == 0x2) + { + state->data_conf_data[slot] = 0; //flag as unconfirmed data, no need for additional CRC/Serial checks + state->data_header_padding[slot] = dheader[1] & 0xF; //number of padding octets on last block + state->data_header_blocks[slot] = dheader[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data + fprintf (stderr, "\n Unconfirmed Data Header: DPF %01X - SAP %02X - Block Count %02X - Padding Octets %02X", + state->data_header_format[slot] & 0xF, state->data_header_sap[slot], + state->data_header_blocks[slot], state->data_header_padding[slot] ); + } + + if ( (state->data_header_format[slot] & 0xF) == 0x3) + { + state->data_conf_data[slot] = 1; //set flag to indicate the following blocks are confirmed data so we know to run additional CRC etc on it. + state->data_header_padding[slot] = dheader[1] & 0xF; //number of padding octets on last block + state->data_header_blocks[slot] = dheader[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data + fprintf (stderr, "\n Confirmed Data Header: DPF %01X - SAP %02X - Block Count %02X - Padding Octets %02X", + state->data_header_format[slot] & 0xF, state->data_header_sap[slot], + state->data_header_blocks[slot], state->data_header_padding[slot] ); + } + + if ( (state->data_header_format[slot] & 0xF) == 0xD) //DD_HEAD + { + state->data_conf_data[slot] = 0; + state->data_header_padding[slot] = dheader[7] & 0xF; + state->data_header_blocks[slot] = ( (dheader[0] & 0x30) | ((dheader[1] & 0xF) >> 0) ); //what a pain MSB | LSB + fprintf (stderr, "\n Short Data - Defined: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X", + state->data_header_format[slot] & 0xF, state->data_header_sap[slot], + state->data_header_blocks[slot], state->data_header_padding[slot] ); + } + + if ( (state->data_header_format[slot] & 0xF) == 0xE) //SP_HEAD or R_HEAD + { + state->data_conf_data[slot] = 0; + state->data_header_padding[slot] = dheader[7] & 0xF; + state->data_header_blocks[slot] = ( (dheader[0] & 0x30) | ((dheader[1] & 0xF) >> 0) ); + fprintf (stderr, "\n Short Data - Raw or Precoded: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X", + state->data_header_format[slot] & 0xF, state->data_header_sap[slot], + state->data_header_blocks[slot], state->data_header_padding[slot] ); + } + + + } + + //do we still need this? since we have ample PDU storage + if (state->data_header_blocks[slot] > 7) + { + state->data_header_blocks[slot] = 7; + } + + fprintf (stderr, "%s ", KNRM); + //end collecting data header info + + fprintf (stderr, "%s ", KMAG); + + if (state->data_header_sap[slot] == 0x4 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n IP Data - Source: "); + fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] ); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] ); + + sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ", + ( (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]), + ( (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]) ); + + + state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]; + + } + + if (state->data_header_sap[slot] == 0x0 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n Unified Data Transport - Source: "); + fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] ); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] ); + + sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ", + ( (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]), + ( (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]) ); + + state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]; + + } + + if (state->data_header_sap[slot] == 0x9 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n Proprietary Packet Data - Source: "); + fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] ); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] ); + + sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ", + ( (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]), + ( (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]) ); + + state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]; + + } + + if (state->data_header_sap[slot] == 0x2 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n TCP/IP Header Compression Data - Source: "); + fprintf (stderr, "[%d]", dheader[3]); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", dheader[2]); + + sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ", + dheader[3], dheader[2] ); + + state->dmr_lrrp_source[slot] = dheader[3]; + + } + + if (state->data_header_sap[slot] == 0x3 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n UDP/IP Header Compression Data - Source: "); + fprintf (stderr, "[%d]", dheader[3]); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", dheader[2]); + + sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ", + dheader[3], dheader[2] ); + + state->dmr_lrrp_source[slot] = dheader[3]; + + } + + if (state->data_header_sap[slot] == 0x5 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n ARP - Address Resolution Protocol "); + } + + if ( (state->data_header_format[slot] & 0xF ) == 0xD && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n Short Data - Defined - Source: "); + fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] ); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] ); + } + + if ( (state->data_header_format[slot] & 0xF) == 0xE && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n Short Data - Raw or Status/Precoded - Source: "); + fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] ); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] ); + } + + if ( (state->data_header_format[slot] & 0xF ) == 0x1 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n Response Packet - Source: "); + fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] ); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] ); + } + + if ( (state->data_header_format[slot] & 0xF ) == 0x0 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n Unified Data Transport - Source: "); + fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] ); + fprintf (stderr, " Destination: "); + fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] ); + } + + if ( (state->data_header_format[slot] & 0x40) == 0x40 && state->data_p_head[slot] == 0) //check response req bit + { + fprintf (stderr, "\n Response Requested - "); + fprintf (stderr, " Source:"); + fprintf (stderr, " [%d]", (dheader[2] <<16 ) + (dheader[3] << 8) + dheader[4] ); + fprintf (stderr, " Destination:"); + fprintf (stderr, " [%d]", (dheader[5] <<16 ) + (dheader[6] <<8 ) + dheader[7] ); + } + + //if proprietary header was flagged by the last data header, then process data differently + if (state->data_p_head[slot] == 1) + { + fprintf (stderr, "\n Proprietary Data Header: SAP %01X - Format %01X - MFID %02X", + (dheader[0] & 0xF0) >> 4, dheader[0] & 0xF, dheader[1] ); + + state->data_p_head[slot] = 0; + state->data_header_sap[slot] = 0; //reset this to zero so we don't trip the condition below + state->data_block_counter[slot]++; //increment the counter since this counts against the data blocks + + //set overarching manufacturer in use when non-standard feature id set is up + if (dheader[1] != 0) state->dmr_mfid = dheader[1]; + + //assign prop header pdu to 'superframe' + uint8_t blocks = state->data_header_blocks[slot] - 1; + for(i = 0; i < 12; i++) + { + state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i]; + } + } + + //only set this flag after everything else is processed + if (state->data_header_sap[slot] == 0x9 && state->data_p_head[slot] == 0) + { + fprintf (stderr, "\n Proprietary Packet Data Incoming "); + state->data_p_head[slot] = 1; //flag that next data header will be a proprietary data header + } + fprintf (stderr, "%s ", KNRM); + + //let user know the data header may have errors + fprintf (stderr, "%s", KRED); + if (CRCCorrect == 1) ; //CRCCorrect 1 is good, else is bad CRC; no print on good + else if(IrrecoverableErrors == 0) fprintf(stderr, " (FEC OK)"); + else fprintf(stderr, " (FEC/CRC ERR)"); + fprintf (stderr, "%s", KNRM); + +} + +//assemble the blocks as they come in, shuffle them into the unified dmr_pdu_sf +void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type) +{ + int i, j, k; + uint8_t lb = 0; //mbc last block + uint8_t pf = 0; //mbc protect flag + uint8_t is_conf_data = 0; //internal flag to see if type 1 blocks contain confirmed data crcs and serials + uint8_t slot = state->currentslot; + int blocks; + uint8_t blockcounter = state->data_block_counter[slot]; + + //crc specific variables + uint8_t len = 24; //len of completed message needing crc32 number of blocks*block_len - 12? + uint8_t crclen = 32; //len of the crc32 (obviously) + uint8_t start = 12; //starting position (+12 offset loaded up data header) + uint8_t n = 12; //number of bytes per block + + //TODO: CRC check on Header, Blocks and full frames as appropriate + uint32_t CRCCorrect = 0; + uint32_t CRCComputed = 0; + uint32_t CRCExtracted = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t dmr_pdu_sf_bits[18*8*8]; //8 blocks at 18 bytes at 8 bits //just a large value to have plenty storage space + + if (type == 1) blocks = state->data_header_blocks[slot] - 1; + if (type == 2) blocks = state->data_block_counter[slot]; + + //sanity check, setting block_len and block values to sane numbers in case of missing header, else could overload array (crash) or print out + if (blocks < 1) blocks = 1; //changed blocks from uint8_t to int + if (blocks > 8) blocks = 8; + if (block_len == 0) block_len = 18; + if (block_len > 24) block_len = 24; + + //TODO: add CRC/FEC validation to each block and each confirmed data block as well - type 1 + if (type == 1) + { + //type 1 data block, shuffle method + for (j = 0; j < blocks; j++) //6 + { + for (i = 0; i < block_len; i++) //block_len + { + state->dmr_pdu_sf[slot][i+block_len*j] = state->dmr_pdu_sf[slot][i+block_len*(j+1)]; + } + } + + for (i = 0; i < block_len; i++) + { + state->dmr_pdu_sf[slot][i+(blocks*block_len)] = block_bytes[i]; + } + //time to send the completed 'superframe' to the DMR PDU message handler + if (state->data_block_counter[slot] == state->data_header_blocks[slot]) + { + //TODO: CRC32 on completed messages + dmr_pdu (opts, state, state->dmr_pdu_sf[slot]); + } + } + + + //type 2 - MBC header and MBC continuation blocks + if (type == 2) + { + //sanity check (marginal signal, bad decodes, etc) + if (state->data_block_counter[slot] > 8) state->data_block_counter[slot] = 8; + + //Type 2 data block, additive method + for (i = 0; i < block_len; i++) + { + state->dmr_pdu_sf[slot][i+(blockcounter*block_len)] = block_bytes[i]; + } + + memset (dmr_pdu_sf_bits, 0, sizeof(dmr_pdu_sf_bits)); + + lb = block_bytes[0] >> 7; //last block flag + pf = (block_bytes[0] >> 6) & 1; + + if (lb == 1) //last block arrived, time to send to cspdu decoder + { + for(i = 0, j = 0; i < 12*4; i++, j+=8) // + { + dmr_pdu_sf_bits[j + 0] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01; + dmr_pdu_sf_bits[j + 1] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01; + dmr_pdu_sf_bits[j + 2] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01; + dmr_pdu_sf_bits[j + 3] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01; + dmr_pdu_sf_bits[j + 4] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01; + dmr_pdu_sf_bits[j + 5] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01; + dmr_pdu_sf_bits[j + 6] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01; + dmr_pdu_sf_bits[j + 7] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01; + } + + //TODO: CRC check on Header and full frames as appropriate + + //shim these values for now + CRCCorrect = 1; + IrrecoverableErrors = 0; + + dmr_cspdu (opts, state, dmr_pdu_sf_bits, state->dmr_pdu_sf[slot], CRCCorrect, IrrecoverableErrors); + + } + } + + //Full Super Frame Type 1 - Debug Output + if (opts->payload == 1 && type == 1 && state->data_block_counter[slot] == state->data_header_blocks[slot]) + { + fprintf (stderr, "%s",KGRN); + fprintf (stderr, "\n Multi Block PDU Superframe - Slot [%d]\n ", slot+1); + for (i = 0; i < ((blocks+1)*block_len); i++) + { + fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]); + if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71 || i == 83 || i == 95) + { + fprintf (stderr, "\n "); + } + } + fprintf (stderr, "%s ", KNRM); + } + + //Full Super Frame MBC - Debug Output + if (opts->payload == 1 && type == 2 && lb == 1) + { + fprintf (stderr, "%s",KGRN); + fprintf (stderr, "\n MBC Multi Block PDU Superframe - Slot [%d]\n ", slot+1); + for (i = 0; i < ((blocks+1)*block_len); i++) + { + fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]); + if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71 || i == 83 || i == 95) + { + fprintf (stderr, "\n "); + } + } + fprintf (stderr, "%s ", KNRM); + } + + state->data_block_counter[slot]++; //increment block counter + + if (type == 2 && lb == 1) + { + state->data_block_counter[slot] = 0; //reset the block counter (MBCs) + + //clear out unified pdu 'superframe' slot + for (short int i = 0; i < 288; i++) + { + state->dmr_pdu_sf[slot][i] = 0; + } + + state->data_block_crc_valid[slot][0] = 0; //Zero Out MBC Header Block CRC Valid + + } + +} \ No newline at end of file diff --git a/src/dmr_bs.c b/src/dmr_bs.c index 873351d..9cdaaa1 100644 --- a/src/dmr_bs.c +++ b/src/dmr_bs.c @@ -1,3 +1,11 @@ +/*------------------------------------------------------------------------------- + * dmr_bs.c + * DMR BS Voice Handling and Data Gathering Routines - "DMR STEREO" + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + #include "dsd.h" #include "dmr_const.h" @@ -7,32 +15,37 @@ void dmrBS (dsd_opts * opts, dsd_state * state) { int i, j, k, l, dibit; int *dibit_p; - char ambe_fr[4][24] = {0}; - char ambe_fr2[4][24] = {0}; - char ambe_fr3[4][24] = {0}; + + char ambe_fr[4][24]; + char ambe_fr2[4][24]; + char ambe_fr3[4][24]; - const int *w, *x, *y, *z; - char sync[25] = {0}; - char syncdata[48] = {0}; - //char cachdata[13] = {0}; - int mutecurrentslot; - int msMode; - char cc[4]; - unsigned char EmbeddedSignalling[16] = {0}; - int EmbeddedSignallingOk; - unsigned int internalcolorcode; - int internalslot; + //redundancy check (carrier signal loss event) char redundancyA[36]; char redundancyB[36]; - unsigned short int vc1; - unsigned short int vc2; - int cach_okay = 0; - //cach fec - char cachdata[25] = {0}; //increased from 24 to 25 to see if this fixes ubuntu 32 bug - int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23}; + //memcpy of ambe_fr for late entry + char m1[4][24]; + char m2[4][24]; + char m3[4][24]; + + const int *w, *x, *y, *z; + char sync[25]; + char syncdata[48]; + char EmbeddedSignalling[16]; + uint8_t emb_ok = 0; + uint8_t tact_okay = 0; + uint8_t cach_err = 0; + uint8_t internalslot; + uint8_t vc1; + uint8_t vc2; + + //would be ideal to grab all dibits and break them into bits to pass to new data handler? + uint8_t dummy_bits[196]; + memset (dummy_bits, 0, sizeof(dummy_bits)); + //add time to mirror printFrameSync time_t now; char * getTime(void) //get pretty hh:mm:ss timestamp @@ -63,10 +76,21 @@ void dmrBS (dsd_opts * opts, dsd_state * state) short int loop = 1; short int skipcount = 0; + //cach + char cachdata[25]; + int cachInterleave[24] = + {0, 7, 8, 9, 1, 10, + 11, 12, 2, 13, 14, + 15, 3, 16, 4, 17, 18, + 19, 5, 20, 21, 22, 6, 23 + }; + + //cach tact bits + uint8_t tact_bits[7]; + //Run Loop while the getting is good while (loop == 1) { - // CACH internalslot = -1; //reset here so we know if this value is being set properly for(i = 0; i < 12; i++) { @@ -77,30 +101,23 @@ void dmrBS (dsd_opts * opts, dsd_state * state) cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0 } - //decode and correct cach and compare - cach_okay = 69; - if ( Hamming_7_4_decode (cachdata) ) //see if we need to de-interleave this...probably do. + for (i = 0; i < 7; i++) { - cach_okay = 1; + tact_bits[i] = cachdata[i]; } - if (cach_okay == 1) + + //disabled for dmr_cach testing + tact_okay = 0; + if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1; + if (tact_okay != 1) { - //fprintf (stderr, "CACH Okay "); - } - if (cach_okay != 1) - { - //fprintf (stderr, "CACH FEC Error %d", cach_okay); if (opts->aggressive_framesync == 1) { goto END; } - } - state->currentslot = cachdata[1]; - internalslot = cachdata[1]; - - //this cach fec seems to work quite well, really helps on shaky signals + internalslot = state->currentslot = tact_bits[1]; //Setup for first AMBE Frame //Interleave Schedule @@ -115,6 +132,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) dibit = getDibit(opts, state); state->dmr_stereo_payload[i+12] = dibit; redundancyA[i] = dibit; + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr[*y][*z] = (1 & dibit); // bit 0 @@ -134,11 +152,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state) { goto END; } - // end redundancy test, set B to A - for(i = 0; i < 36; i++) - { - redundancyB[i] = redundancyA[i]; - } + + //end redundancy test, set B to A + memcpy (redundancyB, redundancyA, sizeof (redundancyA)); //Setup for Second AMBE Frame //Interleave Schedule @@ -162,90 +178,39 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } - //short int l = 0; //do I still use this? - // signaling data or sync - long long int late_entry_pi[24] = {0}; - short int m = 0; + //signaling data or sync for(i = 0; i < 24; i++) { dibit = getDibit(opts, state); - state->dmr_stereo_payload[i+66] = dibit; + sync[i] = (dibit | 1) + 48; //how does this work again? + syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1 - syncdata[(2*i)+1] = (1 & dibit); // bit 0 - sync[i] = (dibit | 1) + 48; + syncdata[(2*i)+1] = (1 & dibit); // bit 0 - if (i < 4 || i > 19) - { - // fprintf(stderr, "\n EMB = "); - EmbeddedSignalling[(2*i)] = (1 & (dibit >> 1)); // bit 1 - //fprintf (stderr, "%02b", dibit); - EmbeddedSignalling[(2*i)+1] = (1 & dibit); // bit 0 - - } - - //Used for ProcessVoiceBurstSync + //embedded link control if(internalslot == 0 && vc1 > 1 && vc1 < 6) //grab on vc1 values 2-5 B C D and E { - /* Time slot 1 superframe buffer filling => SYNC data */ - state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2+1] = (1 & dibit); // bit 0 + state->dmr_embedded_signalling[internalslot][vc1-1][i*2] = (1 & (dibit >> 1)); // bit 1 + state->dmr_embedded_signalling[internalslot][vc1-1][i*2+1] = (1 & dibit); // bit 0 } + if(internalslot == 1 && vc2 > 1 && vc2 < 6) //grab on vc2 values 2-5 B C D and E { - /* Time slot 2 superframe buffer filling => SYNC data */ - state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2+1] = (1 & dibit); // bit 0 + state->dmr_embedded_signalling[internalslot][vc2-1][i*2] = (1 & (dibit >> 1)); // bit 1 + state->dmr_embedded_signalling[internalslot][vc2-1][i*2+1] = (1 & dibit); // bit 0 } } - sync[24] = 0; - EmbeddedSignallingOk = -1; - if(QR_16_7_6_decode(EmbeddedSignalling)) - { - EmbeddedSignallingOk = 1; - } + for(i = 0; i < 8; i++) EmbeddedSignalling[i] = syncdata[i]; + for(i = 0; i < 8; i++) EmbeddedSignalling[i + 8] = syncdata[i + 40]; - internalcolorcode = 69; //set so we know if this value is being set properly - - if( EmbeddedSignallingOk == 1 ) //don't set on 1? - { - //state->color_code = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); - internalcolorcode = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); - state->color_code_ok = EmbeddedSignallingOk; - - //Power Indicator, not the other PI (header) - state->PI = (unsigned int)EmbeddedSignalling[4]; - state->PI_ok = EmbeddedSignallingOk; - - //Link Control Start Stop Indicator - state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]); - state->LCSS_ok = EmbeddedSignallingOk; - - for (i = 0; i < 8; i++) - { - //fprintf (stderr, " %b", EmbeddedSignalling[i]); - } - - } - //else skipcount++; - else - { - for (i = 0; i < 8; i++) - { - //fprintf (stderr, " %b", EmbeddedSignalling[i]); - } - } //Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling for(i = 0; i < 18; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - //dibit = (dibit ^ 2); - } state->dmr_stereo_payload[i+90] = dibit; ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr2[*y][*z] = (1 & dibit); // bit 0 @@ -268,10 +233,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state) for(i = 0; i < 36; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - //dibit = (dibit ^ 2); - } state->dmr_stereo_payload[i+108] = dibit; ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr3[*y][*z] = (1 & dibit); // bit 0 @@ -286,305 +247,137 @@ void dmrBS (dsd_opts * opts, dsd_state * state) //reset vc counters to 1 if new voice sync frame on each slot if ( strcmp (sync, DMR_BS_VOICE_SYNC) == 0) { - if (internalslot == 0) - { - vc1 = 1; - state->DMRvcL = 0; //reset here if internal sync forces reset - } - if (internalslot == 1) - { - vc2 = 1; - state->DMRvcR = 0; //reset here if internal sync forces reset - } + if (internalslot == 0) vc1 = 1; + if (internalslot == 1) vc2 = 1; } - // if( strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0) - // { - // fprintf (stderr,"%s ", getTime()); - // fprintf (stderr, " Sync: DMR TDMA Direct Mode TS 1 \n"); - // goto SKIP; - // } - // - // if( strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0) - // { - // fprintf (stderr,"%s ", getTime()); - // fprintf (stderr, " Sync: DMR TDMA Direct Mode TS 2 \n"); - // goto SKIP; - // } - //check for sync pattern here after collected the rest of the payload, decide what to do with it if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 ) { + fprintf (stderr,"%s ", getTime()); if (internalslot == 0) { - sprintf(state->slot1light, "[slot1]"); - sprintf(state->slot2light, " slot2 "); - if (opts->inverted_dmr == 0) { fprintf (stderr,"Sync: +DMR "); } else fprintf (stderr,"Sync: -DMR "); - //constantly reset the vc counter to 1 each data frame in anticipation of new voice frame + vc1 = 1; - } if (internalslot == 1) { - sprintf(state->slot2light, "[slot2]"); - sprintf(state->slot1light, " slot1 "); - if (opts->inverted_dmr == 0) { fprintf (stderr,"Sync: +DMR "); } else fprintf (stderr,"Sync: -DMR "); - //constantly reset the vc counter to 1 each data frame in anticipation of new voice frame + vc2 = 1; } - processDMRdata (opts, state); - skipcount++; //after 2 data frames, drop back to getFrameSync and process subsequent data with processDMRdata - goto SKIP; - } - - //find way to mitigate or correct coming back here after leaving in inverted signal - if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 && opts->inverted_dmr == 1) - { + dmr_data_sync (opts, state); skipcount++; goto SKIP; } - //extra check to see if we have missed a voice/data frame sync at this point and then exit if required - if (1 == 1) //opts->aggressive_framesync - { - //extremely aggressive - if ( vc1 > 7 || vc2 > 7 ) - { - goto END; - } - - } - //only play voice on no data sync - if (strcmp (sync, DMR_BS_DATA_SYNC) != 0) + if (strcmp (sync, DMR_BS_DATA_SYNC) != 0) //we already have a tact ecc check, so we won't get here without that, see if there is any other eccs we can run just to make sure { - if (EmbeddedSignallingOk == 0) + //check the embedded signalling, if bad at this point, we probably aren't quite in sync + if(QR_16_7_6_decode(EmbeddedSignalling)) emb_ok = 1; + else emb_ok = 0; + + //disable the goto END; if this causes more problems than fixing on late entry dual voices i.e., lots of forced resyncs + if ( (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && emb_ok == 0) goto END; //fprintf (stderr, "EMB BAD? "); + else if (emb_ok == 1) { - //goto END; + uint8_t cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); + uint8_t power = EmbeddedSignalling[4]; + uint8_t lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]); } + + skipcount = 0; //reset skip count if processing voice frames fprintf (stderr,"%s ", getTime()); + //simplifying things + char polarity[3]; + char light[18]; + uint8_t vc; if (internalslot == 0) { - state->dmrburstL = 16; //use 16 for Voice? - - if (opts->inverted_dmr == 0) - { - fprintf (stderr,"Sync: +DMR [SLOT1] slot2 | | DMRSTEREO | VC%d ",vc1); - if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - } - if (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - fprintf (stderr, "%s", KNRM); - } - fprintf (stderr, "\n"); - } - else - { - fprintf (stderr,"Sync: -DMR [SLOT1] slot2 | | DMRSTEREO | VC%d ",vc1); - if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - } - if (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - fprintf (stderr, "%s", KNRM); - } - fprintf (stderr, "\n"); - } - } - - if (internalslot == 1) + state->dmrburstL = 16; + vc = vc1; + sprintf (light, "%s", " [SLOT1] slot2 "); + } + else { - state->dmrburstR = 16; //use 16 for Voice? - if (opts->inverted_dmr == 0) - { - fprintf (stderr,"Sync: +DMR slot1 [SLOT2] | | DMRSTEREO | VC%d ",vc2); - if (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - } - if (state->DMRvcR == 0 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - fprintf (stderr, "%s", KNRM); - } - fprintf (stderr, "\n"); - } - else - { - fprintf (stderr,"Sync: -DMR slot1 [SLOT2] | | DMRSTEREO | VC%d ",vc2); - if (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - } - if (state->DMRvcR == 0 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - fprintf (stderr, "%s", KNRM); - } - fprintf (stderr, "\n"); - } - } - if (internalslot == 0 && vc1 == 6) //presumably when full (and no sync issues) + state->dmrburstR = 16; + vc = vc2; + sprintf (light, "%s", " slot1 [SLOT2] "); + } + if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+"); + else sprintf (polarity, "%s", "-"); + + fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC%d ", polarity, light, state->dmr_color_code, vc); + + if (internalslot == 0 && vc1 == 6) { - //process voice burst - ProcessVoiceBurstSync(opts, state); + //process embedded link control fprintf (stderr, "\n"); + dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB); } - if (internalslot == 1 && vc2 == 6) //presumably when full (and no sync issues) + if (internalslot == 1 && vc2 == 6) { - //process voice burst - ProcessVoiceBurstSync(opts, state); + //process embedded link control fprintf (stderr, "\n"); + dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB); } + if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here + + //copy ambe_fr frames first, running process mbe will correct them, + //but this also leads to issues extracting good le mi values when + //we go to do correction on them there too + memcpy (m1, ambe_fr, sizeof(m1)); + memcpy (m2, ambe_fr2, sizeof(m2)); + memcpy (m3, ambe_fr3, sizeof(m3)); + processMbeFrame (opts, state, NULL, ambe_fr, NULL); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); - if (internalslot == 0 && vc1 == 6) - { - state->DMRvcL = 0; - if (state->payload_algid >= 0x21) - { + cach_err = dmr_cach (opts, state, cachdata); + fprintf (stderr, "\n"); - if (state->payload_mi != 0 && state->payload_algid >= 0x21) - { - LFSR(state); - } - fprintf (stderr, "\n"); - } - } + // run alg refresh after vc6 ambe processing + if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state); + if (internalslot == 1 && vc2 == 6) dmr_alg_refresh (opts, state); - if (internalslot == 1 && vc2 == 6) - { - state->DMRvcR = 0; - if (state->payload_algidR >= 0x21) - { - if (state->payload_miR != 0 && state->payload_algidR >= 0x21) - { - LFSR(state); - } - fprintf (stderr, "\n"); - } - } + dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3); - if (internalslot == 0) - { - vc1++; - } - if (internalslot == 1) - { - vc2++; - } + //increment the vc counters + if (internalslot == 0) vc1++; + if (internalslot == 1) vc2++; + + //reset err checks + cach_err = 1; + tact_okay = 0; + emb_ok = 0; } - // recalibrate center/umid/lmid, not sure this helps or does anything particularly in this case - state->center = ((state->max) + (state->min)) / 2; - state->umid = (((state->max) - state->center) * 5 / 8) + state->center; - state->lmid = (((state->min) - state->center) * 5 / 8) + state->center; - - //Escape conditions to break the loop - //7 seems optimal, allows for an extra frame each in case of late entry on dual voices - if ( (vc1 > 7 && vc2 > 7) ) - { - goto END; - } - //14 probably allows a few more in case of a bit of jitter but eventually breaks loop (1 second?) - if ( (vc1 > 14 || vc2 > 14) ) - { - goto END; - } - - //earlier skip conditions teleport us here to process further skip conditions before restarting while loop SKIP: - if (skipcount > 2) //after 2 consecutive data frames, drop back to getFrameSync and process with processDMRdata + if (skipcount > 2) //after 2 consecutive data frames, drop back to getFrameSync and process with dmr_data_sync { + //set tests to all good so we don't get a bogus/redundant voice error + cach_err = 0; + tact_okay = 1; + emb_ok = 1; goto END; } @@ -595,26 +388,37 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } } // while loop - //Teleport here on END condition, set or reset variables and return to look for new frame sync + END: state->dmr_stereo = 0; + state->errs = 0; + state->errs2 = 0; state->errs2R = 0; state->errs2 = 0; - //if we have a cach err, then produce sync pattern/err message - if (cach_okay != 1) + //if we have a tact or emb err, then produce sync pattern/err message + if (tact_okay != 1 || emb_ok != 1) { fprintf (stderr,"%s ", getTime()); fprintf (stderr,"Sync: DMR "); fprintf (stderr, "%s", KRED); - fprintf (stderr, "| ** VOICE CACH ERR ** "); + fprintf (stderr, "| VOICE CACH/EMB ERR"); fprintf (stderr, "%s", KNRM); - //run LFSR if either slot had an active MI in it. - state->currentslot = 0; - if (state->payload_algid >= 0x21) LFSR(state); - state->currentslot = 1; - if (state->payload_algidR >= 0x21) LFSR(state); fprintf (stderr, "\n"); + //run LFSR if either slot had an active MI in it. + if (state->payload_algid >= 0x21) + { + state->currentslot = 0; + LFSR(state); + fprintf (stderr, "\n"); + } + if (state->payload_algidR >= 0x21) + { + state->currentslot = 1; + LFSR(state); + fprintf (stderr, "\n"); + } + } } @@ -624,22 +428,28 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) { int i, j, k, l, dibit; int *dibit_p; - char ambe_fr[4][24] = {0}; - char ambe_fr2[4][24] = {0}; - char ambe_fr3[4][24] = {0}; + char ambe_fr[4][24]; + char ambe_fr2[4][24]; + char ambe_fr3[4][24]; + + //memcpy of ambe_fr for late entry + char m1[4][24]; + char m2[4][24]; + char m3[4][24]; + const int *w, *x, *y, *z; char sync[25]; - char syncdata[48]; - int mutecurrentslot; - int msMode; - char cc[4]; - unsigned char EmbeddedSignalling[16]; - unsigned int EmbeddedSignallingOk; + uint8_t tact_okay = 0; + uint8_t cach_err = 0; - //cach fec - char cachdata[25] = {0}; //increased from 24 to 25 to see if this fixes ubuntu 32 bug - int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23}; + char cachdata[25]; + int cachInterleave[24] = + {0, 7, 8, 9, 1, 10, + 11, 12, 2, 13, 14, + 15, 3, 16, 4, 17, 18, + 19, 5, 20, 21, 22, 6, 23 + }; //add time to mirror printFrameSync time_t now; char * getTime(void) //get pretty hh:mm:ss timestamp @@ -678,27 +488,24 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0 } - //decode and correct cach and compare - int cach_okay = 69; - if ( Hamming_7_4_decode (cachdata) ) //see if we need to de-interleave this...probably do. + //cach tact bits + uint8_t tact_bits[7]; + for (i = 0; i < 7; i++) { - cach_okay = 1; + tact_bits[i] = cachdata[i]; } - if (cach_okay == 1) + + //decode and correct tact and compare + if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1; + if (tact_okay != 1) { - //fprintf (stderr, "CACH Okay "); - } - if (cach_okay != 1) - { - //fprintf (stderr, "CACH FEC Error %d", cach_okay); if (opts->aggressive_framesync == 1) { goto END; } - } - state->currentslot = cachdata[1]; + state->currentslot = tact_bits[1]; //Setup for first AMBE Frame @@ -751,12 +558,8 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) sync[i] = (dibit | 1) + 48; } sync[24] = 0; - //this method seems to work to make sure we aren't in a data sync especially when inverted signal - //consider only testing this when inverted signal if this causes issues with sync later on - if ( strcmp (sync, DMR_BS_VOICE_SYNC) != 0) - { - goto END; - } + + if ( strcmp (sync, DMR_BS_VOICE_SYNC) != 0) goto END; //Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling for(i = 0; i < 18; i++) @@ -795,95 +598,65 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) } fprintf (stderr,"%s ", getTime()); - if (opts->inverted_dmr == 0) - { - fprintf (stderr,"Sync: +DMR | Frame Sync | DMRSTEREO | VC1 "); - if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) || - (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) ) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); + char polarity[3]; + char light[18]; - } - if ( (state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) || - (state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) ) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - fprintf (stderr, "%s", KNRM); - } - fprintf (stderr, "\n"); - } + if (state->currentslot == 0) + { + sprintf (light, "%s", " [SLOT1] slot2 "); + } else { - fprintf (stderr,"Sync: -DMR | Frame Sync | DMRSTEREO | VC1 "); - if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) || - (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) ) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); + sprintf (light, "%s", " slot1 [SLOT2] "); + } + if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+"); + else sprintf (polarity, "%s", "-"); - } - if ( (state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) || - (state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) ) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - fprintf (stderr, "%s", KNRM); - } - fprintf (stderr, "\n"); - } + fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC1*", polarity, light, state->dmr_color_code); - state->DMRvcL = 0; - state->DMRvcR = 0; + dmr_alg_reset (opts, state); + //copy ambe_fr frames first, running process mbe will correct them, + //but this also leads to issues extracting good le mi values when + //we go to do correction on them there too + memcpy (m1, ambe_fr, sizeof(m1)); + memcpy (m2, ambe_fr2, sizeof(m2)); + memcpy (m3, ambe_fr3, sizeof(m3)); + + if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here processMbeFrame (opts, state, NULL, ambe_fr, NULL); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + + //collect the mi fragment + dmr_late_entry_mi_fragment (opts, state, 1, ambe_fr, ambe_fr2, ambe_fr3); + + cach_err = dmr_cach (opts, state, cachdata); + fprintf (stderr, "\n"); + dmrBS (opts, state); //bootstrap into full TDMA frame for BS mode END: - //if we have a cach err, then produce sync pattern/err message - if (cach_okay != 1) + //if we have a tact err, then produce sync pattern/err message + if (tact_okay != 1) { fprintf (stderr,"%s ", getTime()); fprintf (stderr,"Sync: DMR "); fprintf (stderr, "%s", KRED); - fprintf (stderr, "| ** VOICE CACH ERR ** "); + fprintf (stderr, "| VOICE CACH/EMB ERR"); fprintf (stderr, "%s", KNRM); //run LFSR if either slot had an active MI in it. - state->currentslot = 0; - if (state->payload_algid >= 0x21) LFSR(state); - state->currentslot = 1; - if (state->payload_algidR >= 0x21) LFSR(state); - fprintf (stderr, "\n"); + if (state->payload_algid >= 0x21) + { + state->currentslot = 0; + LFSR(state); + fprintf (stderr, "\n"); + } + if (state->payload_algidR >= 0x21) + { + state->currentslot = 1; + LFSR(state); + fprintf (stderr, "\n"); + } } } diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c new file mode 100644 index 0000000..0ac3597 --- /dev/null +++ b/src/dmr_csbk.c @@ -0,0 +1,586 @@ +/*------------------------------------------------------------------------------- + * dmr_csbk.c + * DMR Control Signal Data PDU (CSBK, MBC, UDT) Handler and Related Functions + * + * Portions of Connect+ code reworked from Boatbod OP25 + * Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c + * + * Portions of Capacity+ code reworked from Eric Cottrell + * Source: https://github.com/LinuxSheeple-E/dsd/blob/Feature/DMRECC/dmr_csbk.c + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + +#include "dsd.h" + +//function for handling Control Signalling PDUs (CSBK, MBC, UDT) messages +void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors) +{ + + int csbk_lb = 0; + int csbk_pf = 0; + int csbk_o = 0; + int csbk_fid = 0; + uint64_t csbk_data = 0; + int csbk = 0; + + if(IrrecoverableErrors == 0 && CRCCorrect == 1) + { + + csbk_lb = ( (cs_pdu[0] & 0x80) >> 7 ); + csbk_pf = ( (cs_pdu[0] & 0x40) >> 6 ); + csbk_o = cs_pdu[0] & 0x3F; + csbk_fid = cs_pdu[1]; //feature set id + csbk_pf = ( (cs_pdu[1] & 0x80) >> 7); + csbk = ((cs_pdu[0] & 0x3F) << 8) | cs_pdu[1]; //opcode and fid combo set + + //set overarching manufacturer in use when non-standard feature id set is up + if (csbk_fid != 0) state->dmr_mfid = csbk_fid; + + //TIII standard with fid of 0 - (opcodes in decimal) + if (0 == 0) //standard feature set for TIII //csbk_fid == 0 + { + + + fprintf (stderr, "%s", KYEL); + + //7.1.1.1.1 Channel Grant CSBK/MBC PDU + if (csbk_o > 47 && csbk_o < 53 ) + { + //initial line break + fprintf (stderr, "\n"); + + long int freq = 0; + + //all of these messages share the same format (thankfully) + if (csbk_o == 48) fprintf (stderr, " Private Voice Channel Grant (PV_GRANT)"); + if (csbk_o == 49) fprintf (stderr, " Talkgroup Voice Channel Grant (TV_GRANT)"); + if (csbk_o == 50) fprintf (stderr, " Private Broadcast Voice Channel Grant (BTV_GRANT)"); + if (csbk_o == 51) fprintf (stderr, " Private Data Channel Grant: Single Item (PD_GRANT)"); + if (csbk_o == 52) fprintf (stderr, " Talkgroup Data Channel Grant: Single Item (TD_GRANT)"); + + //Logical Physical Channel Number + uint16_t lpchannum = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 12); + if (lpchannum == 0) fprintf (stderr, " - Invalid Channel"); //invalid channel, not sure why this would even be transmitted + else if (lpchannum == 0xFFF) fprintf (stderr, " - Absolute"); //This is from an MBC, signalling an absolute and not a logical + else fprintf (stderr, " - Logical"); + + //LCN conveyed here is the tdma timeslot variety, and not the RF frequency variety + uint8_t lcn = cs_pdu_bits[28]; + //the next three bits can have different meanings depending on which item above for context + uint8_t st1 = cs_pdu_bits[29]; //late_entry, hi_rate + uint8_t st2 = cs_pdu_bits[30]; //emergency + uint8_t st3 = cs_pdu_bits[31]; //offset, call direction + //target and source are always the same bits + uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24); + uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24); + + fprintf (stderr, "\n"); + fprintf (stderr, " CHAN [%03X][%04d] - LCN/TS [%d] - Target [%08d] - Source [%08d]", lpchannum, lpchannum, lcn, target, source); + if (st2) fprintf (stderr, " Emergency"); + + if (lpchannum == 0xFFF) //This is from an MBC, signalling an absolute and not a logical + { + + //7.1.1.1.2 Channel Grant Absolute Parameters CG_AP appended MBC PDU + uint8_t mbc_lb = cs_pdu_bits[96]; // + uint8_t mbc_pf = cs_pdu_bits[97]; + uint8_t mbc_csbko = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[98], 6); + uint8_t mbc_res = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[104], 4); + uint8_t mbc_cc = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[108], 4); + uint8_t mbc_cdeftype = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[112], 4); //see 7.2.19.7 = 0 for channel parms, 1 through FFFF reserved + uint8_t mbc_res2 = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[116], 2); + uint64_t mbc_cdefparms = (uint64_t)ConvertBitIntoBytes(&cs_pdu_bits[118], 58); //see 7.2.19.7.1 + + //this is how you read the 58 parm bits according to the appendix 7.2.19.7.1 + if (mbc_cdeftype == 0) //if 0, then absolute channel parms + { + uint16_t mbc_lpchannum = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[118], 12); + uint16_t mbc_abs_tx_int = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[130], 10); + uint16_t mbc_abs_tx_step = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[140], 13); + uint16_t mbc_abs_rx_int = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[153], 10); + uint16_t mbc_abs_rx_step = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[163], 13); + + //tx_int (Mhz) + (tx_step * 125) = tx_freq + //rx_int (Mhz) + (rx_step * 125) = rx_freq + fprintf (stderr, "\n"); + fprintf (stderr, " ABS-CHAN [%03X][%04d] - RX INT [%d][%X] - RX STEP [%d][%X]", mbc_lpchannum, mbc_lpchannum, mbc_abs_rx_int, mbc_abs_rx_int, mbc_abs_rx_step, mbc_abs_rx_step ); + //DOULBE CHECK APPENDIX C - C.1.1.2 Fixed Channel Plan for accurate information (found it after figuring out calc, so might be worth double checking) + //The Frequency we want to tune is the RX Frequency + freq = (mbc_abs_rx_int * 1000000 ) + (mbc_abs_rx_step * 125); + //tx_freq = (mbc_abs_tx_int * 1000000 ) + (mbc_abs_tx_step * 125); + + } + } + + //print frequency from absolute + if (freq != 0 && lpchannum == 0xFFF) fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000); + + //run external channel map function on logical + if (lpchannum != 0 && lpchannum != 0xFFF) + { + freq = state->trunk_chan_map[lpchannum]; + (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000); + } + + //if not a data channel grant (only tuning to voice channel grants) + if (csbk_o < 51) //48, 49, 50 are voice grants, 51 and 52 are data grants + { + //shim in chan map 0 as the cc frequency, user will need to specify it in the channel map file + if (state->p25_cc_freq != 0 && state->trunk_chan_map[0] != 0) state->p25_cc_freq = state->trunk_chan_map[0]; + + //shim in here for ncurses freq display when not trunking (playback, not live) + if (opts->p25_trunk == 0 && freq != 0) + { + //just set to both for now, could go on tslot later + state->p25_vc_freq[0] = freq; + state->p25_vc_freq[1] = freq; + } + + char mode[8]; //allow, block, digital, enc, etc + + for (int i = 0; i < state->group_tally; i++) + { + if (state->group_array[i].groupNumber == target) + { + fprintf (stderr, " [%s]", state->group_array[i].groupName); + strcpy (mode, state->group_array[i].groupMode); + } + } + + if (state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0)) + { + if (freq != 0) //if we have a valid frequency + { + //RIGCTL + if (opts->use_rigctl == 1) + { + SetModulation(opts->rigctl_sockfd, 12500); //bw depends on system strength more than anything, 12.5 should be safe for DMR + SetFreq(opts->rigctl_sockfd, freq); //minus one because our index starts at zero + state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq; + opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop + } + } + + //rtl_udp + else if (opts->audio_in_type == 3) + { + rtl_udp_tune (opts, state, freq); + state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq; + opts->p25_is_tuned = 1; + } + } + } + + } + + //Move + if (csbk_o == 57) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, " Move (C_MOVE) (TODO)"); + } + + //Aloha + if (csbk_o == 25) + { + //initial line break + fprintf (stderr, "\n"); + uint8_t reserved = cs_pdu_bits[16]; + uint8_t tsccas = cs_pdu_bits[17]; + uint8_t sync = cs_pdu_bits[18]; + uint8_t version = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[19], 3); //Document Version Control + uint8_t offset = cs_pdu_bits[22]; //0-TSCC uses aligned timing; 1-TSCC uses offset timing + uint8_t active = cs_pdu_bits[23]; //Active_Connection + uint8_t mask = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24], 5); + uint8_t sf = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[29], 2); //service function + uint8_t nrandwait = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[31], 4); + uint8_t regreq = cs_pdu_bits[35]; + uint8_t backoff = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[36], 4); + + uint8_t model = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 2); + uint16_t net = 0; + uint16_t site = 0; + char model_str[8]; + sprintf (model_str, "%s", " "); + if (model == 0) //Tiny + { + net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 9); + site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[51], 3); + sprintf (model_str, "%s", "Tiny"); + } + else if (model == 1) //Small + { + net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 7); + site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[49], 5); + sprintf (model_str, "%s", "Small"); + } + else if (model == 2) //Large + { + net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 4); + site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[46], 8); + sprintf (model_str, "%s", "Large"); + } + else if (model == 3) //Huge + { + net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 2); + site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[44], 10); + sprintf (model_str, "%s", "Huge"); + } + + uint8_t par = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[54], 2); + uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24); + + fprintf (stderr, " C_ALOHA_SYS_PARMS - %s - Net ID: %d Site ID: %d Par: %d \n Reg Req: %d V: %d MS: %d", model_str, net, site, par, regreq, version, target); + //fprintf (stderr, " Sys ID Code: [%04X]", sysidcode); + + uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16); + //fprintf (stderr, "\n SYSCODE: %016b", syscode); + } + + //P_CLEAR + if (csbk_o == 46) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, " Clear (P_CLEAR) (TODO)"); + } + + //(P_PROTECT) - Could be a useful way of determining who is on the current timeslot p_kind 2 + if (csbk_o == 47) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, " Protect (P_PROTECT) -"); + uint16_t reserved = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 12); + uint8_t p_kind = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[28], 3); + uint8_t gi = cs_pdu_bits[31]; + uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24); + uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24); + + if (p_kind == 0) fprintf (stderr, " Disable Target PTT (DIS_PTT)"); + if (p_kind == 1) fprintf (stderr, " Enable Target PTT (EN_PTT)"); + if (p_kind == 2) fprintf (stderr, " Private Call (ILLEGALLY_PARKED)"); + if (p_kind == 3) fprintf (stderr, " Enable Target MS PTT(EN_PTT_ONE_MS)");//EN_PTT_ONE_MS + + fprintf (stderr, "\n"); + fprintf (stderr, " Target [%08d] - Source [%08d]", target, source); + + //experimental, but this may work work if we stay on this channel + //may be reversed considering we won't know exactly who is going to answer first + //only good for an initial protect clear all as well + if (p_kind == 2) + { + //don't set this if operating out of dmr mono or using call alert beep + if (opts->dmr_mono == 0 && opts->call_alert == 0) + { + if (state->currentslot == 0) + { + state->lasttg = target; + state->lastsrc = source; + } + else + { + state->lasttgR = target; + state->lastsrcR = source; + } + } + + } + + } + + if (csbk_o == 40) //0x28 //check to see if these are fid 0 only, or also in other manufacturer fids + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, " Announcements (C_BCAST)"); //site it, vote for etc etc + uint8_t a_type = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 5); + if (a_type == 0) fprintf (stderr, " Announce/Withdraw TSCC (Ann_WD_TSCC)"); + if (a_type == 1) fprintf (stderr, " Specify Call Timer Parameters (CallTimer_Parms)"); + if (a_type == 2) fprintf (stderr, " Vote Now Advice (Vote_Now)"); + if (a_type == 3) fprintf (stderr, " Broadcast Local Time (Local_Time)"); + if (a_type == 4) fprintf (stderr, " Mass Registration (MassReg)"); + if (a_type == 5) fprintf (stderr, " Announce Logical Channel/Frequency Relationship (Chan_Freq)"); + if (a_type == 6) fprintf (stderr, " Adjacent Site Information (Adjacent_Site)"); + if (a_type == 7) fprintf (stderr, " General Site Parameters (Gen_Site_Params)"); + if (a_type > 7 && a_type < 0x1E) fprintf (stderr, " Reserved %02X", a_type); + if (a_type == 0x1E || a_type == 0x1F) fprintf (stderr, " Manufacturer Specific %02X", a_type); + + //sysidcode, probably would have been easier to make this its own external function + uint8_t model = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 2); + uint16_t net = 0; + uint16_t site = 0; + char model_str[8]; + sprintf (model_str, "%s", " "); + + if (model == 0) //Tiny + { + net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 9); + site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[51], 3); + sprintf (model_str, "%s", "Tiny"); + } + else if (model == 1) //Small + { + net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 7); + site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[49], 5); + sprintf (model_str, "%s", "Small"); + } + else if (model == 2) //Large + { + net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 4); + site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[46], 8); + sprintf (model_str, "%s", "Large"); + } + else if (model == 3) //Huge + { + net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 2); + site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[44], 10); + sprintf (model_str, "%s", "Huge"); + } + + uint8_t par = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[54], 2); + uint32_t parms2 = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24); + fprintf (stderr, "\n"); + fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d Par: %d ", model_str, net, site, par); + uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16); + //fprintf (stderr, "\n SYSCODE: %016b", syscode); + + } + + if (csbk == 28) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, " C_AHOY (TODO)"); + } + + if (csbk == 42) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, " P_MAINT (TODO)"); + } + + if (csbk == 30) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, " C_ACKVIT (TODO)"); + } + + if (csbk == 31) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, " C_RAND (TODO)"); + } + + } + + //Capacity+ Section + if (csbk_fid == 0x10) + { + //will need to ponder the best way to do trunking rules for this + if (csbk_o == 0x3E) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, "%s", KYEL); + uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2); + uint8_t slot = cs_pdu_bits[18]; + uint8_t rest_channel = cs_pdu[2] & 0xF; //0xF, or 0x1F? + uint8_t ch[8]; //one bit per channel + uint8_t tg = 0; + uint32_t tghex = 0; //combined all tgs for debug + int i, k; + k = 0; + if (rest_channel != state->dmr_rest_channel) + { + state->dmr_rest_channel = rest_channel; + } + for (int i = 0; i < 8; i++) + { + ch[i] = cs_pdu_bits[i+24]; + } + + fprintf (stderr, " Capacity Plus Channel Status - Rest Channel %d", rest_channel); + + fprintf (stderr, "\n "); + for (i = 0; i < 8; i++) + { + fprintf (stderr, "Ch%d: ", i+1); + if (ch[i] != 0) + { + tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[k*8+32], 8); + fprintf (stderr, " %03d ", tg); + k++; + + } + else if (i+1 == rest_channel) fprintf (stderr, "Rest "); + else fprintf (stderr, "Idle "); + + if (i == 3) fprintf (stderr, "\n "); + } + tghex = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24); + //fprintf (stderr, "\n TG Hex = 0x%06X", tghex); + state->dmr_mfid = 0x10; + sprintf (state->dmr_branding_sub, "%s", "Cap+ "); + fprintf (stderr, "%s", KNRM); + } + } + + //Connect+ Section + if (csbk_fid == 0x06) + { + if (csbk_o == 0x01) + { + //initial line break + fprintf (stderr, "\n"); + uint8_t nb1 = cs_pdu[2] & 0x3F; + uint8_t nb2 = cs_pdu[3] & 0x3F; + uint8_t nb3 = cs_pdu[4] & 0x3F; + uint8_t nb4 = cs_pdu[5] & 0x3F; + uint8_t nb5 = cs_pdu[6] & 0x3F; + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Connect Plus Neighbors\n"); + fprintf (stderr, " NB1(%02d), NB2(%02d), NB3(%02d), NB4(%02d), NB5(%02d)", nb1, nb2, nb3, nb4, nb5); + state->dmr_mfid = 0x06; + sprintf(state->dmr_branding_sub, "Con+ "); + } + + if (csbk_o == 0x03) + { + //shim in chan map 0 as the cc frequency, user will need to specify it in the channel map file + if (state->p25_cc_freq != 0 && state->trunk_chan_map[0] != 0) state->p25_cc_freq = state->trunk_chan_map[0]; + + //initial line break + fprintf (stderr, "\n"); + uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] ); + uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] ); + uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 ); + uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 ); + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Connect Plus Voice Channel Grant\n"); + fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + state->dmr_mfid = 0x06; + sprintf(state->dmr_branding_sub, "Con+ "); + // state->dmr_vc_lcn = lcn; + // state->dmr_vc_lsn = lcn * (tslot+1); + + //shim in here for ncurses freq display when not trunking (playback, not live) + if (opts->p25_trunk == 0 && state->trunk_chan_map[lcn] != 0) + { + //just set to both for now, could go on tslot later + state->p25_vc_freq[0] = state->trunk_chan_map[lcn]; + state->p25_vc_freq[1] = state->trunk_chan_map[lcn]; + } + + char mode[8]; //allow, block, digital, enc, etc + + for (int i = 0; i < state->group_tally; i++) + { + if (state->group_array[i].groupNumber == grpAddr) + { + fprintf (stderr, " [%s]", state->group_array[i].groupName); + strcpy (mode, state->group_array[i].groupMode); + } + } + + //need channel map frequencies and stuff, also way to figure out control channel frequency? (channel 0 from channel map?) + if (state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0)) + { + if (state->trunk_lcn_freq[lcn] != 0) //if we have a valid frequency + { + //RIGCTL + if (opts->use_rigctl == 1) + { + SetModulation(opts->rigctl_sockfd, 12500); //bw depends on system strength more than anything, 12.5 should be safe for DMR + SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[lcn]); //minus one because our index starts at zero + state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[lcn]; + opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop + } + } + + //rtl_udp + else if (opts->audio_in_type == 3) + { + rtl_udp_tune (opts, state, state->trunk_chan_map[lcn]); + state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[lcn]; + opts->p25_is_tuned = 1; + } + } + + } + + if (csbk_o == 0x06) + { + //initial line break + fprintf (stderr, "\n"); + uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] ); + uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] ); + uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 ) ; + uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 ); + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Connect Plus Data Channel Grant\n"); + fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + state->dmr_mfid = 0x06; + sprintf(state->dmr_branding_sub, "Con+ "); + } + + if (csbk_o == 0x0C) + { + //initial line break + fprintf (stderr, "\n"); + uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] ); + uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] ); + uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 ) ; ////extract(csbk, 64, 68); //double check these? + uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 ); //csbk[68]; + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " 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); + state->dmr_mfid = 0x06; + sprintf(state->dmr_branding_sub, "Con+ "); + } + + if (csbk_o == 0x11) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Connect Plus Registration Request"); + state->dmr_mfid = 0x06; + sprintf(state->dmr_branding_sub, "Con+ "); + } + + if (csbk_o == 0x12) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Connect Plus Registration Response"); + state->dmr_mfid = 0x06; + sprintf(state->dmr_branding_sub, "Con+ "); + } + + if (csbk_o == 0x18) + { + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Connect Plus Talkgroup Affiliation"); + state->dmr_mfid = 0x06; + sprintf(state->dmr_branding_sub, "Con+ "); + } + + fprintf (stderr, "%s", KNRM); + + } + + } + END: + fprintf (stderr, "%s", KNRM); + +} \ No newline at end of file diff --git a/src/dmr_data.c b/src/dmr_data.c index d725043..f3e6ca1 100644 --- a/src/dmr_data.c +++ b/src/dmr_data.c @@ -18,35 +18,32 @@ #include "dsd.h" void -processDMRdata (dsd_opts * opts, dsd_state * state) +dmr_data_sync (dsd_opts * opts, dsd_state * state) { int i, dibit; int *dibit_p; char sync[25]; char syncdata[48]; - char cachdata[25] = {0}; - char cc[5] = {0}; - char ccAscii[5] = {0}; - char bursttype[5]; - unsigned int burst; - char info[196]; + char cachdata[25]; + char bursttype[5]; + uint8_t burst; + char info[196]; unsigned char SlotType[20]; unsigned int SlotTypeOk; - int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23}; + uint8_t cach_err = 0; -#ifdef DMR_DUMP - char syncbits[49]; - char cachbits[25]; - int k; -#endif - - ccAscii[4] = 0; - bursttype[4] = 0; + int cachInterleave[24] = + {0, 7, 8, 9, 1, 10, + 11, 12, 2, 13, 14, + 15, 3, 16, 4, 17, 18, + 19, 5, 20, 21, 22, 6, 23 + }; dibit_p = state->dmr_payload_p - 90; - // CACH + + //collect cach and de-interleave for (i = 0; i < 12; i++) { dibit = *dibit_p; @@ -65,67 +62,34 @@ processDMRdata (dsd_opts * opts, dsd_state * state) } - //decode and correct cach and compare - int cach_okay = 69; - if ( Hamming_7_4_decode (cachdata) ) //is now de-interleaved appropriately + //seperate tact bits from cach + uint8_t tact_bits[7]; + for (i = 0; i < 7; i++) { - cach_okay = 1; + tact_bits[i] = cachdata[i]; } - if (cach_okay == 1) + + //run hamming on tact bits + int cach_okay = -1; + if ( Hamming_7_4_decode (tact_bits) ) cach_okay = 1; + else { - //fprintf (stderr, "CACH Okay "); - } - if (cach_okay != 1) - { - //fprintf (stderr, "CACH FEC Error %d", cach_okay); - if (opts->aggressive_framesync == 1) //may not worry about it on data + cach_okay = -1; + if (opts->aggressive_framesync == 2) { + SlotTypeOk = 0; goto END; } - } - state->currentslot = cachdata[1]; + state->currentslot = tact_bits[1]; - //minor bugfix for MSData when MSData has accumulated data blocks - //(i.e. data header and 1/2 rate data), force all data into slot 0 + //in the future, maybe we will remove the hard set on this if (state->dmr_ms_mode == 1) { state->currentslot = 0; } - if (state->currentslot == 0 && state->dmr_ms_mode == 0) - { - state->slot1light[0] = '['; - state->slot1light[6] = ']'; - state->slot2light[0] = ' '; - state->slot2light[6] = ' '; - } - //else - if (state->currentslot == 1 && state->dmr_ms_mode == 0) - { - state->slot2light[0] = '['; - state->slot2light[6] = ']'; - state->slot1light[0] = ' '; - state->slot1light[6] = ' '; - } - //end correct cach and set slot - -#ifdef DMR_DUMP - k = 0; - for (i = 0; i < 12; i++) - { - dibit = cachdata[i]; - cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 - k++; - cachbits[k] = (1 & dibit) + 48; // bit 0 - k++; - } - 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++) { @@ -139,7 +103,6 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (int)state->dmr_stereo_payload[i+12]; } - trellisdibits[i] = dibit; info[2*i] = (1 & (dibit >> 1)); // bit 1 info[(2*i)+1] = (1 & dibit); // bit 0 } @@ -153,10 +116,9 @@ processDMRdata (dsd_opts * opts, dsd_state * state) } if (state->dmr_stereo == 1) { - dibit = (int)state->dmr_stereo_payload[61]; //61, not i+61 + dibit = (int)state->dmr_stereo_payload[61]; } - cc[0] = (1 & (dibit >> 1)); // bit 1 - cc[1] = (1 & dibit); // bit 0 + SlotType[0] = (1 & (dibit >> 1)); // bit 1 SlotType[1] = (1 & dibit); // bit 0 @@ -170,17 +132,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (int)state->dmr_stereo_payload[62]; } - cc[2] = (1 & (dibit >> 1)); // bit 1 - cc[3] = (1 & dibit); // bit 0 + SlotType[2] = (1 & (dibit >> 1)); // bit 1 SlotType[3] = (1 & dibit); // bit 0 - ccAscii[0] = cc[0] + '0'; - ccAscii[1] = cc[1] + '0'; - ccAscii[2] = cc[2] + '0'; - ccAscii[3] = cc[3] + '0'; - ccAscii[4] = cc[4] + '\0'; - dibit = *dibit_p; dibit_p++; if (opts->inverted_dmr == 1) @@ -189,7 +144,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) } if (state->dmr_stereo == 1) //state { - dibit = (int)state->dmr_stereo_payload[63]; //(int) + dibit = (int)state->dmr_stereo_payload[63]; } SlotType[4] = (1 & (dibit >> 1)); // bit 1 @@ -203,7 +158,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) } if (state->dmr_stereo == 1) //state { - dibit = (int)state->dmr_stereo_payload[64]; //(int) + dibit = (int)state->dmr_stereo_payload[64]; } SlotType[6] = (1 & (dibit >> 1)); // bit 1 @@ -223,7 +178,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) SlotType[8] = (1 & (dibit >> 1)); // bit 1 SlotType[9] = (1 & dibit); // bit 0 - // signalling data or sync + // signaling data or sync for (i = 0; i < 24; i++) { dibit = *dibit_p; @@ -239,32 +194,19 @@ processDMRdata (dsd_opts * opts, dsd_state * state) syncdata[2*i] = (1 & (dibit >> 1)); // bit 1 syncdata[(2*i)+1] = (1 & dibit); // bit 0 sync[i] = (dibit | 1) + 48; - - } sync[24] = 0; -#ifdef DMR_DUMP - k = 0; - for (i = 0; i < 24; i++) - { - syncbits[k] = syncdata[(k*2)] + 48; // bit 1 - k++; - syncbits[k] = syncdata[(k*2)+1] + 48; // bit 0 - k++; - } - syncbits[48] = 0; - fprintf(stderr, "%s ", syncbits); -#endif - - if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) )//|| (strcmp (sync, DMR_MS_DATA_SYNC) == 0)) + if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) ) { if (state->currentslot == 0) { sprintf(state->slot1light, "[slot1]"); + sprintf(state->slot2light, " slot2 "); } else { + sprintf(state->slot1light, " slot1 "); sprintf(state->slot2light, "[slot2]"); } } @@ -273,15 +215,17 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { state->currentslot = 0; sprintf(state->slot1light, "[sLoT1]"); + sprintf(state->slot2light, "[DMODE]"); } else if(strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0) { state->currentslot = 1; + sprintf(state->slot1light, "[DMODE]"); sprintf(state->slot2light, "[sLoT2]"); } - if (opts->errorbars == 1 && state->dmr_ms_mode == 0) + if (state->dmr_ms_mode == 0) { fprintf(stderr, "%s %s ", state->slot1light, state->slot2light); } @@ -289,283 +233,85 @@ processDMRdata (dsd_opts * opts, dsd_state * state) // Slot type - Second part - Parity bit for (i = 0; i < 5; i++) { - if (state->dmr_stereo == 0) //only get dibits if not using dmr_stereo method + if (state->dmr_stereo == 0) { dibit = getDibit(opts, state); } - if (opts->inverted_dmr == 1) - { - //dibit = (dibit ^ 2); - } if (state->dmr_stereo == 1) { - dibit = (int)state->dmr_stereo_payload[i+90]; //double checked these i+ values make sure we are on the right ones + dibit = (int)state->dmr_stereo_payload[i+90]; } SlotType[(i*2) + 10] = (1 & (dibit >> 1)); // bit 1 SlotType[(i*2) + 11] = (1 & dibit); // bit 0 } /* Check and correct the SlotType (apply Golay(20,8) FEC check) */ - + // golay (20,8) hamming-weight of 6 reliably corrects at most 2 bit-errors - if( Golay_20_8_decode(SlotType) ) - { - SlotTypeOk = 1; - //fprintf (stderr, "Slot Okay "); - } + if( Golay_20_8_decode(SlotType) ) SlotTypeOk = 1; else { - + SlotTypeOk = -1; if (opts->aggressive_framesync == 1) { SlotTypeOk = 0; goto END; } - } - /* Slot Type parity checked => Fill the color code */ state->color_code = (SlotType[0] << 3) + (SlotType[1] << 2) +(SlotType[2] << 1) + (SlotType[3] << 0); state->color_code_ok = SlotTypeOk; - /* Reconstitute the burst type */ - //consider assigning this only when slottypeok or similar check passes, eliminate bad burst types from decoding randomly - burst = (unsigned int)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]); - if (state->currentslot == 0) - { - state->dmrburstL = burst; - } - if (state->currentslot == 1) - { - state->dmrburstR = burst; - } + //not sure why I still have two variables for this, need to look and see what state->color_code still ties into + if (SlotTypeOk == 1) state->dmr_color_code = state->color_code; /* Reconstitute the burst type */ - bursttype[0] = SlotType[4] + '0'; - bursttype[1] = SlotType[5] + '0'; - bursttype[2] = SlotType[6] + '0'; - bursttype[3] = SlotType[7] + '0'; - bursttype[4] = '\0'; + burst = (uint8_t)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]); + if (state->currentslot == 0) state->dmrburstL = burst; + if (state->currentslot == 1) state->dmrburstR = burst; - if (strcmp (bursttype, "0000") == 0) - { - sprintf(state->fsubtype, " PI Header "); - } - else if (strcmp (bursttype, "0001") == 0) - { - sprintf(state->fsubtype, " VOICE LC "); - } - else if (strcmp (bursttype, "0010") == 0) - { - sprintf(state->fsubtype, " TLC "); - } - else if (strcmp (bursttype, "0011") == 0) - { - sprintf(state->fsubtype, " CSBK "); - } - else if (strcmp (bursttype, "0100") == 0) - { - sprintf(state->fsubtype, " MBC Header "); - } - else if (strcmp (bursttype, "0101") == 0) - { - sprintf(state->fsubtype, " MBC "); - } - else if (strcmp (bursttype, "0110") == 0) - { - sprintf(state->fsubtype, " DATA Header "); - } - else if (strcmp (bursttype, "0111") == 0) - { - sprintf(state->fsubtype, " RATE 1/2 DATA"); - } - else if (strcmp (bursttype, "1000") == 0) - { - sprintf(state->fsubtype, " RATE 3/4 DATA"); - } - else if (strcmp (bursttype, "1001") == 0) - { - sprintf(state->fsubtype, " Slot idle "); - } - else if (strcmp (bursttype, "1010") == 0) - { - sprintf(state->fsubtype, " Rate 1 DATA "); - } - else - { - sprintf(state->fsubtype, " "); - } - // Current slot - First half - Data Payload - 1st part - //trellis + // Current slot - Second Half - Data Payload - 2nd part for (i = 0; i < 49; i++) { - if (state->dmr_stereo == 0) //only get dibits if not using dmr_stereo method + if (state->dmr_stereo == 0) { dibit = getDibit(opts, state); } - if (opts->inverted_dmr == 1) - { - //dibit = (dibit ^ 2); - } + if (state->dmr_stereo == 1) { - dibit = (int)state->dmr_stereo_payload[i+95]; //double checked these i+ values make sure we are on the right ones + dibit = (int)state->dmr_stereo_payload[i+95]; } - trellisdibits[i+49] = dibit; + info[(2*i) + 98] = (1 & (dibit >> 1)); // bit 1 info[(2*i) + 99] = (1 & dibit); // bit 0 } + + dmr_data_burst_handler(opts, state, (uint8_t *)info, burst); - // Skip cach (24 bit = 12 dibit) and next slot 1st half (98 + 10 bit = 49 + 5 dibit) - if (state->dmr_stereo == 0) + //don't run cach on simplex or mono + if (state->dmr_ms_mode == 0 || opts->dmr_mono == 0) { - skipDibit (opts, state, 12 + 49 + 5); - } + cach_err = dmr_cach (opts, state, cachdata); + } - if (opts->errorbars == 1) - { - /* Print the color code */ - //if (burst == 0b1001 && state->color_code_ok) //only print on idle for data types, otherwise prints on voice frames. - if (SlotTypeOk == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf(stderr, "| Color Code=%02d ", (int)state->color_code); - fprintf (stderr, "%s", KNRM); - //state->dmr_color_code = state->color_code; - } - else fprintf(stderr, "| "); + //ending line break + fprintf(stderr, "\n"); - //if(state->color_code_ok) fprintf(stderr, "(OK) |"); - if(state->color_code_ok) fprintf(stderr, "| (CRC OK ) |"); //add line break - else - { - fprintf (stderr, "%s", KRED); - fprintf(stderr, "| (CRC ERR) |"); - fprintf (stderr, "%s", KNRM); - } - //fprintf (stderr, "\n"); //print line break - if (strcmp (state->fsubtype, " ") == 0) - { - //fprintf(stderr, " Unknown burst type: %s", bursttype); - fprintf(stderr, " Unknown"); - } - else - { - fprintf(stderr, "%s", state->fsubtype); - } - } - - switch(burst) - { - /* Burst = PI header */ - case 0b0000: - { - ProcessDmrPIHeader(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); - break; - } - - /* Burst = Voice LC header */ - case 0b0001: - { - /* Extract data from Voice LC Header */ - ProcessDmrVoiceLcHeader(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); - break; - } - - /* Burst = TLC */ - case 0b0010: - { - //Not sure if I really care about this in the context of what it shows - ProcessDmrTerminaisonLC(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); - break; - } - - /* Burst = CSBK */ - case 0b0011: - { - //going to disable until I can find more useful info to present - 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 Continuation*/ - 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: - { - //need to keep working on improving the trellis decode, but is partially viable now - Process34Data(opts, state, trellisdibits, (uint8_t *)syncdata, (uint8_t *)SlotType); - break; - } - - /* Burst = Slot idle */ - case 0b1001: - { - if(state->color_code_ok && state->dmr_stereo == 0) state->dmr_color_code = state->color_code; //try setting this on idle if crc ok - break; - } - - /* Burst = Rate 1 DATA */ - case 0b1010: - { - Process1Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); - break; - } - - /* Burst = Unified Single Block DATA */ - case 0b1101: - { - ProcessUnifiedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); - break; - } - - /* Default */ - default: - { - /* Nothing to do */ - ProcessReservedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); - break; - } - } /* End switch(burst) */ - - if (opts->errorbars == 1) - { - fprintf(stderr, "\n"); - } END: if (SlotTypeOk == 0 || cach_okay != 1) { fprintf (stderr, "%s", KRED); - fprintf (stderr, "| ** CACH or Burst Type FEC ERR ** "); + fprintf (stderr, "| CACH/Burst FEC ERR"); fprintf (stderr, "%s", KNRM); fprintf (stderr, "\n"); } -} /* End processDMRdata() */ + // Skip cach (24 bit = 12 dibit) and next slot 1st half (98 + 10 bit = 49 + 5 dibit) + if (state->dmr_stereo == 0) + { + skipDibit (opts, state, 12 + 49 + 5); + } + +} diff --git a/src/dmr_dburst.c b/src/dmr_dburst.c new file mode 100644 index 0000000..e5b44d3 --- /dev/null +++ b/src/dmr_dburst.c @@ -0,0 +1,446 @@ +/*------------------------------------------------------------------------------- + * dmr_dburst.c + * DMR Data Burst Handling and related BPTC/FEC/CRC Functions + * + * Portions of BPTC/FEC/CRC code from LouisErigHerve + * Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + +//TODO: CRC9 on confirmed data blocks; CRC32 on completed data sf; +//TODO: Embedded GPS Calculations +//TODO: MBC full message CRC16 (does this include the header or not though?) +//TODO: Reverse Channel Signalling - RC single burst BPTC/7-bit CRC +//TODO: Single Burst Embedded LC - Non-RC single burst LC - Look for Late Entry Alg/Key + +#include "dsd.h" + +void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst) +{ + + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t slot = state->currentslot; + uint8_t block = state->data_block_counter[slot]; + + //BPTC 196x96 Specific + uint8_t BPTCDeInteleavedData[196]; + uint8_t BPTCDmrDataBit[96]; + uint8_t BPTCDmrDataByte[12]; + + //Embedded Signalling Specific + uint8_t BptcDataMatrix[8][16]; + uint8_t LC_DataBit[77]; + uint8_t LC_DataBytes[10]; + int Burst = -1; + + //Unified PDU (is this the best nomenclature) Bytes + uint8_t DMR_PDU[25]; //using 25 bytes as the max for now + uint8_t DMR_PDU_bits[196]; //bitwise version of unified payload, will probably be a lot easier to use this w/ manual + memset (DMR_PDU, 0, sizeof (DMR_PDU)); + memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits)); + + uint8_t R[3]; + uint8_t BPTCReservedBits = 0; + + uint32_t crcmask = 0; + uint8_t crclen = 0; + + uint8_t is_bptc = 0; + uint8_t is_trellis = 0; + uint8_t is_emb = 0; + uint8_t is_lc = 0; + uint8_t is_full = 0; + uint8_t pdu_len = 0; + uint8_t pdu_start = 0; //starting value of pdu (0 normal, 2 for confirmed) + + switch(databurst){ + case 0x00: //PI + is_bptc = 1; + crclen = 16; + crcmask = 0x6969; //insert pi and 69 jokes here + pdu_len = 12; //12 bytes + sprintf(state->fsubtype, " PI "); + break; + case 0x01: //VLC + is_bptc = 1; + is_lc = 1; + crclen = 24; + crcmask = 0x969696; + pdu_len = 12; //12 bytes + sprintf(state->fsubtype, " VLC "); + break; + case 0x02: //TLC + is_bptc = 1; + is_lc = 1; + crcmask = 0x999999; + crclen = 24; + pdu_len = 12; //12 bytes + sprintf(state->fsubtype, " TLC "); + break; + case 0x03: //CSBK + is_bptc = 1; + crclen = 16; + crcmask = 0xA5A5; + pdu_len = 12; //12 bytes + sprintf(state->fsubtype, " CSBK"); + break; + case 0x04: //MBC Header + is_bptc = 1; + crclen = 16; + crcmask = 0xAAAA; + pdu_len = 12; //12 bytes + sprintf(state->fsubtype, " MBCH"); + break; + case 0x05: //MBC Continuation + is_bptc = 1; + //let block assembler carry out crc on the completed message + pdu_len = 12; //12 bytes + sprintf(state->fsubtype, " MBCC"); + break; + case 0x06: //Data Header + is_bptc = 1; + crclen = 16; + crcmask = 0xCCCC; + pdu_len = 12; //12 bytes + sprintf(state->fsubtype, " DATA"); + break; + //TODO - 1/2 0x0F0 - 3/4 0x1FF - Rate 1 0x10F + //going to set crclen and mask according to confirmed data here, + //use block assmebler to carry out completed message crc + case 0x07: //1/2 Rate Data + is_bptc = 1; + crclen = 9; //confirmed data only + crcmask = 0x0F0; + pdu_len = 12; //12 bytes unconfirmed + if (state->data_conf_data[slot] == 1) + { + pdu_len = 10; + pdu_start = 2; //start at plus two when assembling + } + sprintf(state->fsubtype, " R12D "); + break; + case 0x08: //3/4 Rate Data + is_trellis = 1; + crclen = 9; //confirmed data only + crcmask = 0x1FF; + pdu_len = 18; //18 bytes unconfirmed + if (state->data_conf_data[slot] == 1) + { + pdu_len = 16; + pdu_start = 2; //start at plus two when assembling + } + sprintf(state->fsubtype, " R34D "); + break; + case 0x09: //Idle + //pseudo-random data fill, no need to do anything with this + sprintf(state->fsubtype, " IDLE "); + break; + case 0x0A: //1 Rate Data + crclen = 9; //confirmed data only + crcmask = 0x1FF; + is_full = 1; + pdu_len = 25; //196 bits - 24.5 bytes + sprintf(state->fsubtype, " R_1D "); + break; + case 0x0B: //Unified Data + is_bptc = 1; + crclen = 16; + crcmask = 0x3333; + pdu_len = 12; //12 bytes + sprintf(state->fsubtype, " UDAT "); + break; + //special types (not real data 'sync' bursts) + case 0xEB: //Embedded Signalling + is_emb = 1; + pdu_len = 9; + break; + + default: + break; + + } + + if (databurst != 0xEB) + { + if (state->dmr_ms_mode == 0) fprintf(stderr, "| Color Code=%02d ", state->dmr_color_code); + fprintf(stderr, "|%s", state->fsubtype); + } + + //Most Data Sync Burst types will use the bptc 196x96 + if (is_bptc) + { + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* Deinterleave DMR data */ + BPTCDeInterleaveDMRData(info, BPTCDeInteleavedData); + + /* Extract the BPTC 196,96 DMR data */ + IrrecoverableErrors = BPTC_196x96_Extract_Data(BPTCDeInteleavedData, BPTCDmrDataBit, 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 bits BPTC data into 12 bytes */ + k = 0; + for(i = 0; i < 12; i++) + { + BPTCDmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + BPTCDmrDataByte[i] = BPTCDmrDataByte[i] << 1; + BPTCDmrDataByte[i] = BPTCDmrDataByte[i] | (BPTCDmrDataBit[k] & 0x01); + k++; + } + } + + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + CRCExtracted = 0; + for(i = 0; i < crclen; i++) + { + CRCExtracted = CRCExtracted << 1; + CRCExtracted = CRCExtracted | (uint32_t)(BPTCDmrDataBit[i + 96 - crclen] & 1); + } + + /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ + CRCExtracted = CRCExtracted ^ crcmask; + + /* Check/correct the BPTC data and compute the Reed-Solomon (12,9) CRC */ + if (is_lc) CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask); + + //TODO: run CRC9 on confirmed 1/2 data blocks + else if (state->data_conf_data[slot] == 1) + { + //run CRC on individual blocks according to type and validate each individual block + } + + //run CCITT on other data forms + else //will still run on unconfirmed data (shouldn't matter other than a possible bogus warning message) + { + CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit); + if (CRCComputed == CRCExtracted) CRCCorrect = 1; + else CRCCorrect = 0; + } + + if (databurst == 0x04 || databurst == 0x06) //MBC Header, Data Header + { + if (CRCCorrect) + { + state->data_block_crc_valid[slot][0] = 1; + } + else state->data_block_crc_valid[slot][0] = 0; + } + + /* Convert corrected x bytes into x*8 bits */ + for(i = 0, j = 0; i < pdu_len; i++, j+=8) + { + BPTCDmrDataBit[j + 0] = (BPTCDmrDataByte[i+pdu_start] >> 7) & 0x01; + BPTCDmrDataBit[j + 1] = (BPTCDmrDataByte[i+pdu_start] >> 6) & 0x01; + BPTCDmrDataBit[j + 2] = (BPTCDmrDataByte[i+pdu_start] >> 5) & 0x01; + BPTCDmrDataBit[j + 3] = (BPTCDmrDataByte[i+pdu_start] >> 4) & 0x01; + BPTCDmrDataBit[j + 4] = (BPTCDmrDataByte[i+pdu_start] >> 3) & 0x01; + BPTCDmrDataBit[j + 5] = (BPTCDmrDataByte[i+pdu_start] >> 2) & 0x01; + BPTCDmrDataBit[j + 6] = (BPTCDmrDataByte[i+pdu_start] >> 1) & 0x01; + BPTCDmrDataBit[j + 7] = (BPTCDmrDataByte[i+pdu_start] >> 0) & 0x01; + } + + //convert to unified DMR_PDU and DMR_PDU_bits + for (i = 0; i < pdu_len; i++) + { + DMR_PDU[i] = BPTCDmrDataByte[i+pdu_start]; + } + + for (i = 0; i < pdu_len * 8; i++) + { + DMR_PDU_bits[i] = BPTCDmrDataBit[i]; + } + + } + + //Embedded Signalling will use BPTC 128x77 + if (is_emb) + { + + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + /* First step : Reconstitute the BPTC 16x8 matrix */ + Burst = 1; /* Burst B to E contains embedded signaling data */ + k = 0; + for(i = 0; i < 16; i++) + { + for(j = 0; j < 8; j++) + { + /* Only the LSBit of the byte is stored */ + BptcDataMatrix[j][i] = state->dmr_embedded_signalling[slot][Burst][k+8]; + k++; + + /* Go on to the next burst once 32 bit + * of the SNYC have been stored */ + if(k >= 32) + { + k = 0; + Burst++; + } + } /* End for(j = 0; j < 8; j++) */ + } /* End for(i = 0; i < 16; i++) */ + + /* Extract the 72 LC bit (+ 5 CRC bit) of the matrix */ + IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit); + + /* Reconstitute the 5 bit CRC */ + CRCExtracted = (LC_DataBit[72] & 1) << 4; + CRCExtracted |= (LC_DataBit[73] & 1) << 3; + CRCExtracted |= (LC_DataBit[74] & 1) << 2; + CRCExtracted |= (LC_DataBit[75] & 1) << 1; + CRCExtracted |= (LC_DataBit[76] & 1) << 0; + + /* Compute the 5 bit CRC */ + CRCComputed = ComputeCrc5Bit(LC_DataBit); + + if(CRCExtracted == CRCComputed) CRCCorrect = 1; + else CRCCorrect = 0; + + for (i = 0; i < 72; i++) + { + DMR_PDU_bits[i] = LC_DataBit[i]; + } + + for (i = 0; i < 9; i++) + { + DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&LC_DataBit[i*8], 8); + } + + } + + //the ugly one + if (is_trellis) + { + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 1; //can't be tested, but maybe can poll trellis decoder for a value in the future + + uint8_t tdibits[98]; + memset (tdibits, 0, sizeof(tdibits)); + + //reconstitute info bits into reverse ordered dibits for the trellis decoder + for (i = 0; i < 98; i++) + { + tdibits[97-i] = (info[i*2] << 1) | info[i*2+1]; + } + + unsigned char TrellisReturn[18]; + memset (TrellisReturn, 0, sizeof(TrellisReturn)); + + CDMRTrellisDecode(tdibits, TrellisReturn); + + for (i = 0; i < pdu_len; i++) //18 + { + DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start]; + } + + for(i = 0, j = 0; i < pdu_len; i++, j+=8) + { + DMR_PDU_bits[j + 0] = (TrellisReturn[i+pdu_start] >> 7) & 0x01; + DMR_PDU_bits[j + 1] = (TrellisReturn[i+pdu_start] >> 6) & 0x01; + DMR_PDU_bits[j + 2] = (TrellisReturn[i+pdu_start] >> 5) & 0x01; + DMR_PDU_bits[j + 3] = (TrellisReturn[i+pdu_start] >> 4) & 0x01; + DMR_PDU_bits[j + 4] = (TrellisReturn[i+pdu_start] >> 3) & 0x01; + DMR_PDU_bits[j + 5] = (TrellisReturn[i+pdu_start] >> 2) & 0x01; + DMR_PDU_bits[j + 6] = (TrellisReturn[i+pdu_start] >> 1) & 0x01; + DMR_PDU_bits[j + 7] = (TrellisReturn[i+pdu_start] >> 0) & 0x01; + } + + //TODO: run CRC9 on confirmed 3/4 data blocks + + } + + if (is_full) //Rate 1 Data + { + CRCExtracted = 0; + CRCComputed = 0; + IrrecoverableErrors = 0; + + //TODO: run CRC9 on confirmed data + + for (i = 0; i < 24; i++) + { + DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&info[i*8], 8); + } + //leftover 4 bits, manual doesn't say which 4 so assuming last 4 + //pushing last 4 to 25 and shifting it + DMR_PDU[25] = (uint8_t)ConvertBitIntoBytes(&info[192], 4); + DMR_PDU[25] = DMR_PDU[25] << 4; + + //copy info to dmr_pdu_bits + memcpy(DMR_PDU_bits, info, sizeof(DMR_PDU_bits)); + + } + + + //time for some pi + if (databurst == 0x00) dmr_pi (opts, state, DMR_PDU, CRCCorrect, IrrecoverableErrors); + + //full link control + if (databurst == 0x01) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 1); //VLC + if (databurst == 0x02) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 2); //TLC + if (databurst == 0xEB) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 3); //EMB + + //dmr data header and multi block types (header, 1/2, 3/4, 1, Unified) - type 1 + if (databurst == 0x06) dmr_dheader (opts, state, DMR_PDU, CRCCorrect, IrrecoverableErrors); + if (databurst == 0x07) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //1/2 Rate Data + if (databurst == 0x08) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //3/4 Rate Data + //if (databurst == 0x0A) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Full Rate Data - Disabled until further testing can be done + + //is unified data handled like normal data, or control signalling data? + if (databurst == 0x0B) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Unified Data + //if (databurst == 0x0B) dmr_cspdu (opts, state, DMR_PDU_bits, DMR_PDU, CRCCorrect, IrrecoverableErrors); + + //control signalling types (CSBK, MBC, UDT) + if (databurst == 0x03) dmr_cspdu (opts, state, DMR_PDU_bits, DMR_PDU, CRCCorrect, IrrecoverableErrors); + + //both MBC header and MBC continuation will go to the block_assembler - type 2, and then to dmr_cspdu + if (databurst == 0x04) + { + state->data_block_counter[slot] = 0; //zero block counter before running header + dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 2); + } + if (databurst == 0x05) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 2); + + //print the unified PDU format here, if not slot idle + if (opts->payload == 1 && databurst != 0x09) + { + fprintf (stderr, "\n"); + fprintf (stderr, "%s", KCYN); + fprintf (stderr, " DMR PDU Payload "); + for (i = 0; i < pdu_len; i++) + { + fprintf (stderr, "[%02X]", DMR_PDU[i]); + } + + fprintf (stderr, "%s", KNRM); + + // fprintf (stderr, "%s", KCYN); + // fprintf (stderr, "\n Hex to Ascii - "); + // for (i = 0; i < 12; i++) + // { + // if (DMR_PDU[i] <= 0x7E && DMR_PDU[i] >=0x20) + // { + // fprintf (stderr, "%c", DMR_PDU[i]); + // } + // else fprintf (stderr, "."); + // } + + fprintf (stderr,"%s", KNRM); + } + +} + diff --git a/src/dmr_flco.c b/src/dmr_flco.c new file mode 100644 index 0000000..aa91de0 --- /dev/null +++ b/src/dmr_flco.c @@ -0,0 +1,587 @@ +/*------------------------------------------------------------------------------- + * dmr_flco.c + * DMR Full Link Control, Short Link Control, TACT/CACH and related funtions + * + * Portions of link control/voice burst/vlc/tlc from LouisErigHerve + * Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + +#include "dsd.h" + +//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings +void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type) +{ + + //force slot to 0 if using dmr mono handling + if (opts->dmr_mono == 1) state->currentslot = 0; + + uint8_t pf = 0; + uint8_t reserved = 0; + uint8_t flco = 0; + uint8_t fid = 0; + uint8_t so = 0; + uint32_t target = 0; + uint32_t source = 0; + int restchannel = -1; + int is_cap_plus = 0; + int is_alias = 0; + int is_gps = 0; + + + pf = (uint8_t)(lc_bits[0]); //Protect Flag + reserved = (uint8_t)(lc_bits[1]); //Reserved + flco = (uint8_t)ConvertBitIntoBytes(&lc_bits[2], 6); //Full Link Control Opcode + fid = (uint8_t)ConvertBitIntoBytes(&lc_bits[8], 8); //Feature set ID (FID) + so = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //Service Options + target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //Target or Talk Group + source = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24); + + //look for Cap+ on VLC header, then set source and/or rest channel appropriately + if (type == 1 && fid == 0x10 && flco == 0x04) + { + is_cap_plus = 1; + restchannel = (int)ConvertBitIntoBytes(&lc_bits[48], 8); + source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16); + } + + //Embedded Talker Alias Header Only (format and len storage) + if (IrrecoverableErrors == 0) + { + if (type == 3 && flco == 0x04) + { + dmr_embedded_alias_header(opts, state, lc_bits); + } + + //Embedded Talker Alias Header (continuation) and Blocks + if (type == 3 && flco > 0x3 && flco < 0x08) + { + is_alias = 1; + dmr_embedded_alias_blocks(opts, state, lc_bits); + } + + //Embedded GPS + if (type == 3 && flco == 0x08) + { + is_gps = 1; + dmr_embedded_gps(opts, state, lc_bits); + } + } + + //will want to continue to observe for different flco and fid combinations to find out their meaning + //Standard Addressing/Cap+ Addressing (trying to avoid embedded alias and gps, etc) + if(IrrecoverableErrors == 0 && is_alias == 0 && is_gps == 0) + { + //set overarching manufacturer in use when non-standard feature id set is up + //may not want to set moto 0x10 here either, lots of radios use that set as well + if (fid != 0) state->dmr_mfid = fid; + + if (type != 2) //VLC and EMB, set our target, source, so, and fid per channel + { + if (state->currentslot == 0) + { + state->dmr_fid = fid; + state->dmr_so = so; + state->lasttg = target; + state->lastsrc = source; + } + if (state->currentslot == 1) + { + state->dmr_fidR = fid; + state->dmr_soR = so; + state->lasttgR = target; + state->lastsrcR = source; + } + + } + + if (type == 2) //TLC, zero out target, source, so, and fid per channel, and other odd and ends + { + //I wonder which of these we truly want to zero out, possibly none of them + if (state->currentslot == 0) + { + // state->dmr_fid = 0; + // state->dmr_so = 0; + state->lasttg = 0; + state->lastsrc = 0; + state->payload_mi = 0; + } + if (state->currentslot == 1) + { + // state->dmr_fidR = 0; + // state->dmr_soR = 0; + state->lasttgR = 0; + state->lastsrcR = 0; + state->payload_miR = 0; + } + } + + + if (restchannel != state->dmr_rest_channel && restchannel != -1) + { + state->dmr_rest_channel = restchannel; + } + + if (type == 1) fprintf (stderr, "%s \n", KGRN); + if (type == 2) fprintf (stderr, "%s \n", KRED); + if (type == 3) fprintf (stderr, "%s", KGRN); + + fprintf (stderr, " SLOT %d ", state->currentslot+1); + fprintf(stderr, "TGT=%u SRC=%u ", target, source); + if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so); + + if (flco == 3) fprintf (stderr, "Private "); //UU_V_Ch_Usr + else fprintf (stderr, "Group "); //Grp_V_Ch_Usr + + if(so & 0x80) fprintf(stderr, "Emergency "); + if(so & 0x40) + { + fprintf (stderr, "%s", KRED); + fprintf(stderr, "Encrypted "); + } + + /* Check the "Service Option" bits */ + if(so & 0x30) + { + /* Experimentally determined with DSD+, + * is equal to 0x2, this is a TXI call */ + if((so & 0x30) == 0x20) fprintf(stderr, "TXI "); + else fprintf(stderr, "Reserved=%d ", (so & 0x30) >> 4); + } + if(so & 0x08) fprintf(stderr, "Broadcast "); + if(so & 0x04) fprintf(stderr, "OVCM "); + if(so & 0x03) + { + if((so & 0x03) == 0x01) fprintf(stderr, "Priority 1 "); + else if((so & 0x03) == 0x02) fprintf(stderr, "Priority 2 "); + else if((so & 0x03) == 0x03) fprintf(stderr, "Priority 3 "); + else fprintf(stderr, "No Priority "); /* We should never go here */ + } + + fprintf(stderr, "Call "); + + fprintf (stderr, "%s", KRED); + if (CRCCorrect == 1) ; //CRCCorrect 1 is good, else is bad CRC; no print on good + else if(IrrecoverableErrors == 0) fprintf(stderr, "(FEC/RAS)"); + else fprintf(stderr, "(FEC/CRC ERR)"); + + //check Cap+ rest channel info if available and good fec + if (is_cap_plus == 1) + { + if (restchannel != -1) + { + fprintf (stderr, "%s ", KYEL); + fprintf (stderr, "Cap+ R-Ch %d", restchannel); + } + } + + fprintf (stderr, "%s ", KNRM); + + //group labels + for (int i = 0; i < state->group_tally; i++) + { + //ROMAN! Change target to source if you prefer + if (state->group_array[i].groupNumber == target) + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "[%s] ", state->group_array[i].groupName); + fprintf (stderr, "%s", KNRM); + } + } + + if (state->K != 0 && fid == 0x10 && so & 0x40) + { + fprintf (stderr, "%s", KYEL); + fprintf (stderr, "Key %lld ", state->K); + fprintf (stderr, "%s ", KNRM); + } + + if (state->K1 != 0 && fid == 0x68 && so & 0x40) + { + fprintf (stderr, "\n"); + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Key %010llX ", state->K1); + if (state->K2 != 0) fprintf (stderr, "%016llX ", state->K2); + if (state->K4 != 0) fprintf (stderr, "%016llX %016llX", state->K3, state->K4); + fprintf (stderr, "%s ", KNRM); + } + + } + +} + +//externalized dmr cach - tact and slco fragment handling +uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]) +{ + int i, j; + uint8_t err = 0; + uint8_t tact_valid = 0; + uint8_t cach_valid = 0; + + bool h1, h2, h3, crc; + + //dump payload - testing + uint8_t slco_raw_bits[68]; //raw + uint8_t slco_bits[68]; //de-interleaved + + //tact pdu + uint8_t tact_bits[7]; + uint8_t at = 0; //access type, set to 1 during continuous transmission mode + uint8_t slot = 2; //tdma time slot + uint8_t lcss = 0; //link control start stop (9.3.3) NOTE: There is no Single fragment LC defined for CACH signalling + + //cach_bits are already de-interleaved upon initial collection (still needs secodary slco de-interleave) + for (i = 0; i < 7; i++) + { + tact_bits[i] = cach_bits[i]; + } + + //run hamming 7_4 on the tact_bits (redundant, since we do it earlier, but need the lcss) + if ( Hamming_7_4_decode (tact_bits) ) + { + at = tact_bits[0]; //any useful tricks with this? csbk on/off etc? + slot = tact_bits[1]; // + lcss = (tact_bits[2] << 1) | tact_bits[3]; + tact_valid = 1; //set to 1 for valid, else remains 0. + //fprintf (stderr, "AT=%d LCSS=%d - ", at, lcss); //debug print + } + else //probably skip/memset/zeroes with else statement? + { + //do something? + err = 1; + //return (err); + } + + //determine counter value based on lcss value + if (lcss == 0) //run as single block/fragment NOTE: There is no Single fragment LC defined for CACH signalling (but is mentioned in the manual table) + { + //reset the full cach, even if we aren't going to use it, may be beneficial for next time + state->dmr_cach_counter = 0; //first fragment, set to zero. + memset (state->dmr_cach_fragment, 0, sizeof (state->dmr_cach_fragment)); + + //seperate + for (i = 0; i < 17; i++) + { + slco_raw_bits[i] = cach_bits[i+7]; + } + + //De-interleave + int src = 0; + for (i = 0; i < 17; i++) + { + src = (i * 4) % 67; + slco_bits[i] = slco_raw_bits[src]; + } + //slco_bits[i] = slco_raw_bits[i]; + + //hamming check here + h1 = Hamming17123 (slco_bits + 0); + + //run single - manual would suggest that though this exists, there is no support? or perhaps its manufacturer only thing? + if (h1) dmr_slco (opts, state, slco_bits); + else + { + err = 1; + //return (err); + } + return (err); + } + + if (lcss == 1) //first block, reset counters and memset + { + //reset the full cach and counter + state->dmr_cach_counter = 0; + memset (state->dmr_cach_fragment, 0, sizeof (state->dmr_cach_fragment)); + } + if (lcss == 3) state->dmr_cach_counter++; //continuation, so increment counter by one. + if (lcss == 2) //final segment - assemble, de-interleave, hamming, crc, and execute + { + state->dmr_cach_counter = 3; + } + + //sanity check + if (state->dmr_cach_counter > 3) //marginal/shaky/bad signal or tuned away + { + //zero out complete fragment array + lcss = 5; //toss away value + state->dmr_cach_counter = 0; + memset (state->dmr_cach_fragment, 0, sizeof (state->dmr_cach_fragment)); + err = 1; + return (err); + } + + //add fragment to array + for (i = 0; i < 17; i++) + { + state->dmr_cach_fragment[state->dmr_cach_counter][i] = cach_bits[i+7]; + } + + if (lcss == 2) //last block arrived, compile, hamming, crc and send off to dmr_slco + { + //assemble + for (j = 0; j < 4; j++) + { + for (i = 0; i < 17; i++) + { + slco_raw_bits[i+(17*j)] = state->dmr_cach_fragment[j][i]; + } + } + + //De-interleave method, hamming, and crc from Boatbod OP25 + + //De-interleave + int src = 0; + for (i = 0; i < 67; i++) + { + src = (i * 4) % 67; + slco_bits[i] = slco_raw_bits[src]; + } + slco_bits[i] = slco_raw_bits[i]; + + //hamming checks here + h1 = Hamming17123 (slco_bits + 0); + h2 = Hamming17123 (slco_bits + 17); + h3 = Hamming17123 (slco_bits + 34); + + // remove hamming and leave 36 bits of Short LC + for (i = 17; i < 29; i++) { + slco_bits[i-5] = slco_bits[i]; + } + for (i = 34; i < 46; i++) { + slco_bits[i-10] = slco_bits[i]; + } + + //zero out the hangover bits + for (i = 36; i < 68; i++) + { + slco_bits[i] = 0; + } + + //run crc8 + crc = crc8_ok(slco_bits, 36); + + //only run SLCO on good everything + if (h1 && h2 && h3 && crc) dmr_slco (opts, state, slco_bits); + else + { + fprintf (stderr, "\n"); + fprintf (stderr, "%s", KRED); + fprintf (stderr, " SLCO CRC ERR"); + fprintf (stderr, "%s", KNRM); + } + + } + return (err); //return err value based on success or failure, even if we aren't checking it +} + +void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]) +{ + int i; + uint8_t slco_bytes[6]; //completed byte blocks for payload print + for (i = 0; i < 5; i++) slco_bytes[i] = (uint8_t)ConvertBitIntoBytes(&slco_bits[i*8], 8); + slco_bytes[5] = (uint8_t)ConvertBitIntoBytes(&slco_bits[32], 4); + + + //just going to decode the Short LC with all potential parameters known + uint8_t slco = (uint8_t)ConvertBitIntoBytes(&slco_bits[0], 4); + uint8_t model = (uint8_t)ConvertBitIntoBytes(&slco_bits[4], 2); + uint16_t netsite = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 12); + uint8_t reg = slco_bits[18]; //registration required/not required or normalchanneltype/composite cch + uint8_t csc = (uint16_t)ConvertBitIntoBytes(&slco_bits[19], 9); //common slot counter, 0-511 + uint16_t net = 0; + uint16_t site = 0; + char model_str[8]; + sprintf (model_str, "%s", ""); + //activity update stuff + uint8_t ts1_act = (uint8_t)ConvertBitIntoBytes(&slco_bits[4], 4); //activity update ts1 + uint8_t ts2_act = (uint8_t)ConvertBitIntoBytes(&slco_bits[8], 4); //activity update ts2 + uint8_t ts1_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 8); //ts1 address hash (crc8) //361-1 B.3.7 + uint8_t ts2_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //ts2 address hash (crc8) //361-1 B.3.7 + + //Sys_Parms + if (slco == 0x2 || slco == 0x3) + { + if (model == 0) //Tiny + { + net = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 9); + site = (uint16_t)ConvertBitIntoBytes(&slco_bits[15], 3); + sprintf (model_str, "%s", "Tiny"); + } + else if (model == 1) //Small + { + net = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 7); + site = (uint16_t)ConvertBitIntoBytes(&slco_bits[13], 5); + sprintf (model_str, "%s", "Small"); + } + else if (model == 2) //Large + { + net = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 4); + site = (uint16_t)ConvertBitIntoBytes(&slco_bits[10], 8); + sprintf (model_str, "%s", "Large"); + } + else if (model == 3) //Huge + { + net = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 2); + site = (uint16_t)ConvertBitIntoBytes(&slco_bits[8], 10); + sprintf (model_str, "%s", "Huge"); + } + } + + //Con+ + uint8_t con_netid = (uint8_t)ConvertBitIntoBytes(&slco_bits[8], 8); + uint8_t con_siteid = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 8); + //Cap+ + uint8_t restchannel = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 8); + + //initial line break + fprintf (stderr, "\n"); + fprintf (stderr, "%s", KYEL); + + if (slco == 0x2) //C_SYS_Parms + fprintf (stderr, " C_SYS_PARMS - %s - Net ID: %d Site ID: %d - Reg Req: %d - CSC: %d ", model_str, net, site, reg, csc); + else if (slco == 0x3) //P_SYS_Parms + fprintf (stderr, " P_SYS_PARMS - %s - Net ID: %d Site ID: %d - Comp Ch: %d ", model_str, net, site, reg); + else if (slco == 0x0) //null + fprintf (stderr, " SLCO NULL "); + else if (slco == 0x1) + fprintf (stderr, " SLCO Activity Update TS1: %X Hash: %02X TS2: %X Hash: %02X", ts1_act, ts1_hash, ts2_act, ts2_hash); //102 361-2 7.1.3.2 + else if (slco == 0x9) + { + state->dmr_mfid = 0x10; + sprintf (state->dmr_branding_sub, "%s", "Con+ "); + fprintf (stderr, " SLCO Connect Plus Voice Channel - Net ID: %d Site ID: %d", con_netid, con_siteid); + } + + else if (slco == 0xA) + { + state->dmr_mfid = 0x10; + sprintf (state->dmr_branding_sub, "%s", "Con+ "); + fprintf (stderr, " SLCO Connect Plus Control Channel - Net ID: %d Site ID: %d", con_netid, con_siteid); + } + + else if (slco == 0xF) + { + state->dmr_mfid = 0x10; + sprintf (state->dmr_branding_sub, "%s", "Cap+ "); + fprintf (stderr, " SLCO Capacity Plus Rest Channel %d", restchannel); + } + + else fprintf (stderr, " SLCO Unknown - %d ", slco); + + if (opts->payload == 1 && slco != 0) //if not SLCO NULL + { + fprintf (stderr, "\n SLCO Completed Block "); + for (i = 0; i < 5; i++) + { + fprintf (stderr, "[%02X]", slco_bytes[i]); + } + } + + fprintf (stderr, "%s", KNRM); + +} + +//externalize embedded alias to keep the flco function relatively clean +void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]) +{ + + uint8_t slot = state->currentslot; + uint8_t pf; + uint8_t res; + uint8_t format = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 2); + uint8_t len; + + //this len seems to pertain to number of blocks? not bit len. + //len = (uint8_t)ConvertBitIntoBytes(&lc_bits[18], 5); + + if (format == 0) len = 7; + else if (format == 1 || format == 2) len = 8; + else len = 16; + + state->dmr_alias_format[slot] = format; + state->dmr_alias_len[slot] = len; + + //fprintf (stderr, "F: %d L: %d - ", format, len); + +} + +void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]) +{ + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Embedded Alias: "); + uint8_t slot = state->currentslot; + uint8_t block = (uint8_t)ConvertBitIntoBytes(&lc_bits[2], 6); //FLCO equals block number + uint8_t format = state->dmr_alias_format[slot]; //0=7-bit; 1=ISO8; 2=UTF-8; 3=UTF16BE + uint8_t len = state->dmr_alias_len[slot]; + uint8_t start; //starting position depends on context of block and format + + //there is some issue with the next three lines of code that prevent proper assignments, not sure what. + //if (block > 4) start = 16; + //else if (block == 4 && format > 0) start = 23; //8-bit and 16-bit chars + //else start = 24; + + //forcing start to 16 make it work on 8-bit alias, len seems okay when set off of format + start = 16; + len = 8; + + // fprintf (stderr, "block: %d start: %d len: %d ", block, start, len); + + //all may not be used depending on format, len, start. + uint16_t A0, A1, A2, A3, A4, A5, A6; + + //sanity check + if (block > 7) block = 4; //prevent oob array (although we should never get here) + + if (len > 6) //if not greater than zero, then the header hasn't arrived yet + { + A0 = 0; A1 = 0; A2 = 0; A3 = 0; A4 = 0; A5 = 0; A6 = 0; //NULL ASCII Characters + A0 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*0], len); + A1 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*1], len); + A2 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*2], len); + A3 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*3], len); + A4 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*4], len); + A5 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*5], len); + A6 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*6], len); + + //just going to assign the usual ascii set here to prevent 'naughty' characters, sans diacriticals + if (A0 > 0x19 && A0 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][0], "%c", A0); + if (A1 > 0x19 && A1 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][1], "%c", A1); + if (A2 > 0x19 && A2 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][2], "%c", A2); + if (A3 > 0x19 && A3 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][3], "%c", A3); + if (A4 > 0x19 && A4 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][4], "%c", A4); + if (A5 > 0x19 && A5 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][5], "%c", A5); + if (A6 > 0x19 && A6 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][6], "%c", A6); + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 7; j++) + { + fprintf (stderr, "%s", state->dmr_alias_block_segment[slot][i][j]); + } + } + + + } + else fprintf (stderr, "Missing Header Block Format and Len Data"); + fprintf (stderr, "%s", KNRM); + +} + +//externalize embedded GPS +void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]) +{ + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Embedded GPS"); + uint8_t pf = lc_bits[0]; + uint8_t res_a = lc_bits[1]; + uint8_t res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); + uint8_t pos_err = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 3); + uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[23], 25); + uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24); + + //run calculations and print + + fprintf (stderr, "%s", KNRM); +} diff --git a/src/dmr_le.c b/src/dmr_le.c new file mode 100644 index 0000000..646f92d --- /dev/null +++ b/src/dmr_le.c @@ -0,0 +1,139 @@ +/*------------------------------------------------------------------------------- + * dmr_le.c + * DMR Late Entry MI Fragment Assembly, Procesing, and related Alg functions + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + +#include "dsd.h" + +//gather ambe_fr mi fragments for processing +void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, char ambe_fr[4][24], char ambe_fr2[4][24], char ambe_fr3[4][24]) +{ + + uint8_t slot = state->currentslot; + + //collect our fragments and place them into storage + state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4); + state->late_entry_mi_fragment[slot][vc][1] = (uint64_t)ConvertBitIntoBytes(&ambe_fr2[3][0], 4); + state->late_entry_mi_fragment[slot][vc][2] = (uint64_t)ConvertBitIntoBytes(&ambe_fr3[3][0], 4); + + if (vc == 6) dmr_late_entry_mi (opts, state); + +} + +void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state) +{ + uint8_t slot = state->currentslot; + int i, j; + int g[3]; + unsigned char mi_go_bits[24]; + + uint64_t mi_test = 0; + uint64_t go_test = 0; + uint64_t mi_corrected = 0; + uint64_t go_corrected = 0; + + mi_test = (state->late_entry_mi_fragment[slot][1][0] << 32L) | (state->late_entry_mi_fragment[slot][2][0] << 28) | (state->late_entry_mi_fragment[slot][3][0] << 24) | + (state->late_entry_mi_fragment[slot][1][1] << 20) | (state->late_entry_mi_fragment[slot][2][1] << 16) | (state->late_entry_mi_fragment[slot][3][1] << 12) | + (state->late_entry_mi_fragment[slot][1][2] << 8) | (state->late_entry_mi_fragment[slot][2][2] << 4) | (state->late_entry_mi_fragment[slot][3][2] << 0); + + go_test = (state->late_entry_mi_fragment[slot][4][0] << 32L) | (state->late_entry_mi_fragment[slot][5][0] << 28) | (state->late_entry_mi_fragment[slot][6][0] << 24) | + (state->late_entry_mi_fragment[slot][4][1] << 20) | (state->late_entry_mi_fragment[slot][5][1] << 16) | (state->late_entry_mi_fragment[slot][6][1] << 12) | + (state->late_entry_mi_fragment[slot][4][2] << 8) | (state->late_entry_mi_fragment[slot][5][2] << 4) | (state->late_entry_mi_fragment[slot][6][2] << 0); + + for (j = 0; j < 3; j++) + { + for (i = 0; i < 12; i++) + { + mi_go_bits[i] = (( mi_test << (i+j*12) ) & 0x800000000) >> 35; + mi_go_bits[i+12] = (( go_test << (i+j*12) ) & 0x800000000) >> 35; + } + //execute golay decode and assign pass or fail to g + if ( Golay_24_12_decode(mi_go_bits) ) g[j] = 1; + else g[j] = 0; + + for (i = 0; i < 12; i++) + { + mi_corrected = mi_corrected << 1; + mi_corrected |= mi_go_bits[i]; + go_corrected = go_corrected << 1; + go_corrected |= mi_go_bits[i+12]; + } + } + + int mi_final = 0; + mi_final = (mi_corrected >> 4) & 0xFFFFFFFF; + + if (g[0] && g[1] && g[2]) + { + if (slot == 0 && state->payload_algid != 0) + { + if (state->payload_mi != mi_final) + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_mi, mi_final); + state->payload_mi = mi_final; + fprintf (stderr, "%s", KNRM); + } + } + if (slot == 1 && state->payload_algidR != 0) + { + if (state->payload_miR != mi_final) + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_miR, mi_final); + state->payload_miR = mi_final; + fprintf (stderr, "%s", KNRM); + } + } + + } + +} + +void dmr_alg_refresh (dsd_opts * opts, dsd_state * state) +{ + if (state->currentslot == 0) + { + state->dropL = 256; + + if (state->K1 != 0) + { + state->DMRvcL = 0; + } + + if (state->payload_algid >= 0x21) + { + LFSR (state); + fprintf (stderr, "\n"); + } + } + if (state->currentslot == 1) + { + state->dropR = 256; + + if (state->K1 != 0) + { + state->DMRvcR = 0; + } + + if (state->payload_algidR >= 0x21) + { + LFSR (state); + fprintf (stderr, "\n"); + } + } + +} + +void dmr_alg_reset (dsd_opts * opts, dsd_state * state) +{ + state->dropL = 256; + state->dropR = 256; + state->DMRvcL = 0; + state->DMRvcR = 0; + state->payload_miP = 0; +} + diff --git a/src/dmr_ms.c b/src/dmr_ms.c index ba693a3..bc732eb 100644 --- a/src/dmr_ms.c +++ b/src/dmr_ms.c @@ -1,40 +1,58 @@ +/*------------------------------------------------------------------------------- + * dmr_ms.c + * DMR MS/Simplex/Direct Mode Voice Handling and Data Gathering Routines + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + #include "dsd.h" #include "dmr_const.h" //A subroutine for processing MS voice void dmrMS (dsd_opts * opts, dsd_state * state) { - //fprintf (stderr, "\n Quick DMR Voice Testing\n"); + int i, j, k, l, dibit; int *dibit_p; - char ambe_fr[4][24] = {0}; - char ambe_fr2[4][24] = {0}; - char ambe_fr3[4][24] = {0}; - char ambe_fr4[4][24] = {0}; - char t_ambe_fr[4][24] = {9}; - char t_ambe_fr2[4][24] = {9}; - char t_ambe_fr3[4][24] = {9}; + char ambe_fr[4][24]; + char ambe_fr2[4][24]; + char ambe_fr3[4][24]; + char ambe_fr4[4][24]; + + //memcpy of ambe_fr for late entry + char m1[4][24]; + char m2[4][24]; + char m3[4][24]; + const int *w, *x, *y, *z; char sync[25]; char syncdata[48]; - //standalone inbound rc sync exists on dibits 48-96? - //or 44-92? of each potential payload, middle 10 ms or 30 ms frame - char rcsync[25]; - char rcsyncdata[96]; //96 bit RC sync data - char cachdata[13] = {0}; - int mutecurrentslot; - int msMode; - char cc[4]; - unsigned char EmbeddedSignalling[16]; - unsigned char EmbeddedSignallingInverse[16]; - int EmbeddedSignallingOk; - unsigned int internalcolorcode; - int internalslot; - int activeslot; - char redundancyA[36]; - char redundancyB[36]; - unsigned short int vc1; - unsigned short int vc2; + char EmbeddedSignalling[16]; + + //cach + char cachdata[25]; + int cachInterleave[24] = + {0, 7, 8, 9, 1, 10, + 11, 12, 2, 13, 14, + 15, 3, 16, 4, 17, 18, + 19, 5, 20, 21, 22, 6, 23 + }; + + //cach tact bits + uint8_t tact_bits[7]; + + uint8_t emb_ok = 0; + uint8_t tact_okay = 0; + uint8_t cach_err = 0; + uint8_t EmbeddedSignallingOk = 0; + + uint8_t internalslot; + uint8_t vc; + + //dummy bits to pass to dburst for link control + uint8_t dummy_bits[196]; + memset (dummy_bits, 0, sizeof (dummy_bits)); //add time to mirror printFrameSync time_t now; @@ -53,39 +71,43 @@ void dmrMS (dsd_opts * opts, dsd_state * state) return curr; } - //Init the color code status - state->color_code_ok = 0; + vc = 2; - vc1 = 2; - vc2 = 2; - - short int loop = 1; short int skipcount = 0; - //Hardset variables for MS + //Hardset variables for MS/Mono state->currentslot = 0; //0 - internalslot = 0; - activeslot = 0; - //Run Loop while the getting is good - while (loop == 1) { + //Note: Manual dibit inversion required here since I didn't seperate inverted return from normal return in framesync, + //so getDibit doesn't know to invert it before it gets here - short int m = 0; - - state->dmrburstL = 16; //Use 16 for Voice + for (j = 0; j < 6; j++) { + state->dmrburstL = 16; for(i = 0; i < 12; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } + if(opts->inverted_dmr == 1) dibit = (dibit ^ 2); + cachdata[i] = dibit; state->dmr_stereo_payload[i] = dibit; - } + for (i = 0; i < 7; i++) + { + tact_bits[i] = cachdata[i]; + } + + tact_okay = 0; + if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1; + if (tact_okay != 1) + { + //do nothing since we aren't loop locked forever. + } + + //internalslot = tact_bits[1]; + internalslot = 0; + //Setup for first AMBE Frame //Interleave Schedule w = rW; @@ -97,12 +119,10 @@ void dmrMS (dsd_opts * opts, dsd_state * state) for(i = 0; i < 36; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } + if(opts->inverted_dmr == 1) dibit = (dibit ^ 2); + state->dmr_stereo_payload[i+12] = dibit; - redundancyA[i] = dibit; + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr[*y][*z] = (1 & dibit); // bit 0 @@ -113,20 +133,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state) } - //check for repetitive data if caught in a 'no carrier' loop? Just picking random values. - //this will test for no carrier (input signal) and return us to no sync state if necessary - if (redundancyA[16] == redundancyB[16] && redundancyA[27] == redundancyB[27] && - redundancyA[01] == redundancyB[01] && redundancyA[32] == redundancyB[32] && - redundancyA[03] == redundancyB[03] && redundancyA[33] == redundancyB[33] && - redundancyA[13] == redundancyB[13] && redundancyA[07] == redundancyB[07] ) - { - //goto END; - } - for(i = 0; i < 36; i++) - { - redundancyB[i] = redundancyA[i]; - } - //Setup for Second AMBE Frame //Interleave Schedule w = rW; @@ -138,10 +144,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state) for(i = 0; i < 18; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } + if(opts->inverted_dmr == 1) dibit = (dibit ^ 2); + state->dmr_stereo_payload[i+48] = dibit; ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr2[*y][*z] = (1 & dibit); // bit 0 @@ -157,85 +161,37 @@ void dmrMS (dsd_opts * opts, dsd_state * state) for(i = 0; i < 24; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } + if(opts->inverted_dmr == 1) dibit = (dibit ^ 2); + state->dmr_stereo_payload[i+66] = dibit; + syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1 syncdata[(2*i)+1] = (1 & dibit); // bit 0 + sync[i] = (dibit | 1) + 48; - if (i < 4 || i > 19) // + // load the superframe to do embedded signal processing + if(vc > 1 && vc < 6) //grab on vc1 values 2-5 B C D and E { - EmbeddedSignalling[2*i] = (1 & (dibit >> 1)); // bit 1 - EmbeddedSignalling[2*i+1] = (1 & dibit); // bit 0 - } - - // load the superframe to do the voiceburstsync processing - if(internalslot == 0 && vc1 > 1 && vc1 < 6) //grab on vc1 values 2-5 B C D and E - { - /* Time slot 1 superframe buffer filling => SYNC data */ - state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2+1] = (1 & dibit); // bit 0 - } - if(internalslot == 1 && vc2 > 1 && vc2 < 6) //grab on vc2 values 2-5 B C D and E - { - /* Time slot 2 superframe buffer filling => SYNC data */ - state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2+1] = (1 & dibit); // bit 0 + state->dmr_embedded_signalling[internalslot][vc-1][i*2] = (1 & (dibit >> 1)); // bit 1 + state->dmr_embedded_signalling[internalslot][vc-1][i*2+1] = (1 & dibit); // bit 1 } } sync[24] = 0; EmbeddedSignallingOk = -1; - - // for (i = 0; i < 16; i++) - // { - // EmbeddedSignallingInverse[i] = EmbeddedSignalling[i] ^ 1; - // } - if(QR_16_7_6_decode(EmbeddedSignalling)) { EmbeddedSignallingOk = 1; } - //test for inverted signal - this should move to data, and have a slottype check here perhaps? - // else if (QR_16_7_6_decode(EmbeddedSignallingInverse)) - // { - // if (opts->inverted_dmr == 0) - // { - // opts->inverted_dmr = 1; - // } - // else opts->inverted_dmr = 0; - // goto END; - // } - - internalcolorcode = 69; //set so we know if this value is being set properly - if(EmbeddedSignallingOk == 1) - { - state->color_code = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); - internalcolorcode = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); - state->color_code_ok = EmbeddedSignallingOk; - //Power Indicator, not the other PI (header) - state->PI = (unsigned int)EmbeddedSignalling[4]; - state->PI_ok = EmbeddedSignallingOk; - //Link Control Start Stop Indicator - state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]); - state->LCSS_ok = EmbeddedSignallingOk; - - } - //else skipcount++; - //Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling for(i = 0; i < 18; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } + if(opts->inverted_dmr == 1) dibit = (dibit ^ 2); + state->dmr_stereo_payload[i+90] = dibit; ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr2[*y][*z] = (1 & dibit); // bit 0 @@ -245,12 +201,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state) y++; z++; - //WIP for RC inbound sync data, part 2, second 24 bits (12 dibits) - if (i <= 12) - { - rcsyncdata[i+12] = (dibit | 1) + 48; //test and double check positions for this sync data - } - } //Setup for Third AMBE Frame @@ -264,10 +214,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state) for(i = 0; i < 36; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } + if(opts->inverted_dmr == 1) dibit = (dibit ^ 2); + state->dmr_stereo_payload[i+108] = dibit; ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr3[*y][*z] = (1 & dibit); // bit 0 @@ -277,229 +225,64 @@ void dmrMS (dsd_opts * opts, dsd_state * state) y++; z++; - } - if ( ((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) && opts->inverted_dmr == 0) || - ((strcmp (sync, DMR_MS_DATA_SYNC) == 0) && opts->inverted_dmr == 1) ) + state->dmr_ms_mode = 1; + memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2)); + + //copy ambe_fr frames first, running process mbe will correct them, + //but this also leads to issues extracting good le mi values when + //we go to do correction on them there too + memcpy (m1, ambe_fr, sizeof(m1)); + memcpy (m2, ambe_fr2, sizeof(m2)); + memcpy (m3, ambe_fr3, sizeof(m3)); + + if (state->directmode == 0) { - if (internalslot == 0) - { - vc1 = 1; - state->DMRvcL = 0; //reset here if jitter/sync forces reset - fprintf (stderr, "MS Slot 1 Voice Sync \n"); - } - - if (internalslot == 1) - { - vc2 = 1; - state->DMRvcR = 0; //reset here if jitter/sync forces reset - } - - state->dmr_ms_mode = 1; //set to 1 here?? + processMbeFrame (opts, state, NULL, ambe_fr, NULL); + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); } - - state->dmr_ms_mode = 1; //set to 1 here? - - //don't know if we will catch an RC sync in here or not, should be on VC6 if it occurs - if ( (strcmp (rcsync, DMR_RC_DATA_SYNC) == 0) || (strcmp (sync, DMR_RC_DATA_SYNC) == 0) ) //should be in same position as sync + else { - fprintf (stderr,"%s ", getTime()); - if (internalslot == 0) - { - sprintf(state->slot1light, "[slot1]"); - sprintf(state->slot2light, " slot2 "); - //fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | RC ", state->color_code); - fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | RC ", state->color_code); - //test with vc1 reset disabled, if all is well, leave disabled - //vc1 = 1; - } - if (internalslot == 1) - { - sprintf(state->slot2light, "[slot2]"); - sprintf(state->slot1light, " slot1 "); - //fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | RC ", state->color_code); - fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | RC ", state->color_code); - //test with vc1 reset disabled, if all is well, leave disabled - //vc2 = 1; - } - fprintf (stderr, "\n "); //21 spaces to line up the sync - //processDMRdata (opts, state); - state->dmr_ms_rc = 1; //don't know what to do with this, if anything... - goto SKIP; + processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); } - //check for sync pattern here after collected the rest of the payload, decide what to do with it - //if ( (strcmp (sync, DMR_MS_DATA_SYNC) == 0) ) - //fixed to compensate for inverted signal - if ( ((strcmp (sync, DMR_MS_DATA_SYNC) == 0) && opts->inverted_dmr == 0) || - ((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) && opts->inverted_dmr == 1) ) + if (vc == 6) { - fprintf (stderr,"%s ", getTime()); - if (internalslot == 0) - { - sprintf(state->slot1light, "[slot1]"); - sprintf(state->slot2light, " slot2 "); - //fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | MS Data ", state->color_code); - if (opts->inverted_dmr == 0) - { - fprintf (stderr,"Sync: +DMR "); - } - else fprintf (stderr,"Sync: -DMR "); - //test with vc1 reset disabled, if all is well, leave disabled - //vc1 = 1; - } - if (internalslot == 1) - { - sprintf(state->slot2light, "[slot2]"); - sprintf(state->slot1light, " slot1 "); - //fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | Data ", state->color_code); - if (opts->inverted_dmr == 0) - { - fprintf (stderr,"Sync: +DMR MS/DM MODE "); - } - else fprintf (stderr,"Sync: -DMR MS/DM MODE "); - //test with vc1 reset disabled, if all is well, leave disabled - //vc2 = 1; - } - //fprintf (stderr, "\n "); //21 spaces to line up the sync - //fprintf (stderr, " "); //21 spaces to line up the sync - state->dmr_ms_mode = 1; //set to 1 here?? - processDMRdata (opts, state); - skipcount++; - //goto SKIP; - goto END; + dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB); + fprintf (stderr, "\n"); + dmr_alg_refresh (opts, state); } - if( ( ( ((strcmp (sync, DMR_MS_DATA_SYNC) != 0) && opts->inverted_dmr == 0) || - ((strcmp (sync, DMR_MS_VOICE_SYNC) != 0) && opts->inverted_dmr == 1) ) ) - && internalslot == activeslot && vc1 < 7) + //collect the mi fragment + dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3); - { + //errors in ms/mono since we skip the other slot + // cach_err = dmr_cach (opts, state, cachdata); - skipcount = 0; //reset skip count if processing voice frames - fprintf (stderr,"%s ", getTime()); - if (internalslot == 0 && opts->inverted_dmr == 0) - { - fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc1); - if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - } - if (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - fprintf (stderr, "%s", KNRM); - } - fprintf (stderr, "\n"); - } + vc++; + //this is necessary because we need to skip and collect dibits, not just skip them + if (vc > 6) goto END; - if (internalslot == 0 && opts->inverted_dmr == 1) - { - fprintf (stderr,"Sync: -DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc1); - if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - } - if (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - fprintf (stderr, "%s", KNRM); - } - fprintf (stderr, "\n"); - } - - - if (internalslot == 0 && vc1 == 6) //presumably when full (and no sync issues) - { - //process voice burst - ProcessVoiceBurstSync(opts, state); - fprintf (stderr, "\n"); - } - - state->dmr_ms_mode == 1; - memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2)); - - //state->directmode = 0; //flag off for testing - - if (state->directmode == 0) - { - processMbeFrame (opts, state, NULL, ambe_fr, NULL); - processMbeFrame (opts, state, NULL, ambe_fr2, NULL); - processMbeFrame (opts, state, NULL, ambe_fr3, NULL); - } - else - { - processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio - processMbeFrame (opts, state, NULL, ambe_fr2, NULL); - processMbeFrame (opts, state, NULL, ambe_fr3, NULL); - } - - if (vc1 == 6 && state->payload_algid >= 21) - { - state->DMRvcL = 0; - if (state->payload_mi != 0 && state->payload_algid >= 0x21) - { - LFSR(state); - } - fprintf (stderr, "\n"); - } - } - vc1++; - //6 seems optimal for MS, allows to quickly exit and resync if wonky or something - if ( (vc1 > 6) || skipcount > 2) //escape to find new sync if deadspins without a renewed voice frame sync inside of loop - { - goto END; - } - - SKIP: skipDibit (opts, state, 144); //skip to next tdma channel state->dmr_ms_rc = 0; - //since we are in a repetitive loop, run ncursesPrinter here + //since we are in a loop, run ncursesPrinter here if (opts->use_ncurses_terminal == 1) { ncursesPrinter(opts, state); } - } // end while loop - //reset these variables when exiting MS/DM mode. + } // end loop + END: //get first half payload dibits and store them in the payload for the next repitition - skipDibit (opts, state, 144); + skipDibit (opts, state, 144); //should we have two of these? + //CACH + First Half Payload = 12 + 54 for (i = 0; i < 66; i++) //66 { @@ -516,7 +299,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state) state->dmr_ms_mode = 0; state->dmr_ms_rc = 0; state->directmode = 0; //flag off - state->DMRvcL = 0; + } @@ -525,19 +308,39 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) { int i, j, k, l, dibit; int *dibit_p; - char ambe_fr[4][24] = {0}; - char ambe_fr2[4][24] = {0}; - char ambe_fr3[4][24] = {0}; - char ambe_fr4[4][24] = {0}; //shim for playing back direct mode samples where ambe1 is bad, duplicate 2 to 4 and play both to smooth audio + + char ambe_fr[4][24]; + char ambe_fr2[4][24]; + char ambe_fr3[4][24]; + char ambe_fr4[4][24]; //shim for crappy tdma direct, need more samples to see if this is really a necessary shim or not + + //memcpy of ambe_fr for late entry + char m1[4][24]; + char m2[4][24]; + char m3[4][24]; + const int *w, *x, *y, *z; char sync[25]; char syncdata[48]; - char cachdata[13] = {0}; + + //cach + char cachdata[25]; + int cachInterleave[24] = + {0, 7, 8, 9, 1, 10, + 11, 12, 2, 13, 14, + 15, 3, 16, 4, 17, 18, + 19, 5, 20, 21, 22, 6, 23 + }; + int mutecurrentslot; int msMode; char cc[4]; - unsigned char EmbeddedSignalling[16]; - unsigned int EmbeddedSignallingOk; + char EmbeddedSignalling[16]; + + uint8_t emb_ok = 0; + uint8_t tact_okay = 0; + uint8_t cach_err = 0; + uint8_t EmbeddedSignallingOk = 0; //add time to mirror sync time_t now; @@ -555,8 +358,8 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) return curr; } - - state->dmrburstL = 16; //Use 16 for Voice? + + state->dmrburstL = 16; state->currentslot = 0; //force to slot 0 dibit_p = state->dmr_payload_p - 90; @@ -594,7 +397,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } - //state->dmr_stereo_payload[i+12] = dibit; + state->dmr_stereo_payload[i+12] = dibit; ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr[*y][*z] = (1 & dibit); // bit 0 @@ -630,12 +433,11 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) z++; } - + //Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling for(i = 0; i < 18; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) { dibit = (dibit ^ 2); @@ -675,86 +477,28 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) z++; } - //work around to set erroneous PI header values to 0 if K is active - if (state->K > 0 || state->K1 > 0) - { - state->payload_keyid = 0; //just for testing - state->payload_keyidR = 0; //just for testing - } - - fprintf (stderr,"%s ", getTime()); + fprintf (stderr, "%s ", getTime()); if (opts->inverted_dmr == 0) { - fprintf (stderr,"Sync: +DMR MS/DM MODE | Frame Sync | DMRSTEREO | VC1 "); - if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) || - (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x10) ) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - } - if ( (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) || - (state->DMRvcR == 0 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x68) ) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - } - fprintf (stderr, "%s", KNRM); - fprintf (stderr, "\n"); - } - else - { - fprintf (stderr,"Sync: -DMR MS/DM MODE | Frame Sync | DMRSTEREO | VC1 "); - if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) || - (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x10) ) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - } - if ( (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) || - (state->DMRvcR == 0 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x68) ) - { - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %016llX", state->K1); - if (state->K2 != 0) - { - fprintf(stderr, " %016llX", state->K2); - } - if (state->K3 != 0) - { - fprintf(stderr, " %016llX", state->K3); - } - if (state->K4 != 0) - { - fprintf(stderr, " %016llX", state->K4); - } - } - fprintf (stderr, "%s", KNRM); - fprintf (stderr, "\n"); + fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO "); } + else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO "); - state->dmr_ms_mode = 1; - state->DMRvcL = 0; + fprintf (stderr, "| VC* "); + fprintf (stderr, "\n"); + + //alg reset + //dmr_alg_reset (opts, state); memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2)); - //state->directmode = 0; //flag off for testing samples + //copy ambe_fr frames first, running process mbe will correct them, + //but this also leads to issues extracting good le mi values when + //we go to do correction on them there too + memcpy (m1, ambe_fr, sizeof(m1)); + memcpy (m2, ambe_fr2, sizeof(m2)); + memcpy (m3, ambe_fr3, sizeof(m3)); if (state->directmode == 0) { @@ -768,25 +512,24 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) processMbeFrame (opts, state, NULL, ambe_fr2, NULL); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); } - + + //collect the mi fragment + dmr_late_entry_mi_fragment (opts, state, 1, ambe_fr, ambe_fr2, ambe_fr3); + + //errors due to skipping other slot + // cach_err = dmr_cach (opts, state, cachdata); skipDibit (opts, state, 144); //skip to next TDMA slot dmrMS (opts, state); //bootstrap into full TDMA frame } +//simplied to a simple data collector, and then passed on to dmr_data_sync for the usual processing void dmrMSData (dsd_opts * opts, dsd_state * state) { int i, b, c; int dibit; int *dibit_p; - unsigned int burst; - - unsigned char MSCach[24] = {0}; //12 dibits = 24 bits - unsigned char MSSync[48] = {0}; //24 dibits = 48 bits - unsigned char MSSlot[20] = {0}; //10 dibits = 20 bits - unsigned char MSBurst[5] = {0}; - int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23}; //add time to mirror sync time_t now; @@ -804,8 +547,7 @@ void dmrMSData (dsd_opts * opts, dsd_state * state) return curr; } - b = 0; - c = 0; + //CACH + First Half Payload + Sync = 12 + 54 + 24 dibit_p = state->dmr_payload_p - 90; @@ -813,94 +555,25 @@ void dmrMSData (dsd_opts * opts, dsd_state * state) { dibit = *dibit_p; dibit_p++; - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } + if(opts->inverted_dmr == 1) dibit = (dibit ^ 2); state->dmr_stereo_payload[i] = dibit; - //load cach - if (i < 12) - { - MSCach[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1 - MSCach[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0 - } - //load slot, first half - if (i > 60 && i < 66) - { - MSSlot[(b*2)] = (1 & (dibit >> 1)); // bit 1 - MSSlot[(b*2)+1] = (1 & dibit); // bit - b++; - } - //load sync - if (i > 66) - { - MSSync[(c*2)] = (1 & (dibit >> 1)); // bit 1 - MSSync[(c*2)+1] = (1 & dibit); // bit 0 - c++; - } + } for (i = 0; i < 54; i++) { dibit = getDibit(opts, state); - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } + if(opts->inverted_dmr == 1) dibit = (dibit ^ 2); state->dmr_stereo_payload[i+90] = dibit; - //load slot, second half - if (i < 6) - { - MSSlot[(b*2)] = (1 & (dibit >> 1)); // bit 1 - MSSlot[(b*2)+1] = (1 & dibit); // bit - b++; - } } - //state->directmode = 0; //flag off for testing - - //with FEC fix, now we can (hopefully) feel confident in running MS data - if (1 == 1) //opts->payload == 1 && state->directmode == 0 + fprintf (stderr, "%s ", getTime()); + if (opts->inverted_dmr == 0) { - fprintf (stderr, "%s ", getTime()); - if (opts->inverted_dmr == 0) - { - fprintf (stderr,"Sync: +DMR MS/DM MODE "); - } - else fprintf (stderr,"Sync: -DMR MS/DM MODE "); + fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO "); } - - // decode and correct cach and slot - // golay (20,8) hamming-weight of 6 reliably corrects at most 2 bit-errors - int cach_okay = -1; - if ( Hamming_7_4_decode (MSCach) ) - { - cach_okay = 1; - } - if (cach_okay == 1) - { - //fprintf (stderr, "CACH Okay "); - } - else - { - //fprintf (stderr, "CACH ERR "); - if (opts->aggressive_framesync == 1) //may not worry about it on data - { - goto END; - } - } - - int slot_okay = -1; - if(Golay_20_8_decode(MSSlot)) - { - slot_okay = 1; - } - if (slot_okay == 1) - { - //fprintf (stderr, "Slot Okay "); - } - else goto END; + else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO "); sprintf(state->slot1light, "%s", ""); @@ -910,33 +583,23 @@ void dmrMSData (dsd_opts * opts, dsd_state * state) state->dmr_stereo = 1; state->dmr_ms_mode = 1; - //with FEC fix, now we can (hopefully) feel confident in running MS data - if (1 == 1) //opts->payload == 1 && state->directmode == 0 - { - processDMRdata (opts, state); - } - - END: - if (slot_okay != 1 || cach_okay != 1) - { - fprintf (stderr, "%s", KRED); - fprintf (stderr, "| ** CACH or Burst Type FEC ERR ** "); - fprintf (stderr, "%s", KNRM); - fprintf (stderr, "\n"); - } + dmr_data_sync (opts, state); state->dmr_stereo = 0; state->dmr_ms_mode = 0; state->directmode = 0; //flag off - //get potential first half payload dibits and store them in the payload for the next repitition, MS voice or data. - skipDibit (opts, state, 144); - + //should just be loaded in the dmr_payload_buffer instead now + for (i = 0; i < 144; i++) //66 + { + dibit = getDibit(opts, state); + state->dmr_stereo_payload[i] = dibit; + } //CACH + First Half Payload = 12 + 54 for (i = 0; i < 66; i++) //66 { dibit = getDibit(opts, state); - state->dmr_stereo_payload[i] = dibit; + state->dmr_stereo_payload[i] = dibit; } } diff --git a/src/dmr_pdu.c b/src/dmr_pdu.c new file mode 100644 index 0000000..0939079 --- /dev/null +++ b/src/dmr_pdu.c @@ -0,0 +1,369 @@ +/*------------------------------------------------------------------------------- + * dmr_bs.c + * DMR Data (1/2, 3/4, 1) PDU Decoding + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + +//unified DMR multiblock PDU message handler (LRRP, etc) +#include "dsd.h" + +char * getTimeL(void) //get pretty hh:mm:ss timestamp +{ + time_t t = time(NULL); + + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; +} + +char * getDateL(void) { + char datename[120]; + char * curr2; + struct tm * to; + time_t t; + t = time(NULL); + to = localtime( & t); + strftime(datename, sizeof(datename), "%Y/%m/%d", to); + curr2 = strtok(datename, " "); + return curr2; +} + +void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[]) +{ + + int message_legnth = 0; + uint8_t slot = state->currentslot; + uint8_t blocks = state->data_header_blocks[slot] - 1; //subtract 1 for the relevant value in the calc below + uint8_t padding = state->data_header_padding[slot]; + uint8_t lrrp_conf = 0; + + lrrp_conf = dmr_lrrp_check (opts, state, DMR_PDU); + + //maybe one day we will have more things to do here + state->data_conf_data[slot] = 0; //flag off confirmed data after processing it + +} + +//The contents of this function are mostly my reversed engineered efforts by observing DSDPlus output and matching data bytes +//combined with a few external sources such as OK-DMR for some token values and extra data values (rad and alt) +//this is by no means an extensive LRRP list and is prone to error (unless somebody has the manual or something) +uint8_t dmr_lrrp_check (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[]) +{ + int i, j; + uint8_t message_len = 0; + uint8_t slot = state->currentslot; + uint8_t blocks = state->data_header_blocks[slot] - 1; + uint8_t padding = state->data_header_padding[slot]; + uint8_t lrrp_confidence = 0; //variable to increment based on number of tokens found, the more, the higher the confidence level + + //source/dest and ports + uint32_t source = 0; + uint32_t dest = 0; + uint16_t port_s = 0; + uint16_t port_d = 0; + + //time + uint16_t year = 0; + uint16_t month = 0; + uint16_t day = 0; + uint16_t hour = 0; + uint16_t minute = 0; + uint16_t second = 0; + + //lat-long-radius-alt + uint32_t lat = 0; + uint8_t lat_sign = 0; + uint32_t lon = 0; + uint16_t rad = 0; + uint8_t alt = 0; + double lat_unit = (double)180/(double)4294967295; + double lon_unit = (double)360/(double)4294967295; + + //speed/velocity + uint16_t vel = 0; + double velocity = 0; + uint8_t vel_set = 0; + + //track, direction, degrees + uint8_t degrees = 0; + uint8_t deg_set = 0; + + //triggered information report + uint8_t report = 0; + uint8_t pot_report = 0; //potential report by findind 0x0D and backtracking a few bytes + + i = 0; //watch DMR_PDU[10] closely for a 'report' token + //start looking for tokens (using my best understanding of the ok-dmr library xml and python files) + for (i; i < ( ((blocks+1)*16) - (padding+4) ); i++) //need to change the 16, or entire thing? or who cares lol just keep looking + { + + switch(DMR_PDU[i]){ + case 0x0C: //LRRP_TriggeredLocationReport + if (source == 0) + { + source = (DMR_PDU[i+1] << 16 ) + (DMR_PDU[i+2] << 8) + DMR_PDU[i+3]; + dest = (DMR_PDU[i+5] << 16 ) + (DMR_PDU[i+6] << 8) + DMR_PDU[i+7]; + port_s = (DMR_PDU[i+8] << 8) + DMR_PDU[i+9]; + port_d = (DMR_PDU[i+10] << 8) + DMR_PDU[i+11]; + i += 11; + lrrp_confidence++; + } + break; + //may need more 'report' types to trigger various scenarios + //disable all but 0x1F if issues or falsing happens often + //case 0x1D: //ARRP_TriggeredInformationAnswer_NCDT + //case 0x1E: //ARRP_TriggeredInformationReport = FALSE? + //case 0x25: //ARRP_UnsolicitedInformationReport_NCDT = (0x25, True, "") + case 0x13: //LRRP_UnsolicitedLocationReport_NCDT + case 0x15: //LRRP_LocationProtocolReport_NCDT + case 0x21: //ARRP_TriggeredInformationStopRequest_NCDT + case 0x1F: //ARRP_TriggeredInformationReport_NCDT + if (report == 0) + { + report = DMR_PDU[i]; + i += 1; + lrrp_confidence++; + } + break; + //0x0D always seems to follow 0x1F or other 'report' types two/three bytes later + case 0x0D: //message len indicator //LRRP_TriggeredLocationReport_NCDT + if (report > 0 && message_len == 0) + { + message_len = DMR_PDU[i+1]; + i += 1; + lrrp_confidence++; + } + else if (message_len == 0) + { + if (i > 3) + { + if (DMR_PDU[i-3] > 0) pot_report = DMR_PDU[i-3]; + if (pot_report < 0x27) + { + report = pot_report; + message_len = DMR_PDU[i+1]; + i += 1; + //no lrrp_confidence on speculative reporting, but will print it as such. + } + } + + } + break; + //RESULT TOKEN or Request ID! + case 0x23: //this value has been seen after the 0x0D message len, appears to be a 2-byte value, was tripping a false on time stamp + i += 2; + break; + //answer and report tokens + case 0x51: //circle-2d + case 0x54: //circle-3d + case 0x55: //circle-3d <- false positives on one sample, so either an earlier token occurred (that we don't have) or just random data? + if (message_len > 0 && lat == 0) + { + if (DMR_PDU[i+1] & 0x80) lat_sign = 1; + lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 ); + lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 ); + rad = (DMR_PDU[i+9] << 8) + DMR_PDU[i+10]; + i += 10; //double check + lrrp_confidence++; + } + break; + + case 0x34: //Time Interval Periodic Trigger (timestamp) + case 0x35: //Time Interval Periodic Trigger (timestamp) + if (message_len > 0 && year == 0) + { + year = (DMR_PDU[i+1] << 6) + (DMR_PDU[i+2] >> 2); + month = ((DMR_PDU[i+2] & 0x3) << 2) + ((DMR_PDU[i+3] & 0xC0) >> 6); + day = ((DMR_PDU[i+3] & 0x30) >> 1) + ((DMR_PDU[i+3] & 0x0E) >> 1); + hour = ((DMR_PDU[i+3] & 0x01) << 4) + ((DMR_PDU[i+4] & 0xF0) >> 4); + minute = ((DMR_PDU[i+4] & 0x0F) << 2) + ((DMR_PDU[i+5] & 0xC0) >> 6); + second = (DMR_PDU[i+5] & 0x3F); + i += 5; + //sanity check + if (year > 2000 && year < 2025) lrrp_confidence++; + if (year > 2025 || year < 2000) year = 0; //needs future proofing + } + break; + + case 0x66: //point-2d + if (message_len > 0 && lat == 0) + { + if (DMR_PDU[i+1] & 0x80) lat_sign = 1; + lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 ); + lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 ); + i += 8; //check + lrrp_confidence++; + } + break; + case 0x69: //point-3d + case 0x6A: //point-3d + if (message_len > 0 && lat == 0) + { + if (DMR_PDU[i+1] & 0x80) lat_sign = 1; + lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 ); + lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 ); + alt = DMR_PDU[i+9]; + i += 9; //check + lrrp_confidence++; + } + break; + case 0x36: //protocol-version + i += 1; + //lrrp_confidence++; + break; + //speed/velocity + case 0x70: //speed-virt + case 0x6C: //speed-hor + if (message_len > 0 && vel_set == 0) + { + vel = (DMR_PDU[i+1] << 8) + DMR_PDU[i+2]; //don't think this is meant to be shifted, but doing it anyways for comparison + velocity = ( ((double)( (DMR_PDU[i+1] ) + DMR_PDU[i+2] )) / ( (double)128)); + vel_set = 1; + i += 2; + lrrp_confidence++; + } + break; + case 0x56: //direction-hor + if (message_len > 0 && deg_set == 0) + { + degrees = DMR_PDU[i+1] * 2; + deg_set = 1; + i += 1; + lrrp_confidence++; + } + break; + //below all unknown + case 0x37: //result + case 0x38: //result + case 0x39: //result 'operations error'? attributes 0x22? + case 0x6B: //unknown-uint8 + case 0x65: //lev-conf + default: + //do nothing + break; + } + } + if (report && message_len > 0) + { + fprintf (stderr, "%s", KYEL); + fprintf (stderr, "\n LRRP Confidence: %d - Message Len: %d", lrrp_confidence, message_len); + if (lrrp_confidence >= 3) //find the sweet magical number + { + //now we can open our lrrp file and write to it as well + FILE * pFile; //file pointer + if (opts->lrrp_file_output == 1) + { + //open file by name that is supplied in the ncurses terminal, or cli + pFile = fopen (opts->lrrp_out_file, "a"); + //write current date/time if not present in LRRP data + if (!year) fprintf (pFile, "%s\t", getDateL() ); //current date, only add this IF no included timestamp in LRRP data? + if (!year) fprintf (pFile, "%s\t", getTimeL() ); //current timestamp, only add this IF no included timestamp in LRRP data? + if (year) fprintf (pFile, "%04d/%02d/%02d\t%02d:%02d:%02d\t", year, month, day, hour, minute, second); //add timestamp from decoded audio if available + //write data header source (or destination?) if not available in lrrp data + if (!source) fprintf (pFile, "%08lld\t", state->dmr_lrrp_source[state->currentslot]); //source address from data header + if (source) fprintf (pFile, "%08d\t", source); //add source form decoded audio if available, else its from the header + } + + if (pot_report) + { + fprintf (stderr, "\n"); + fprintf (stderr, " Potential ARRP/LRRP Report (Debug): 0x%02X", report); + } + if (report) + { + fprintf (stderr, "\n"); + fprintf (stderr, " Report: 0x%02X", report); + if (report == 0x1F) fprintf (stderr, " ARRP_TriggeredInformationReport_NCDT "); //customize later when more is learned + if (report == 0x21) fprintf (stderr, " ARRP_TriggeredInformationStopRequest_NCDT "); + if (report == 0x22) fprintf (stderr, " ARRP_TriggeredInformationStopAnswer "); + if (report == 0x25) fprintf (stderr, " ARRP_UnsolicitedInformationReport_NCDT "); + if (report == 0x26) fprintf (stderr, " ARRP_UnsolicitedInformationReport_NCDT "); + if (report == 0x27) fprintf (stderr, " ARRP_InformationProtocolRequest_NCDT "); + if (report == 0x13) fprintf (stderr, " LRRP_UnsolicitedLocationReport_NCDT "); + + } + if (source) + { + fprintf (stderr, "\n"); + fprintf (stderr, " Source: %08d - %04d", source, port_s); + fprintf (stderr, "\n"); + fprintf (stderr, " Destination: %08d - %04d", dest, port_d); + + } + if (year) + { + fprintf (stderr, "\n"); + fprintf (stderr, " LRRP - Time: "); + fprintf (stderr, " %04d.%02d.%02d %02d:%02d:%02d", year, month, day, hour, minute, second); + + } + if (lat) + { + fprintf (stderr, "\n"); + if (lat_sign) //print a '-' in front of the value + fprintf (stderr, " LRRP - Lat: -%.5lf", (double)lat * lat_unit); + else fprintf (stderr, " LRRP - Lat: %.5lf", (double)lat * lat_unit); + fprintf (stderr, " Lon: %.5lf", (double)lon * lon_unit); + if (lat_sign) + fprintf (stderr, " (-%.5lf, %.5lf)", (double)lat * lat_unit , (double)lon * lon_unit); + else fprintf (stderr, " (%.5lf, %.5lf)", (double)lat * lat_unit , (double)lon * lon_unit); + + if (opts->lrrp_file_output == 1) + { + if (lat_sign) fprintf (pFile, "-"); + fprintf (pFile, "%.5lf\t", (double)lat * lat_unit); + fprintf (pFile, "%.5lf\t", (double)lon * lon_unit); + } + + } + if (rad) + { + fprintf (stderr, "\n"); + fprintf (stderr, " LRRP - Radius: %d", rad); //unsure of 'units' or calculation for radius (meters?) + } + if (alt) + { + fprintf (stderr, "\n"); + fprintf (stderr, " LRRP - Altitude: %d", alt); //unsure of 'units' or calculation for alt (meters?) + } + if (vel_set) + { + fprintf (stderr, "\n"); + fprintf (stderr, " LRRP - Velocity: %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity)); + if (opts->lrrp_file_output == 1) fprintf (pFile, "%.3lf\t ", (velocity * 3.6) ); + } + if (deg_set) + { + fprintf (stderr, "\n"); + fprintf (stderr, " LRRP - Track: %d Degrees", degrees); + if (opts->lrrp_file_output == 1) fprintf (pFile, "%d\t",degrees); + } + + //close open file + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "\n"); + fclose (pFile); + } + } + + } + + if (pot_report) + { + fprintf (stderr, "\n"); + fprintf (stderr, " Potential ARRP/LRRP Report (Debug): 0x%02X", report); + } + fprintf (stderr, "%s", KNRM); + + + return (lrrp_confidence); +} \ No newline at end of file diff --git a/src/dmr_pi.c b/src/dmr_pi.c new file mode 100644 index 0000000..092effa --- /dev/null +++ b/src/dmr_pi.c @@ -0,0 +1,136 @@ +/*------------------------------------------------------------------------------- + * dmr_pi.c + * DMR Privacy Indicator and LFSR Function + * + * LFSR code courtesy of https://github.com/mattames/LFSR/ + * + * LWVMOBILE + * 2022-12 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + +#include "dsd.h" + +void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors) +{ + + if((IrrecoverableErrors == 0)) + { + if (state->currentslot == 0) + { + + if (0 == 0) + { + state->payload_algid = PI_BYTE[0]; + state->payload_keyid = PI_BYTE[2]; + } + + state->payload_mi = ( ((PI_BYTE[3]) << 24) + ((PI_BYTE[4]) << 16) + ((PI_BYTE[5]) << 8) + (PI_BYTE[6]) ); + if (state->payload_algid < 0x26) + { + fprintf (stderr, "%s ", KYEL); + fprintf (stderr, "\n Slot 1"); + fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi); + fprintf (stderr, "%s ", KNRM); + } + + if (state->payload_algid >= 0x26) + { + if (0 == 0) + { + state->payload_algid = 0; + state->payload_keyid = 0; + state->payload_mi = 0; + } + } + } + + if (state->currentslot == 1) + { + if (0 == 0) + { + state->payload_algidR = PI_BYTE[0]; + state->payload_keyidR = PI_BYTE[2]; + } + + state->payload_miR = ( ((PI_BYTE[3]) << 24) + ((PI_BYTE[4]) << 16) + ((PI_BYTE[5]) << 8) + (PI_BYTE[6]) ); + if (state->payload_algidR < 0x26) + { + fprintf (stderr, "%s ", KYEL); + fprintf (stderr, "\n Slot 2"); + fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR); + fprintf (stderr, "%s ", KNRM); + } + + if (state->payload_algidR >= 0x26) + { + if (0== 0) + { + state->payload_algidR = 0; + state->payload_keyidR = 0; + state->payload_miR = 0; + } + } + } + } + + + if((IrrecoverableErrors == 0) && CRCCorrect) + { + //fprintf (stderr, " (PI CRC Okay)"); + } + else if((IrrecoverableErrors == 0)) + { + //fprintf (stderr, " (PI FEC Okay)"); + } + else { + fprintf (stderr, "%s", KRED); + fprintf (stderr, (" (PI FEC ERR)")); + fprintf (stderr, "%s ", KNRM); + } + +} + +void LFSR(dsd_state * state) +{ + int lfsr = 0; + if (state->currentslot == 0) + { + lfsr = state->payload_mi; + } + else lfsr = state->payload_miR; + + uint8_t cnt = 0; + + for(cnt=0;cnt<32;cnt++) + { + // Polynomial is C(x) = x^32 + x^4 + x^2 + 1 + int bit = ((lfsr >> 31) ^ (lfsr >> 3) ^ (lfsr >> 1)) & 0x1; + lfsr = (lfsr << 1) | (bit); + } + + if (state->currentslot == 0) + { + if (1 == 1) + { + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Slot 1"); + fprintf (stderr, " DMR PI Continuation ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid); + fprintf(stderr, " Next MI: 0x%08X", lfsr); + fprintf (stderr, "%s", KNRM); + } + state->payload_mi = lfsr; + } + + if (state->currentslot == 1) + { + if (1 == 1) + { + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Slot 2"); + fprintf (stderr, " DMR PI Continuation ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR); + fprintf(stderr, " Next MI: 0x%08X", lfsr); + fprintf (stderr, "%s", KNRM); + } + state->payload_miR = lfsr; + } +} \ No newline at end of file diff --git a/src/dmr_process_voice.c b/src/dmr_process_voice.c deleted file mode 100644 index 7d4d6d3..0000000 --- a/src/dmr_process_voice.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (C) 2010 DSD Author - * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include "dsd.h" -#include "dmr_const.h" -#include "p25p1_check_hdu.h" - -void ProcessDMR (dsd_opts * opts, dsd_state * state) -{ - uint32_t i, j; - uint32_t Frame; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameL = NULL; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameR = NULL; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameRC = NULL; //Reverse Test for MS Backwards - - int *errs; - int *errs2; - unsigned long long int k; - int x; - k = 0; - - TSVoiceSupFrameL = &state->TS1SuperFrame; - TSVoiceSupFrameR = &state->TS2SuperFrame; - -int Pr[256] = { - 0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903, - 0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306, - 0x2618, 0x3918, 0xC518, 0xDA18, 0x031B, 0x1C1B, 0xE01B, 0xFF1B, - 0x6C1D, 0x731D, 0x8F1D, 0x901D, 0x491E, 0x561E, 0xAA1E, 0xB51E, //31 - 0x4B28, 0x5428, 0xA828, 0xB728, 0x6E2B, 0x712B, 0x8D2B, 0x922B, - 0x012D, 0x1E2D, 0xE22D, 0xFD2D, 0x242E, 0x3B2E, 0xC72E, 0xD82E, - 0x6D30, 0x7230, 0x8E30, 0x9130, 0x4833, 0x5733, 0xAB33, 0xB433, - 0x2735, 0x3835, 0xC435, 0xDB35, 0x0236, 0x1D36, 0xE136, 0xFE36, //63 - 0x2B49, 0x3449, 0xC849, 0xD749, 0x0E4A, 0x114A, 0xED4A, 0xF24A, - 0x614C, 0xAE4C, 0x824C, 0x9D4C, 0x444F, 0x5B4F, 0xA74F, 0xB84F, - 0x0D51, 0x1251, 0xEE51, 0xF151, 0x2852, 0x3752, 0xCB52, 0xD452, - 0x4754, 0x5854, 0xA454, 0xBB54, 0x6257, 0x7D57, 0x8157, 0x9E57, //95 - 0x6061, 0x7F61, 0x8361, 0x9C61, 0x4562, 0x5A62, 0xA662, 0xB962, - 0x2A64, 0x3564, 0xC964, 0xD664, 0x0F67, 0x1067, 0xEC67, 0xF367, - 0x4679, 0x5979, 0xA579, 0xBA79, 0x637A, 0x7C7A, 0x807A, 0x9F7A, - 0x0C7C, 0x137C, 0xEF7C, 0xF07C, 0x297F, 0x367F, 0xCA7F, 0xD57F, //127 - 0x4D89, 0x5289, 0xAE89, 0xB189, 0x688A, 0x778A, 0x8B8A, 0x948A, - 0x078C, 0x188C, 0xE48C, 0xFB8C, 0x228F, 0x3D8F, 0xC18F, 0xDE8F, - 0x6B91, 0x7491, 0x8891, 0x9791, 0x4E92, 0x5192, 0xAD92, 0xB292, - 0x2194, 0x3E94, 0xC294, 0xDD94, 0x0497, 0x1B97, 0xE797, 0xF897, //159 - 0x06A1, 0x19A1, 0xE5A1, 0xFAA1, 0x23A2, 0x3CA2, 0xC0A2, 0xDFA2, - 0x4CA4, 0x53A4, 0xAFA4, 0xB0A4, 0x69A7, 0x76A7, 0x8AA7, 0x95A7, - 0x20B9, 0x3FB9, 0xC3B9, 0xDCB9, 0x05BA, 0x1ABA, 0xE6BA, 0xF9BA, - 0x6ABC, 0x75BC, 0x89BC, 0x96BC, 0x4FBF, 0x50BF, 0xACBF, 0xB3BF, //191 - 0x66C0, 0x79C0, 0x85C0, 0x9AC0, 0x43C3, 0x5CC3, 0xA0C3, 0xBFC3, - 0x2CC5, 0x33C5, 0xCFC5, 0xD0C5, 0x09C6, 0x16C6, 0xEAC6, 0xF5C6, - 0x84D0, 0x85DF, 0x8AD3, 0x8BDC, 0xB6D5, 0xB7DA, 0xB8D6, 0xB9D9, - 0xD0DA, 0xD1D5, 0xDED9, 0xDFD6, 0xE2DF, 0xE3D0, 0xECDC, 0xEDD3, //223 - 0x2DE8, 0x32E8, 0xCEE8, 0xD1E8, 0x08EB, 0x17EB, 0xEBEB, 0xF4EB, - 0x67ED, 0x78ED, 0x84ED, 0x9BED, 0x42EE, 0x5DEE, 0xA1EE, 0xBEEE, - 0x0BF0, 0x14F0, 0xE8F0, 0xF7F0, 0x2EF3, 0x31F3, 0xCDF3, 0xD2F3, - 0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6 //255 -}; - - -if ( (state->currentslot == 0 && state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) || - (state->currentslot == 0 && state->K > 0 && state->M == 1) ) -{ - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - k = Pr[state->K]; - k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k ); - - for(Frame = 0; Frame < 6; Frame++) - { - for(i = 0; i < 3; i++) - { - for(j = 0; j < 48; j++) - { - x = ( ((k << j) & 0x800000000000) >> 47 ); - TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x; - } - } - } -} - -if ( (state->currentslot == 1 && state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) || - (state->currentslot == 1 && state->K > 0 && state->M == 1) ) -{ - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " PrK %lld", state->K); - fprintf (stderr, "%s", KNRM); - k = Pr[state->K]; - k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k ); - - for(Frame = 0; Frame < 6; Frame++) - { - for(i = 0; i < 3; i++) - { - for(j = 0; j < 48; j++) - { - x = ( ((k << j) & 0x800000000000) >> 47 ); - TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x; - } - } - } -} - -if ( (state->currentslot == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) || - (state->currentslot == 0 && state->K1 > 0 && state->M == 1) ) -{ - - int pos = 0; - - unsigned long long int k1 = state->K1; - unsigned long long int k2 = state->K2; - unsigned long long int k3 = state->K3; - unsigned long long int k4 = state->K4; - - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %010llX", k1); - - int T_Key[256] = {0}; - int pN[882] = {0}; - - int len = 0; - - if (k2 == 0) - { - len = 39; - k1 = k1 << 24; - } - if (k2 != 0) - { - len = 127; - fprintf(stderr, " %016llX", k2); - } - if (k4 != 0) - { - len = 255; - fprintf(stderr, " %016llX", k3); - fprintf(stderr, " %016llX", k4); - } - - fprintf (stderr, "%s", KNRM); - - for (i = 0; i < 64; i++) - { - T_Key[i] = ( ((k1 << i) & 0x8000000000000000) >> 63 ); - T_Key[i+64] = ( ((k2 << i) & 0x8000000000000000) >> 63 ); - T_Key[i+128] = ( ((k3 << i) & 0x8000000000000000) >> 63 ); - T_Key[i+192] = ( ((k4 << i) & 0x8000000000000000) >> 63 ); - } - - for (i = 0; i < 882; i++) - { - pN[i] = T_Key[pos]; - pos++; - if (pos > len) - { - pos = 0; - } - } - - pos = 0; - for(Frame = 0; Frame < 6; Frame++) - { - for(i = 0; i < 3; i++) - { - for(j = 0; j < 49; j++) - { - TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= pN[pos]; - pos++; - } - } - - } - -} - -if ( (state->currentslot == 1 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) || - (state->currentslot == 1 && state->K1 > 0 && state->M == 1) ) -{ - - int pos = 0; - - unsigned long long int k1 = state->K1; - unsigned long long int k2 = state->K2; - unsigned long long int k3 = state->K3; - unsigned long long int k4 = state->K4; - - fprintf (stderr, "\n"); - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " SPT %010llX", k1); - - int T_Key[256] = {0}; - int pN[882] = {0}; - - int len = 0; - - if (k2 == 0) - { - len = 39; - k1 = k1 << 24; - } - if (k2 != 0) - { - len = 127; - fprintf(stderr, " %016llX", k2); - } - if (k4 != 0) - { - len = 255; - fprintf(stderr, " %016llX", k3); - fprintf(stderr, " %016llX", k4); - } - - fprintf (stderr, "%s", KNRM); - - for (i = 0; i < 64; i++) - { - T_Key[i] = ( ((k1 << i) & 0x8000000000000000) >> 63 ); - T_Key[i+64] = ( ((k2 << i) & 0x8000000000000000) >> 63 ); - T_Key[i+128] = ( ((k3 << i) & 0x8000000000000000) >> 63 ); - T_Key[i+192] = ( ((k4 << i) & 0x8000000000000000) >> 63 ); - } - - for (i = 0; i < 882; i++) - { - pN[i] = T_Key[pos]; - pos++; - if (pos > len) - { - pos = 0; - } - } - - pos = 0; - for(Frame = 0; Frame < 6; Frame++) - { - for(i = 0; i < 3; i++) - { - for(j = 0; j < 49; j++) - { - TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= pN[pos]; - pos++; - } - } - - } - -} - -if (state->currentslot == 0) -{ - - for(Frame = 0; Frame < 6; Frame++) //6 - { - /* 1 DMR frame contains 3 AMBE voice samples */ - for(i = 0; i < 3; i++) - { - 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 - - 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); - - if (opts->payload == 1) - { - PrintAMBEData(opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); - } - - //quick enc toggle to determine whether or not to play enc traffic - int enc_bit = 0; - enc_bit = (state->dmr_so >> 6) & 0x1; - if (enc_bit == 1) - { - state->dmr_encL = 1; - } - else state->dmr_encL = 0; - - if (state->K != 0 || state->K1 != 0) - { - state->dmr_encL = 0; - } - - //quick test to determine whether or not to run the next few steps below - if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) - { - if (opts->mbe_out_f != NULL) - { - saveAmbe2450Data (opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); - } - - state->debug_audio_errors += *errs2; - - processAudio(opts, state); - - if (opts->wav_out_f != NULL) - { - writeSynthesizedVoice (opts, state); - } - - if (opts->audio_out == 1) //opts->audio_out == 1 - { - playSynthesizedVoice (opts, state); - } - } //second bracket for the test enc condition - } /* End for(i = 0; i < 3; i++) */ - } /* End for(Frame = 0; Frame < 6; Frame++) */ - } //End if Current Slot == 0 - - if (state->currentslot == 1) - { - - for(Frame = 0; Frame < 6; Frame++) - { - /* 1 DMR frame contains 3 AMBE voice samples */ - for(i = 0; i < 3; i++) - { - errs = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); - errs2 = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); - state->errs = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement - state->errs2 = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement - - mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str, - TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], - state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - - - if (opts->payload == 1) - { - PrintAMBEData(opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); - } - - //quick enc toggle to determine whether or not to play enc traffic - int enc_bit = 0; - enc_bit = (state->dmr_soR >> 6) & 0x1; - if (enc_bit == 1) - { - state->dmr_encR = 1; - } - else state->dmr_encR = 0; - - if (state->K != 0 || state->K1 != 0) - { - state->dmr_encR = 0; - } - - //quick test to determine whether or not to run the next few steps below - if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) - { - if (opts->mbe_out_f != NULL) - { - saveAmbe2450Data (opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); - } - - state->debug_audio_errors += *errs2; - - if (opts->audio_out == 1) - { - processAudio(opts, state); - } - - if (opts->wav_out_f != NULL) - { - writeSynthesizedVoice (opts, state); - } - - if (opts->audio_out == 1) - { - playSynthesizedVoice (opts, state); - } - } - } /* End for(i = 0; i < 3; i++) */ - } /* End for(Frame = 0; Frame < 6; Frame++) */ - } //End if Current Slot == 1 - - -} /* End ProcessDMR */ -/* End of file */ diff --git a/src/dmr_sync.c b/src/dmr_sync.c deleted file mode 100644 index cd79173..0000000 --- a/src/dmr_sync.c +++ /dev/null @@ -1,2939 +0,0 @@ -/* - * Copyright (C) 2010 DSD Author - * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - - //Originally found at - https://github.com/LouisErigHerve/dsd - //Modified for use in DSD-FME - -#include "dsd.h" - -char * getTimeL(void) //get pretty hh:mm:ss timestamp -{ - time_t t = time(NULL); - - char * curr; - char * stamp = asctime(localtime( & t)); - - curr = strtok(stamp, " "); - curr = strtok(NULL, " "); - curr = strtok(NULL, " "); - curr = strtok(NULL, " "); - - return curr; -} - -char * getDateL(void) { - char datename[120]; //increased to 200 to fix 32-bit Ubuntu/Cygwin when fopen file printing to lrrp.txt - char * curr2; - struct tm * to; - time_t t; - t = time(NULL); - to = localtime( & t); - strftime(datename, sizeof(datename), "%Y/%m/%d", to); - curr2 = strtok(datename, " "); - return curr2; -} - -//Trellis Decoding still needs work, so don't be surprised by bad decodes -void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98], 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[144]; - uint8_t DmrDataByte[18]; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; - uint8_t R[3]; - uint8_t BPTCReservedBits = 0; - short int slot = 0; - - slot = (short int)state->currentslot; - /* Check the current time slot */ - if(state->currentslot == 0) - { - TSVoiceSupFrame = &state->TS1SuperFrame; - } - else - { - TSVoiceSupFrame = &state->TS2SuperFrame; - } - - unsigned char tdibits_reverse[98]; - unsigned char tdibits_inverted[98]; - unsigned char tdibits_to_bits[196]; - - for (i = 0; i < 98; i++) - { - tdibits_reverse[97-i] = tdibits[i]; - } - - unsigned char TrellisReturn[18]; - CDMRTrellisDecode(tdibits_reverse, TrellisReturn); //NEEDS REVERSE DIBITS! - - 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; - } - - //define our block and padding values - uint8_t blocks = state->data_header_blocks[slot] - 1; //subtract 1 for the relevant value in the calc below - uint8_t padding = state->data_header_padding[slot]; - - //shift data in the superframe up a block - k = 0; - for(i = 0; i < 16; i++) //16, or 18? seems to have two extra bytes in front currently - { - state->dmr_34_rate_sf[slot][i] = state->dmr_34_rate_sf[slot][i+16]; - state->dmr_34_rate_sf[slot][i+16] = state->dmr_34_rate_sf[slot][i+32]; - state->dmr_34_rate_sf[slot][i+32] = state->dmr_34_rate_sf[slot][i+48]; - state->dmr_34_rate_sf[slot][i+48] = state->dmr_34_rate_sf[slot][i+64]; - state->dmr_34_rate_sf[slot][i+64] = state->dmr_34_rate_sf[slot][i+80]; - - DmrDataByte[i] = 0; - for(j = 0; j < 8; j++) - { - DmrDataByte[i] = DmrDataByte[i] << 1; - DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); - k++; - } - - state->dmr_34_rate_sf[slot][i+(blocks*16)] = TrellisReturn[i+2]; //plus two to skip the first two bytes - } - - //Start Polling the 3/4 Rate Super Frame for Data when byte 0 contains values - //LRRP - int message_legnth = 0; - if ( ((state->dmr_34_rate_sf[slot][0] & 0x7F) == 0x45) || - ((state->dmr_34_rate_sf[slot][0] & 0x7F) == 0x1F) ) //Start LRRP now, shimmed in 1F for KrisMar testing - { - - if ( (state->dmr_34_rate_sf[slot][0] & 0x7F) == 0x1F ) - { - message_legnth = 22; //quick shim for KrisMar samples, until I can find a message legnth flag on his - } - - FILE * pFile; - if (opts->lrrp_file_output == 1) - { - //open file by name that is supplied in the ncurses terminal - pFile = fopen (opts->lrrp_out_file, "a"); - - //seperate these two values since they cause issues with garbage writing to files in some environments (cygwin) - fprintf (pFile, "%s\t", getDateL() ); //current date, may find a way to only add this IF no included timestamp in LRRP data? - fprintf (pFile, "%s\t", getTimeL()) ; //current timestamp, may find a way to only add this IF no included timestamp in LRRP data? - fprintf (pFile, "%08lld\t", state->dmr_lrrp_source[state->currentslot]); //source address from data header - } - - - fprintf (stderr, "%s ", KMAG); - - //go to number of octets minus padding and crc, confirmed data may need a second rule to skip Serial Numbers and Block CRCs - for (short i = 12; i < ( ((blocks+1)*16) - (padding+4) ); i++) - { - - if ( state->dmr_34_rate_sf[slot][i] == 0x0C) //Source and Destination info - { - fprintf (stderr, "\n Source: "); - fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_34_rate_sf[slot][i+0] & 0x3F), state->dmr_34_rate_sf[slot][i+1], state->dmr_34_rate_sf[slot][i+2], state->dmr_34_rate_sf[slot][i+3]); //strip first two bits off 1st byte - fprintf (stderr, " [%08d]", (state->dmr_34_rate_sf[slot][i+1] <<16 ) + (state->dmr_34_rate_sf[slot][i+2] << 8) + state->dmr_34_rate_sf[slot][i+3] ); - fprintf (stderr, " - Port %05d ", (state->dmr_34_rate_sf[slot][i+8] << 8) + state->dmr_34_rate_sf[slot][i+9]); - fprintf (stderr, "\n Destination: "); - fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_34_rate_sf[slot][i+4] & 0x3F), state->dmr_34_rate_sf[slot][i+5], state->dmr_34_rate_sf[slot][6], state->dmr_34_rate_sf[slot][i+7]); //strip first two bits off 4th byte?? - fprintf (stderr, " [%08d]", (state->dmr_34_rate_sf[slot][i+5] <<16 ) + (state->dmr_34_rate_sf[slot][i+6] << 8) + state->dmr_34_rate_sf[slot][i+7] ); - fprintf (stderr, " - Port %05d", (state->dmr_34_rate_sf[slot][i+10] << 8) + state->dmr_34_rate_sf[slot][i+11]); - - i = i + 12; //skip 12 bytes here so we don't accidentally trip another flag with data in these bytes - } - - if (state->dmr_34_rate_sf[slot][i] == 0x0D) //This should lock on to the second 0x0D value hopefully and tell us the message legnth - { - message_legnth = state->dmr_34_rate_sf[slot][i+1]; - fprintf (stderr, "\n Message Legnth: %02d", message_legnth); - i = i + 2; //skip 2 bytes here so we don't accidentally trip another flag with data in these bytes - } - - if ( state->dmr_34_rate_sf[slot][i] == 0x34 && message_legnth > 21 ) //timestamp, seems to need legnth of 27, shortened to 21 due to other samples - { - fprintf (stderr, "\n LRRP - Timestamp: "); - fprintf (stderr, "%4d.", (state->dmr_34_rate_sf[slot][i+1] << 6) + (state->dmr_34_rate_sf[slot][i+2] >> 2) ); //4 digit year - fprintf (stderr, "%02d.", ( ((state->dmr_34_rate_sf[slot][i+2] & 0x3) << 2) + ((state->dmr_34_rate_sf[slot][i+3] & 0xC0) >> 6)) ); //2 digit month - fprintf (stderr, "%02d", ( (state->dmr_34_rate_sf[slot][i+3] & 0x30) >> 1) + ((state->dmr_34_rate_sf[slot][i+3] & 0x0E) >> 1) ); //2 digit day - fprintf (stderr, " %02d:",( (state->dmr_34_rate_sf[slot][i+3] & 0x01) << 4) + ((state->dmr_34_rate_sf[slot][i+4] & 0xF0) >> 4) ); //2 digit hour - fprintf (stderr, "%02d:",( (state->dmr_34_rate_sf[slot][i+4] & 0x0F) << 2) + ((state->dmr_34_rate_sf[slot][i+5] & 0xC0) >> 6) ); //2 digit minute - fprintf (stderr, "%02d", ( (state->dmr_34_rate_sf[slot][i+5] & 0x3F) << 0) ); //2 digit second - - i = i + 6; //skip 6 bytes here so we don't accidentally trip another flag with data in these bytes - } - - //is 66 a hemisphere or meridian difference from 0x51? Or different system type? - if ( (state->dmr_34_rate_sf[slot][i] == 0x51 && message_legnth > 13) || - (state->dmr_34_rate_sf[slot][i] == 0x66 && message_legnth > 13) ) //lattitude and longitude, message_lenght > 13? - { - fprintf (stderr, "\n LRRP -"); - fprintf (stderr, " Lat: "); - if (state->dmr_34_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? - { - fprintf (stderr, "-"); - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "-"); - } - } - 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[slot][i+1] & 0x7F ) << 24 ) + (state->dmr_34_rate_sf[slot][i+2] << 16) + (state->dmr_34_rate_sf[slot][i+3] << 8) + state->dmr_34_rate_sf[slot][i+4]) * 1 ); - lrrplon = ( ( (state->dmr_34_rate_sf[slot][i+5] << 24 ) + (state->dmr_34_rate_sf[slot][i+6] << 16) + (state->dmr_34_rate_sf[slot][i+7] << 8) + state->dmr_34_rate_sf[slot][i+8]) * 1 ); - fprintf (stderr, "%.5lf ", ((double)lrrplat) * lat_unit); - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "%.5lf\t", ((double)lrrplat) * lat_unit); - } - fprintf (stderr, " Lon: "); - if (state->dmr_34_rate_sf[slot][i+5] & 0x80) //first bit indicates a sign, or hemisphere? - { - //fprintf (stderr, "-"); - } - fprintf (stderr, "%.5lf", (lrrplon * lon_unit) ); - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "%.5lf\t", (lrrplon * lon_unit) ); - } - if (state->dmr_34_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? - { - sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: -%.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); - } - else sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: %.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); //print for easy copy/paste into browser? - //fprintf (stderr, " ("); - if (state->dmr_34_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? - { - fprintf (stderr, " (-%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); - } - else fprintf (stderr, " (%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); - - //i = i + 9 + 2; //skip 9 bytes here so we don't accidentally trip another flag with data in these bytes - - //tuck velocity and track inside the lrrp coordinates? loose false positives on velocity and track without a coord point - if ( state->dmr_34_rate_sf[slot][i+11] == 0x6C && message_legnth > 13) - { - //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. double check double values? - //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[slot][i+12] ) + state->dmr_34_rate_sf[slot][i+13] )) / ( (double)128)); - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "%.3lf\t ", (velocity * 3.6) ); - } - fprintf (stderr, "\n LRRP - Velocity: %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity) ); - sprintf ( state->dmr_lrrp[state->currentslot][4], "Vel: %.4lf kph ", (3.6 * velocity)); - - //i = i + 3; //skip 3 bytes here so we don't accidentally trip another flag with data in these bytes - } - if ( state->dmr_34_rate_sf[slot][i+14] == 0x56 && message_legnth > 13) - { - //check for appropriate terminology here - Heading, bearing, course, or track? - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "%d\t", state->dmr_34_rate_sf[slot][i+15] * 2); - } - fprintf (stderr, "\n LRRP - Track: %d Degrees", state->dmr_34_rate_sf[slot][i+15] * 2); - sprintf ( state->dmr_lrrp[state->currentslot][5], "Dir: %d Deg ", state->dmr_34_rate_sf[slot][i+15] * 2); - - i = ((blocks+1)*12); //skip to end of loop here so we don't accidentally trip another flag with data in these bytes - } - - i = i + 15; - } - - //try for a Control ACK at the very end if nothing else pops, flag still unknown - if ( (state->dmr_34_rate_sf[slot][i] == 0x36 || state->dmr_34_rate_sf[slot][i] == 0x37) && message_legnth > 6 ) - { - fprintf (stderr, "\n LRRP - Control ACK "); - } - } - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "\n"); - fclose (pFile); - } - } - fprintf (stderr, "%s ", KNRM); - - //Full - if (opts->payload == 1) - { - fprintf (stderr,"%s", KCYN); - fprintf (stderr, "\n Full 3/4 Rate Trellis Payload - Slot [%d]\n ", slot+1); - for (i = 0; i < 18; i++) //16, or 18? - { - fprintf (stderr, "[%02X]", TrellisReturn[i]); - } - fprintf (stderr, "\n Hex to Ascii - "); - for (i = 0; i < 18; i++) - { - if (TrellisReturn[i] <= 0x7E && TrellisReturn[i] >=0x20) - { - fprintf (stderr, "%c", TrellisReturn[i]); - } - else fprintf (stderr, "."); - } - fprintf (stderr,"%s", KNRM); //change back to normal - } - //Full Super Frame - Debug Output - if (opts->payload == 2 && state->data_block_counter[state->currentslot] == state->data_header_blocks[state->currentslot]) - { - fprintf (stderr, "%s",KGRN); - fprintf (stderr, "\n Rate 3/4 Superframe - Slot [%d]\n ",slot+1); - for (i = 0; i < ((blocks+1)*16); i++) //(16*4), using 16 since we jump the first two bytes - { - fprintf (stderr, "[%02X]", state->dmr_34_rate_sf[slot][i]); - if (i == 15 || i == 31 || i == 47 || i == 63 || i == 79) - { - fprintf (stderr, "\n "); //line break and two spaces after each 16 bytes - } - } - fprintf (stderr, "%s ", KNRM); - } - state->data_block_counter[state->currentslot]++; //increment block counter -} - -//This is Data Header -void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) -{ - short int slot = 0; - slot = (short int)state->currentslot; - - //see if we still need this portion if we are going to use the data block info - //clear out the 3/4 rate data superframe so we don't repeat old info - for (short int i = 0; i < 288; i++) //expanded to 288 to prevent crashing - { - state->dmr_34_rate_sf[slot][i] = 0; - } - //clear out the 1/2 rate data superframe so we don't repeat old info - for (short int i = 0; i < 288; i++) //expanded to 288 to prevent crashing - { - state->dmr_12_rate_sf[slot][i] = 0; - } - - 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++) - { - 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 < 16; i++) - { - CRCExtracted = CRCExtracted << 1; - CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); - } - - /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - CRCExtracted = CRCExtracted ^ 0xCCCC; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0xCCCC); - - /* 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; - } - - //test - if((IrrecoverableErrors == 0) && CRCCorrect) - { - //fprintf (stderr, "\n(Data CRC Okay)"); - } - else if((IrrecoverableErrors == 0)) - { - //fprintf (stderr, "\n(Data FEC Okay)"); - } - else {}//fprintf (stderr, ("\n(Data CRC Fail, FEC Fail)")); - - //collect relevant data header info, figure out format, and grab appropriate info from it - if (state->data_p_head[state->currentslot] == 0) - { - fprintf (stderr, "%s ", KGRN); - state->data_block_counter[state->currentslot] = 1; //reset block counter to 1 - state->data_header_format[state->currentslot] = DmrDataByte[0]; //collect the entire byte, we can check group or individual, response requested as well on this - state->data_header_sap[state->currentslot] = (DmrDataByte[1] & 0xF0) >> 4; //SAP is IP(4) or other - - // state->data_header_padding[state->currentslot] = DmrDataByte[1] & 0xF; //number of padding octets on last block - // state->data_header_blocks[state->currentslot] = DmrDataByte[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data - // fprintf (stderr, "\n Unconfirmed Data Header: Format %02X - SAP %02X - Block Count %02X - Padding Octets %02X", - // state->data_header_format[state->currentslot], state->data_header_sap[state->currentslot], - // state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); - - if ( (state->data_header_format[state->currentslot] & 0xF) == 0x2) - { - state->data_header_padding[state->currentslot] = DmrDataByte[1] & 0xF; //number of padding octets on last block - state->data_header_blocks[state->currentslot] = DmrDataByte[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data - fprintf (stderr, "\n Unconfirmed Data Header: DPF %01X - SAP %02X - Block Count %02X - Padding Octets %02X", - state->data_header_format[state->currentslot] & 0xF, state->data_header_sap[state->currentslot], - state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); - } - - if ( (state->data_header_format[state->currentslot] & 0xF) == 0x3) - { - state->data_header_padding[state->currentslot] = DmrDataByte[1] & 0xF; //number of padding octets on last block - state->data_header_blocks[state->currentslot] = DmrDataByte[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data - fprintf (stderr, "\n Confirmed Data Header: DPF %01X - SAP %02X - Block Count %02X - Padding Octets %02X", - state->data_header_format[state->currentslot] & 0xF, state->data_header_sap[state->currentslot], - state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); - } - - if ( (state->data_header_format[state->currentslot] & 0xF) == 0xD) //DD_HEAD - { - state->data_header_padding[state->currentslot] = DmrDataByte[7] & 0xF; - state->data_header_blocks[state->currentslot] = ( (DmrDataByte[0] & 0x30) | ((DmrDataByte[1] & 0xF) >> 0) ); //what a pain MSB | LSB - fprintf (stderr, "\n Short Data - Defined: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X", - state->data_header_format[state->currentslot] & 0xF, state->data_header_sap[state->currentslot], - state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); - } - - if ( (state->data_header_format[state->currentslot] & 0xF) == 0xE) //SP_HEAD or R_HEAD - { - state->data_header_padding[state->currentslot] = DmrDataByte[7] & 0xF; - state->data_header_blocks[state->currentslot] = ( (DmrDataByte[0] & 0x30) | ((DmrDataByte[1] & 0xF) >> 0) ); //what a pain MSB | LSB - fprintf (stderr, "\n Short Data - Raw or Precoded: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X", - state->data_header_format[state->currentslot] & 0xF, state->data_header_sap[state->currentslot], - state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); - } - - - } - - //sanity check to prevent random crash in 1/2 rate and 3/4 rate data - //we want to assign extra large block sizes to a max of 7 so we don't overload the 1/2 or 3/4 array - if (state->data_header_blocks[state->currentslot] > 7) - { - state->data_header_blocks[state->currentslot] = 7; //currently 1/2 only supports a max of 7 blocks per slot - } - - - fprintf (stderr, "%s ", KNRM); - //end collecting data header info - - //look at see which type of data service ap we have, and then assign src and dst later for lrrp text dump, etc. - fprintf (stderr, "%s ", KMAG); - if (state->data_header_sap[state->currentslot] == 0x4 && state->data_p_head[state->currentslot] == 0) - { - fprintf (stderr, "\n IP Data - Source: "); - //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[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); - fprintf (stderr, " Destination: "); - //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); - - //part below should probably be inside of above if condition - if (1 == 1) //already setting by current slot, no need for checking first - { - sprintf ( state->dmr_lrrp[state->currentslot][1], "SRC [%d] DST [%d] ", - ( (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7]), - ( (DmrDataByte[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4]) ); - } - - state->dmr_lrrp_source[state->currentslot] = (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7]; - - } - - if (state->data_header_sap[state->currentslot] == 0x0 && state->data_p_head[state->currentslot] == 0) - { - fprintf (stderr, "\n Unified Data Transport - Source: "); - //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[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); - fprintf (stderr, " Destination: "); - //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); - - //part below should probably be inside of above if condition - if (1 == 1) //already setting by current slot, no need for checking first - { - sprintf ( state->dmr_lrrp[state->currentslot][1], "SRC [%d] DST [%d] ", - ( (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7]), - ( (DmrDataByte[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4]) ); - } - - state->dmr_lrrp_source[state->currentslot] = (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7]; - - } - - if (state->data_header_sap[state->currentslot] == 0x9 && state->data_p_head[state->currentslot] == 0) - { - fprintf (stderr, "\n Proprietary Packet Data - Source: "); - //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[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); - fprintf (stderr, " Destination: "); - //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); - - //part below should probably be inside of above if condition - if (1 == 1) //already setting by current slot, no need for checking first - { - sprintf ( state->dmr_lrrp[state->currentslot][1], "SRC [%d] DST [%d] ", - ( (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7]), - ( (DmrDataByte[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4]) ); - } - - state->dmr_lrrp_source[state->currentslot] = (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7]; - - } - - if (state->data_header_sap[state->currentslot] == 0x2 && state->data_p_head[state->currentslot] == 0) - { - fprintf (stderr, "\n TCP/IP Header Compression Data - Source: "); - //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[3]); - fprintf (stderr, " Destination: "); - //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[2]); - - //part below should probably be inside of above if condition - if (1 == 1) //already setting by current slot, no need for checking first - { - sprintf ( state->dmr_lrrp[state->currentslot][1], "SRC [%d] DST [%d] ", - DmrDataByte[3], DmrDataByte[2] ); - } - - state->dmr_lrrp_source[state->currentslot] = DmrDataByte[3]; - - } - - if (state->data_header_sap[state->currentslot] == 0x3 && state->data_p_head[state->currentslot] == 0) - { - fprintf (stderr, "\n UDP/IP Header Compression Data - Source: "); - //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[3]); - fprintf (stderr, " Destination: "); - //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[2]); - - //part below should probably be inside of above if condition - if (1 == 1) //already setting by current slot, no need for checking first - { - sprintf ( state->dmr_lrrp[state->currentslot][1], "SRC [%d] DST [%d] ", - DmrDataByte[3], DmrDataByte[2] ); - } - - state->dmr_lrrp_source[state->currentslot] = DmrDataByte[3]; - - } - - if (state->data_header_sap[state->currentslot] == 0x5 && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol - { - fprintf (stderr, "\n ARP - Address Resolution Protocol "); - } - - if ( (state->data_header_format[state->currentslot] & 0xF ) == 0xD && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol - { - fprintf (stderr, "\n Short Data - Defined - Source: "); - //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[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); - fprintf (stderr, " Destination: "); - //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); - } - - if ( (state->data_header_format[state->currentslot] & 0xF) == 0xE && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol - { - fprintf (stderr, "\n Short Data - Raw or Status/Precoded - Source: "); - //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[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); - fprintf (stderr, " Destination: "); - //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); - } - - if ( (state->data_header_format[state->currentslot] & 0xF ) == 0x1 && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol - { - fprintf (stderr, "\n Response Packet - Source: "); - //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[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); - fprintf (stderr, " Destination: "); - //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); - } - - if ( (state->data_header_format[state->currentslot] & 0xF ) == 0x0 && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol - { - fprintf (stderr, "\n Unified Data Transport - Source: "); - //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[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); - fprintf (stderr, " Destination: "); - //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); - } - - if ( (state->data_header_format[state->currentslot] & 0x40) == 0x40 && state->data_p_head[state->currentslot] == 0) //check response req bit - { - fprintf (stderr, "\n Response Requested - "); - 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] ); - } - - //if proprietary header was flagged by the last data header, then process data differently - //maybe we could add the data header bytes found here into the 12 rate and/or 34 rate superframe - if (state->data_p_head[state->currentslot] == 1) - { - fprintf (stderr, "\n Proprietary Data Header: SAP %01X - Format %01X - MFID %02X", - (DmrDataByte[0] & 0xF0) >> 4, DmrDataByte[0] & 0xF, DmrDataByte[1] ); - - state->data_p_head[state->currentslot] = 0; - state->data_header_sap[state->currentslot] = 0; //reset this to zero so we don't trip the condition below - state->data_block_counter[state->currentslot]++; //increment the counter since this counts against the data blocks - //shim the databytes into the approprate 12 Rate Super Frame - uint8_t blocks = state->data_header_blocks[state->currentslot] - 1; - for(i = 0; i < 12; i++) - { - state->dmr_12_rate_sf[slot][i+(blocks*12)] = DmrDataByte[i]; - } - } - - //only set this flag after everything else is processed - if (state->data_header_sap[state->currentslot] == 0x9 && state->data_p_head[state->currentslot] == 0) //9 is Proprietary Packet data - { - fprintf (stderr, "\n Proprietary Packet Data Incoming "); - state->data_p_head[state->currentslot] = 1; //flag that next data header will be a proprietary data header - } - fprintf (stderr, "%s ", KNRM); - - //Full - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull Data Header Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "%s", KNRM); - } - - -} - -void Process1Data(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[25]; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; - uint8_t R[3]; - uint8_t BPTCReservedBits = 0; - short int slot = 0; - slot = (short int)state->currentslot; - - //define our block and padding values - uint8_t blocks = state->data_header_blocks[slot] - 1; //subtract 1 for the relevant value in the calc below - uint8_t padding = state->data_header_padding[slot]; - //shift data in the superframe up a block - k = 0; - for(i = 0; i < 24; i++) - { - //reuse dmr_12_rate_sf since 12, we can use 2 blocks to load 1 block here - state->dmr_12_rate_sf[slot][i] = state->dmr_12_rate_sf[slot][i+24]; //shift block 2 to block 1 - state->dmr_12_rate_sf[slot][i+24] = state->dmr_12_rate_sf[slot][i+48]; //shift block 3 to block 2 - state->dmr_12_rate_sf[slot][i+48] = state->dmr_12_rate_sf[slot][i+72]; //shift block 3 to block 2 - DmrDataByte[i] = 0; - for(j = 0; j < 8; j++) - { - DmrDataByte[i] = DmrDataByte[i] << 1; - DmrDataByte[i] = DmrDataByte[i] | (info[k] ); //& 1 - k++; - } - - //start loading new superframe at appropriate block count determined by the data header - state->dmr_12_rate_sf[slot][i+(blocks*24)] = DmrDataByte[i]; - } - - //need to rework this for rate 1 data, will be a crc 9 for each confirmed block, - //and/or CRC 32 on last block (full superframe) - //NOTE 2: Only used when CRC-9 present in burst. - - /* 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); - // } - - //CRCExtracted = CRCExtracted ^ 0x6969; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); - - //Full - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull Rate 1 Payload \n"); - for (i = 0; i < 24; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - if (i == 11) - { - fprintf (stderr, "\n"); - } - } - fprintf (stderr, "\n Hex to Ascii - "); - for (i = 0; i < 24; i++) - { - if (DmrDataByte[i] <= 0x7E && DmrDataByte[i] >=0x20) - { - fprintf (stderr, "%c", DmrDataByte[i]); - } - else fprintf (stderr, "."); - } - fprintf (stderr, "%s", KNRM); - } - - //Full Super Frame - Debug Output - if (opts->payload == 2 && state->data_block_counter[state->currentslot] == state->data_header_blocks[state->currentslot]) - { - fprintf (stderr, "%s",KGRN); - fprintf (stderr, "\n Rate 1 Superframe - Slot [%d]\n ",slot+1); - for (i = 0; i < ((blocks+1)*24); i++) //only print as many as we have blocks - { - fprintf (stderr, "[%02X]", state->dmr_12_rate_sf[slot][i]); - if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71) //line break and two spaces after each 12 bytes - { - fprintf (stderr, "\n "); - } - } - fprintf (stderr, "%s ", KNRM); - } - state->data_block_counter[state->currentslot]++; //increment block counter - -} - -void ProcessMBChData(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++) - { - 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 < 16; i++) - { - CRCExtracted = CRCExtracted << 1; - CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); - } - - /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - CRCExtracted = CRCExtracted ^ 0xAAAA; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0xAAAA); - - /* 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; - } - - //Full - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull MBC Header Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "%s", KNRM); - } - -} - -void ProcessMBCData(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++) - { - DmrDataByte[i] = 0; - for(j = 0; j < 8; j++) - { - DmrDataByte[i] = DmrDataByte[i] << 1; - DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); - k++; - } - } - - //NO CRC or FEC on MBC Cont. Data? - //...that seems to be according to the manual - - /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ - // CRCExtracted = 0; - // for(i = 0; i < 16; i++) - // { - // CRCExtracted = CRCExtracted << 1; - // CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); - // } - - //No CRC Mask for MBC Continuation Data - //Note 1. None required for intermediate or last blocks. - /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - //CRCExtracted = CRCExtracted ^ 0x6969; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - // CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x0); //0, or FFFF? - - /* 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; - } - - //Full - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull MBC Continuation Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "%s", KNRM); - } - -} - -//This data shouldn't be active, but come here to dump in case of data burst type decoding failure -void ProcessReservedData(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; - } - - /* Convert the 196 bit of voice LC Header data into 12 bytes */ - k = 0; - for(i = 0; i < 24; i++) - { - DmrDataByte[i] = 0; - for(j = 0; j < 8; j++) - { - DmrDataByte[i] = DmrDataByte[i] << 1; - DmrDataByte[i] = DmrDataByte[i] | info[i]; - k++; - } - } - - /* 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; - } - - //Full - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull Reserved Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "%s", KRED); - fprintf (stderr, "\nINFO! This Payload Dump May be caused by erroneous data burst type decoding! "); - fprintf (stderr, "%s", KNRM); - } - -} - -void ProcessUnifiedData(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; - short int slot = 0; - slot = (short int)state->currentslot; - - /* 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); - - - 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 + 80] & 1); - } - - /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - CRCExtracted = CRCExtracted ^ 0x3333; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x3333); - - //test - if((IrrecoverableErrors == 0) && CRCCorrect) - { - //fprintf (stderr, "\n(Unified Data CRC Okay)"); - } - else if((IrrecoverableErrors == 0)) - { - //fprintf (stderr, "\n(Unified Data FEC Okay)"); - } - else - { - fprintf (stderr, "%s", KRED); - fprintf (stderr, ("\n(Unified Rate CRC Fail, FEC Fail)")); - fprintf (stderr, "%s", KNRM); - } - - /* 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; - } - - //Full - if (opts->payload == 1) - { - fprintf (stderr,"%s", KCYN); - fprintf (stderr, "\n Full Unified Data Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "\n Hex to Ascii - "); - for (i = 0; i < 12; i++) - { - if (DmrDataByte[i] <= 0x7E && DmrDataByte[i] >=0x20) - { - fprintf (stderr, "%c", DmrDataByte[i]); - } - else fprintf (stderr, "."); - } - fprintf (stderr,"%s", KNRM); - } - -} - -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; - short int slot = 0; - slot = (short int)state->currentslot; - - /* 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); - - //define our block and padding values - uint8_t blocks = state->data_header_blocks[slot] - 1; //subtract 1 for the relevant value in the calc below - uint8_t padding = state->data_header_padding[slot]; - //shift data in the superframe up a block - k = 0; - for(i = 0; i < 12; i++) - { - state->dmr_12_rate_sf[slot][i] = state->dmr_12_rate_sf[slot][i+12]; //shift block 2 to block 1 - state->dmr_12_rate_sf[slot][i+12] = state->dmr_12_rate_sf[slot][i+24]; //shift block 3 to block 2 - state->dmr_12_rate_sf[slot][i+24] = state->dmr_12_rate_sf[slot][i+36]; //shift block 4 to block 3 - state->dmr_12_rate_sf[slot][i+36] = state->dmr_12_rate_sf[slot][i+48]; //shift block 5 to block 4 - state->dmr_12_rate_sf[slot][i+48] = state->dmr_12_rate_sf[slot][i+60]; //shift block 6 to block 5 - state->dmr_12_rate_sf[slot][i+60] = state->dmr_12_rate_sf[slot][i+72]; //shift block 7 to block 6 - DmrDataByte[i] = 0; - for(j = 0; j < 8; j++) - { - DmrDataByte[i] = DmrDataByte[i] << 1; - DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); - k++; - } - - //start loading new superframe at appropriate block count determined by the data header - state->dmr_12_rate_sf[slot][i+(blocks*12)] = DmrDataByte[i]; //if 3 blocks, then start at position 36; 4 blocks at 48, 5 at - } - - /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ - CRCExtracted = 0; - for(i = 0; i < 24; i++) - { - CRCExtracted = CRCExtracted << 1; - CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); - } - - /* 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? - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); - - //test - if((IrrecoverableErrors == 0) && CRCCorrect) - { - //fprintf (stderr, "\n(1/2 Rate CRC Okay)"); - } - else if((IrrecoverableErrors == 0)) - { - //fprintf (stderr, "\n(1/2 Rate FEC Okay)"); - } - else - { - fprintf (stderr, "%s", KRED); - fprintf (stderr, ("\n(1/2 Rate CRC Fail, FEC Fail)")); - fprintf (stderr, "%s", KNRM); - } - - /* 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; - } - - //Start Polling the 1/2 Rate Super Frame for Data when byte 0 contains values - //LRRP - int message_legnth = 0; - if ( ((state->dmr_12_rate_sf[slot][0] & 0x7F) == 0x45) || - ((state->dmr_12_rate_sf[slot][0] & 0x7F) == 0x1F) ) //Start LRRP now, shimmed in 1F for KrisMar testing - { - - if ( (state->dmr_12_rate_sf[slot][0] & 0x7F) == 0x1F ) - { - message_legnth = 22; //quick shim for KrisMar samples, until I can find a message legnth flag on his - } - - FILE * pFile; //put this outside of the if statement? - if (opts->lrrp_file_output == 1) - { - //open file by name that is supplied in the ncurses terminal - pFile = fopen (opts->lrrp_out_file, "a"); - - //seperate these two values since they cause issues with garbage writing to files in some environments (cygwin) - fprintf (pFile, "%s\t", getDateL() ); //current date, may find a way to only add this IF no included timestamp in LRRP data? - fprintf (pFile, "%s\t", getTimeL() ); //current timestamp, may find a way to only add this IF no included timestamp in LRRP data? - fprintf (pFile, "%08lld\t", state->dmr_lrrp_source[state->currentslot]); //source address from data header - } - - - fprintf (stderr, "%s ", KMAG); - - //go to number of octets minus padding and crc, confirmed data may need a second rule to skip Serial Numbers and Block CRCs - for (short i = 12; i < ( ((blocks+1)*12) - (padding+4) ); i++) - { - - if ( state->dmr_12_rate_sf[slot][i] == 0x0C) //Source and Destination info - { - fprintf (stderr, "\n Source: "); - fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[slot][i+0] & 0x3F), state->dmr_12_rate_sf[slot][i+1], state->dmr_12_rate_sf[slot][i+2], state->dmr_12_rate_sf[slot][i+3]); //strip first two bits off 1st byte - fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[slot][i+1] <<16 ) + (state->dmr_12_rate_sf[slot][i+2] << 8) + state->dmr_12_rate_sf[slot][i+3] ); - fprintf (stderr, " - Port %05d ", (state->dmr_12_rate_sf[slot][i+8] << 8) + state->dmr_12_rate_sf[slot][i+9]); - fprintf (stderr, "\n Destination: "); - fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[slot][i+4] & 0x3F), state->dmr_12_rate_sf[slot][i+5], state->dmr_12_rate_sf[slot][6], state->dmr_12_rate_sf[slot][i+7]); //strip first two bits off 4th byte?? - fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[slot][i+5] <<16 ) + (state->dmr_12_rate_sf[slot][i+6] << 8) + state->dmr_12_rate_sf[slot][i+7] ); - fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[slot][i+10] << 8) + state->dmr_12_rate_sf[slot][i+11]); - - i = i + 12; //skip 12 bytes here so we don't accidentally trip another flag with data in these bytes - } - - if (state->dmr_12_rate_sf[slot][i] == 0x0D) //This should lock on to the second 0x0D value hopefully and tell us the message legnth - { - message_legnth = state->dmr_12_rate_sf[slot][i+1]; - fprintf (stderr, "\n Message Legnth: %02d", message_legnth); - i = i + 2; //skip 2 bytes here so we don't accidentally trip another flag with data in these bytes - } - - if ( state->dmr_12_rate_sf[slot][i] == 0x34 && message_legnth > 21 ) //timestamp, seems to need legnth of 27, shortened to 21 due to other samples - { - fprintf (stderr, "\n LRRP - Timestamp: "); - fprintf (stderr, "%4d.", (state->dmr_12_rate_sf[slot][i+1] << 6) + (state->dmr_12_rate_sf[slot][i+2] >> 2) ); //4 digit year - fprintf (stderr, "%02d.", ( ((state->dmr_12_rate_sf[slot][i+2] & 0x3) << 2) + ((state->dmr_12_rate_sf[slot][i+3] & 0xC0) >> 6)) ); //2 digit month - fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[slot][i+3] & 0x30) >> 1) + ((state->dmr_12_rate_sf[slot][i+3] & 0x0E) >> 1) ); //2 digit day - fprintf (stderr, " %02d:",( (state->dmr_12_rate_sf[slot][i+3] & 0x01) << 4) + ((state->dmr_12_rate_sf[slot][i+4] & 0xF0) >> 4) ); //2 digit hour - fprintf (stderr, "%02d:",( (state->dmr_12_rate_sf[slot][i+4] & 0x0F) << 2) + ((state->dmr_12_rate_sf[slot][i+5] & 0xC0) >> 6) ); //2 digit minute - fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[slot][i+5] & 0x3F) << 0) ); //2 digit second - - i = i + 6; //skip 6 bytes here so we don't accidentally trip another flag with data in these bytes - } - - //is 66 a hemisphere or meridian difference from 0x51? Or different system type? - if ( (state->dmr_12_rate_sf[slot][i] == 0x51 && message_legnth > 13) || - (state->dmr_12_rate_sf[slot][i] == 0x66 && message_legnth > 13) ) //lattitude and longitude, message_lenght > 13? - { - fprintf (stderr, "\n LRRP -"); - fprintf (stderr, " Lat: "); - if (state->dmr_12_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? - { - fprintf (stderr, "-"); - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "-"); - } - } - 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[slot][i+1] & 0x7F ) << 24 ) + (state->dmr_12_rate_sf[slot][i+2] << 16) + (state->dmr_12_rate_sf[slot][i+3] << 8) + state->dmr_12_rate_sf[slot][i+4]) * 1 ); - lrrplon = ( ( (state->dmr_12_rate_sf[slot][i+5] << 24 ) + (state->dmr_12_rate_sf[slot][i+6] << 16) + (state->dmr_12_rate_sf[slot][i+7] << 8) + state->dmr_12_rate_sf[slot][i+8]) * 1 ); - fprintf (stderr, "%.5lf ", ((double)lrrplat) * lat_unit); - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "%.5lf\t", ((double)lrrplat) * lat_unit); - } - fprintf (stderr, " Lon: "); - if (state->dmr_12_rate_sf[slot][i+5] & 0x80) //first bit indicates a sign, or hemisphere? - { - //fprintf (stderr, "-"); - } - fprintf (stderr, "%.5lf", (lrrplon * lon_unit) ); - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "%.5lf\t", (lrrplon * lon_unit) ); - } - if (state->dmr_12_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? - { - sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: -%.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); - } - else sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: %.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); //print for easy copy/paste into browser? - //fprintf (stderr, " ("); - if (state->dmr_12_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? - { - fprintf (stderr, " (-%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); - } - else fprintf (stderr, " (%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); - - //i = i + 9 + 2; //skip 9 bytes here so we don't accidentally trip another flag with data in these bytes - - //tuck velocity and track inside the lrrp coordinates? loose false positives on velocity and track without a coord point - if ( state->dmr_12_rate_sf[slot][i+11] == 0x6C && message_legnth > 13) - { - //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. double check double values? - //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_12_rate_sf[slot][i+12] ) + state->dmr_12_rate_sf[slot][i+13] )) / ( (double)128)); - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "%.3lf\t ", (velocity * 3.6) ); - } - fprintf (stderr, "\n LRRP - Velocity: %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity) ); - sprintf ( state->dmr_lrrp[state->currentslot][4], "Vel: %.4lf kph ", (3.6 * velocity)); - - //i = i + 3; //skip 3 bytes here so we don't accidentally trip another flag with data in these bytes - } - if ( state->dmr_12_rate_sf[slot][i+14] == 0x56 && message_legnth > 13) - { - //check for appropriate terminology here - Heading, bearing, course, or track? - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "%d\t", state->dmr_12_rate_sf[slot][i+15] * 2); - } - fprintf (stderr, "\n LRRP - Track: %d Degrees", state->dmr_12_rate_sf[slot][i+15] * 2); - sprintf ( state->dmr_lrrp[state->currentslot][5], "Dir: %d Deg ", state->dmr_12_rate_sf[slot][i+15] * 2); - - i = ((blocks+1)*12); //skip to end of loop here so we don't accidentally trip another flag with data in these bytes - } - - i = i + 15; - - } - - //try for a Control ACK at the very end if nothing else pops, flag still unknown - if ( (state->dmr_12_rate_sf[slot][i] == 0x36 || state->dmr_12_rate_sf[slot][i] == 0x37) && message_legnth > 6 ) - { - fprintf (stderr, "\n LRRP - Control ACK "); - } - } - if (opts->lrrp_file_output == 1) - { - fprintf (pFile, "\n"); - fclose (pFile); - } - } - fprintf (stderr, "%s ", KNRM); - - //Full - if (opts->payload == 1) - { - fprintf (stderr,"%s", KCYN); - fprintf (stderr, "\n Full 1/2 Rate Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "\n Hex to Ascii - "); - for (i = 0; i < 12; i++) - { - if (DmrDataByte[i] <= 0x7E && DmrDataByte[i] >=0x20) - { - fprintf (stderr, "%c", DmrDataByte[i]); - } - else fprintf (stderr, "."); - } - fprintf (stderr,"%s", KNRM); - } - //Full Super Frame - Debug Output - if (opts->payload == 2 && state->data_block_counter[state->currentslot] == state->data_header_blocks[state->currentslot]) - { - fprintf (stderr, "%s",KGRN); - fprintf (stderr, "\n Rate 1/2 Superframe - Slot [%d]\n ",slot+1); - for (i = 0; i < ((blocks+1)*12); i++) //only print as many as we have blocks - { - fprintf (stderr, "[%02X]", state->dmr_12_rate_sf[slot][i]); - if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71) //line break and two spaces after each 12 bytes - { - fprintf (stderr, "\n "); - } - } - fprintf (stderr, "%s ", KNRM); - } - state->data_block_counter[state->currentslot]++; //increment block counter - -} - -void ProcessCSBK(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; - - // 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 - } - - /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - CRCExtracted = CRCExtracted ^ 0xA5A5; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0xA5A5); - - //test - if((IrrecoverableErrors == 0) && CRCCorrect) - { - //fprintf (stderr, "\n(CSBK CRC Okay)"); - } - else if((IrrecoverableErrors == 0)) - { - //fprintf (stderr, "\n(CSBK FEC Okay)"); - } - else - { - //fprintf (stderr, "%s", KRED); - //fprintf (stderr, ("\n(CSBK CRC Fail, FEC Fail)")); - //fprintf (stderr, "%s", KNRM); - } - - /* 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, "%s", KMAG); - fprintf (stderr, "\nMotoTRBO Connect Plus Neighbors\n"); - fprintf(stderr, " NB1(%02x), NB2(%02x), NB3(%02x), NB4(%02x), NB5(%02x)", nb1, nb2, nb3, nb4, nb5); - fprintf (stderr, "%s", KNRM); - 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, "%s", KGRN); - fprintf (stderr, "\nMotoTRBO Connect Plus Channel Grant\n"); - fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); - fprintf (stderr, "%s", KNRM); - 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, "%s", KRED); - 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); - fprintf (stderr, "%s", KNRM); - 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, "%s", KCYN); - 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); - fprintf (stderr, "%s", KNRM); - 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 CSBK Aloha?"); - //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, "%s", KCYN); - fprintf (stderr, "\nFull CSBK Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "%s", KNRM); - } - -} - -void ProcessDmrPIHeader(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++) - { - 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 - } - - /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - CRCExtracted = CRCExtracted ^ 0x6969; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - 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 (state->currentslot == 0) - { - state->payload_algid = DmrDataByte[0]; - state->payload_keyid = DmrDataByte[2]; - state->payload_mi = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) ); - //state->payload_mi = 0; //testing for late entry, remove later - if (state->payload_algid < 0x26) //have it always print? only if a good value, was 1 == 1 - { - fprintf (stderr, "%s ", KYEL); - fprintf (stderr, "\n Slot 1"); - fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi); - fprintf (stderr, "%s ", KNRM); - } - if (state->payload_algid >= 0x26) //sanity check to make sure we aren't keeping bogus PI header info - { - state->payload_algid = 0; - state->payload_keyid = 0; - state->payload_mi = 0; - } - } - - if (state->currentslot == 1) - { - state->payload_algidR = DmrDataByte[0]; - state->payload_keyidR = DmrDataByte[2]; - state->payload_miR = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) ); - //state->payload_miR = 0; //testing for late entry, remove later - if (state->payload_algidR < 0x26) //have it always print? only if a good value, was 1 == 1 - { - fprintf (stderr, "%s ", KYEL); - fprintf (stderr, "\n Slot 2"); - fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR); - fprintf (stderr, "%s ", KNRM); - } - if (state->payload_algidR >= 0x26) //sanity check to make sure we aren't keeping bogus PI header info - { - state->payload_algidR = 0; - state->payload_keyidR = 0; - state->payload_miR = 0; - } - } - - - //test - if((IrrecoverableErrors == 0) && CRCCorrect) - { - //fprintf (stderr, " (PI CRC Okay)"); - } - else if((IrrecoverableErrors == 0)) - { - //fprintf (stderr, " (PI FEC Okay)"); - } - else { - fprintf (stderr, "%s ", KRED); - fprintf (stderr, ("\n (PI CRC Fail, FEC Fail)")); - fprintf (stderr, "%s ", KNRM); - } - - //Full - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull PI Header Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "%s", KNRM); - } - -} - -//need to look into differences with Cap+ and other systems affecting the expected radio src id values -//find a way to differentiate the system types so we get good radio id decodes all the time -//svc op 0x60 for cap+?? if so, then should we use a mask? -void ProcessDmrVoiceLcHeader(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; - } - if(state->currentslot == 1) - { - 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++) - { - CRCExtracted = CRCExtracted << 1; - CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); - } - - /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - CRCExtracted = CRCExtracted ^ 0x969696; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); - - /* 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; - } - - /* Store the Protect Flag (PF) bit */ - TSVoiceSupFrame->FullLC.ProtectFlag = (unsigned int)(DmrDataBit[0]); - - /* Store the Reserved bit */ - TSVoiceSupFrame->FullLC.Reserved = (unsigned int)(DmrDataBit[1]); - - /* Store the Full Link Control Opcode (FLCO) */ - TSVoiceSupFrame->FullLC.FullLinkControlOpcode = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[2], 6); - - /* Store the Feature set ID (FID) */ - TSVoiceSupFrame->FullLC.FeatureSetID = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[8], 8); - - /* Store the Service Options */ - TSVoiceSupFrame->FullLC.ServiceOptions = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[16], 8); - - /* Store the Group address (Talk Group) */ - TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[24], 24); - - /* Store the Source address */ - TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[48], 24); - - int rest_channel = -1; //set rest_channel to -1; if set to other value, then we know we have a Cap+? - //Below "Should" be a MotoTRBO Cap+ system - if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode & 0x4 && TSVoiceSupFrame->FullLC.FeatureSetID == 0x10) - { - rest_channel = (TSVoiceSupFrame->FullLC.SourceAddress >> 16); //8 bits for Rest Channel - TSVoiceSupFrame->FullLC.SourceAddress = TSVoiceSupFrame->FullLC.SourceAddress & 0xFFFF; - } - - if((IrrecoverableErrors == 0) && CRCCorrect) - { - /* CRC is correct so consider the Full LC data as correct/valid */ - TSVoiceSupFrame->FullLC.DataValidity = 1; - if (state->currentslot == 0) - { - state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; //disabled for now, Cap+ and other systems cause issues with these values - - } - if (state->currentslot == 1) - { - state->dmr_fidR = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; - state->lasttgR = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrcR = TSVoiceSupFrame->FullLC.SourceAddress; - } - } - else if(IrrecoverableErrors == 0) - { - //FEC okay. Set all variables anyways. - TSVoiceSupFrame->FullLC.DataValidity = 0; - if (state->currentslot == 0) - { - state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - } - if (state->currentslot == 1) - { - state->dmr_fidR = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; - state->lasttgR = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrcR = TSVoiceSupFrame->FullLC.SourceAddress; - } - } - else - { - /* CRC checking error, so consider the Full LC data as invalid */ - TSVoiceSupFrame->FullLC.DataValidity = 0; - } - - /* Print the destination ID (TG) and the source ID */ - fprintf (stderr, "%s \n", KGRN); - fprintf (stderr, " SLOT %d ", state->currentslot+1); - fprintf(stderr, "TGT=%u SRC=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - fprintf(stderr, "FID=0x%02X SVC=0x%02X", TSVoiceSupFrame->FullLC.FeatureSetID, TSVoiceSupFrame->FullLC.ServiceOptions); - - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x80) fprintf(stderr, "Emergency "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x40) - { - fprintf (stderr, "%s ", KRED); - fprintf(stderr, "Encrypted "); - //fprintf (stderr, "%s ", KNRM); - } - else - { - fprintf (stderr, "%s ", KGRN); - fprintf(stderr, "Clear/Unencrypted "); - //fprintf (stderr, "%s ", KNRM); - } - - /* Check the "Reserved" bits */ - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) - { - /* Experimentally determined with DSD+, when the "Reserved" bit field - * is equal to 0x2, this is a TXI call */ - if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) == 0x20) fprintf(stderr, "TXI "); - else fprintf(stderr, "Reserved=%d ", (TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) >> 4); - } - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x08) fprintf(stderr, "Broadcast "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x04) fprintf(stderr, "OVCM "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) - { - if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x01) fprintf(stderr, "Priority 1 "); - else if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x02) fprintf(stderr, "Priority 2 "); - else if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x03) fprintf(stderr, "Priority 3 "); - else fprintf(stderr, "No Priority "); /* We should never go here */ - } - fprintf(stderr, "Call "); - fprintf (stderr, "%s ", KNRM); - - if(TSVoiceSupFrame->FullLC.DataValidity) {}//fprintf(stderr, "(CRC OK ) "); - else if(IrrecoverableErrors == 0) {}//fprintf(stderr, "RAS (FEC OK/CRC ERR)"); - else {}//fprintf(stderr, "(FEC FAIL/CRC ERR)"); - - //check Cap+ rest channel info if available - if (rest_channel != -1) - { - //fprintf (stderr, "Cap+ R-Ch=%d", rest_channel); - } - - //Full - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull Voice LC Header Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "%s", KNRM); - } - -} /* End ProcessDmrVoiceLcHeader() */ - - -void ProcessDmrTerminaisonLC(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++) - { - 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++) - { - CRCExtracted = CRCExtracted << 1; - CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); - } - - /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - CRCExtracted = CRCExtracted ^ 0x999999; - - /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x999999); - - /* 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; - } - //fprintf (stderr, "\nDDB = 0x%X \n", DmrDataBit); - /* Store the Protect Flag (PF) bit */ - TSVoiceSupFrame->FullLC.ProtectFlag = (unsigned int)(DmrDataBit[0]); - - /* Store the Reserved bit */ - TSVoiceSupFrame->FullLC.Reserved = (unsigned int)(DmrDataBit[1]); - - /* Store the Full Link Control Opcode (FLCO) */ - TSVoiceSupFrame->FullLC.FullLinkControlOpcode = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[2], 6); - - /* Store the Feature set ID (FID) */ - TSVoiceSupFrame->FullLC.FeatureSetID = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[8], 8); - //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - - /* Store the Service Options */ - TSVoiceSupFrame->FullLC.ServiceOptions = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[16], 8); - - /* Store the Group address (Talk Group) */ - TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[24], 24); - - /* Store the Source address */ - TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[48], 24); - - if((IrrecoverableErrors == 0))// && CRCCorrect) - { - /* CRC is correct so consider the Full LC data as correct/valid */ - TSVoiceSupFrame->FullLC.DataValidity = 1; - } - else - { - /* CRC checking error, so consider the Full LC data as invalid */ - TSVoiceSupFrame->FullLC.DataValidity = 0; - } - - //reset alg, keys, mi during a TLC call termination EVENT so we aren't stuck on an old value - if (state->currentslot == 0) - { - state->payload_algid = 0; - state->payload_keyid = 0; - state->payload_mi = 0; - state->dmr_fid = 0; - state->dmr_so = 0; - state->lastsrc = 0; - state->lasttg = 0; - - } - if (state->currentslot == 1) - { - state->payload_algidR = 0; - state->payload_keyidR = 0; - state->payload_miR = 0; - state->dmr_fidR = 0; - state->dmr_soR = 0; - state->lastsrcR = 0; - state->lasttgR = 0; - - } - - //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, "%s \n", KRED); - fprintf (stderr, " SLOT %d ", state->currentslot+1); - fprintf(stderr, "TGT=%u SRC=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - fprintf(stderr, "FID=0x%02X SVC=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID, TSVoiceSupFrame->FullLC.ServiceOptions); - fprintf (stderr, "%s ", KNRM); - - } - else if(IrrecoverableErrors == 0) - { - fprintf (stderr, "%s \n", KRED); - fprintf (stderr, " SLOT %d ", state->currentslot+1); - fprintf(stderr, "TGT=%u SRC=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - fprintf(stderr, "FID=0x%02X SVC=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID, TSVoiceSupFrame->FullLC.ServiceOptions); - fprintf(stderr, "RAS (FEC OK/CRC ERR) "); //tlc - fprintf (stderr, "%s ", KNRM); - - } - else {} //fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); - -#ifdef PRINT_TERMINAISON_LC_BYTES - fprintf(stderr, "\n"); - fprintf(stderr, "TERMINAISON LINK CONTROL (TLC) : "); - for(i = 0; i < 12; i++) - { - fprintf(stderr, "0x%02X", DmrDataByte[i]); - if(i != 11) fprintf(stderr, " - "); - } - - fprintf(stderr, "\n"); - - fprintf(stderr, "BPTC(196,96) Reserved bit R(0)-R(2) = 0x%02X\n", BPTCReservedBits); - - fprintf(stderr, "CRC extracted = 0x%04X - CRC computed = 0x%04X - ", CRCExtracted, CRCComputed); - - if((IrrecoverableErrors == 0) && CRCCorrect) - { - fprintf(stderr, "CRCs are equal + FEC OK !\n"); - } - else if(IrrecoverableErrors == 0) - { - else fprintf(stderr, "FEC correctly corrected but CRCs are incorrect\n"); - } - else - { - fprintf(stderr, "ERROR !!! CRCs are different and FEC Failed !\n"); - } - - fprintf(stderr, "Hamming Irrecoverable Errors = %u\n", IrrecoverableErrors); -#endif /* PRINT_TERMINAISON_LC_BYTES */ - - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull TLC Payload "); - for (i = 0; i < 12; i++) - { - fprintf (stderr, "[%02X]", DmrDataByte[i]); - } - fprintf (stderr, "%s", KNRM); - } -} /* End ProcessDmrTerminaisonLC() */ - - -/* Extract the Link Control (LC) embedded in the SYNC - * of a DMR voice superframe */ -void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) -{ - uint32_t i, j, k; - uint32_t Burst; - uint8_t BptcDataMatrix[8][16]; - uint8_t LC_DataBit[77]; - uint8_t LC_DataBytes[10]; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; - uint32_t IrrecoverableErrors; - uint8_t CRCExtracted; - uint8_t CRCComputed; - uint32_t CRCCorrect = 0; - - if(state->currentslot == 0) - { - TSVoiceSupFrame = &state->TS1SuperFrame; - } - else - { - TSVoiceSupFrame = &state->TS2SuperFrame; - } - - /* First step : Reconstitute the BPTC 16x8 matrix */ - Burst = 1; /* Burst B to E contains embedded signaling data */ - k = 0; - for(i = 0; i < 16; i++) - { - for(j = 0; j < 8; j++) - { - /* Only the LSBit of the byte is stored */ - BptcDataMatrix[j][i] = TSVoiceSupFrame->TimeSlotRawVoiceFrame[Burst].Sync[k + 8]; - k++; - - /* Go on to the next burst once 32 bit - * of the SNYC have been stored */ - if(k >= 32) - { - k = 0; - Burst++; - } - } /* End for(j = 0; j < 8; j++) */ - } /* End for(i = 0; i < 16; i++) */ - - /* Extract the 72 LC bit (+ 5 CRC bit) of the matrix */ - IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit); - - /* Convert the 77 bit of voice LC Header data into 9 bytes */ - k = 0; - for(i = 0; i < 10; i++) - { - LC_DataBytes[i] = 0; - for(j = 0; j < 8; j++) //this was changed to 10 (confused) broke Voice Burst including Alias - { - LC_DataBytes[i] = LC_DataBytes[i] << 1; - LC_DataBytes[i] = LC_DataBytes[i] | (LC_DataBit[k] & 0x01); - k++; - if(k >= 76) break; - } - } - - /* Reconstitute the 5 bit CRC */ - CRCExtracted = (LC_DataBit[72] & 1) << 4; - CRCExtracted |= (LC_DataBit[73] & 1) << 3; - CRCExtracted |= (LC_DataBit[74] & 1) << 2; - CRCExtracted |= (LC_DataBit[75] & 1) << 1; - CRCExtracted |= (LC_DataBit[76] & 1) << 0; - - /* Compute the 5 bit CRC */ - CRCComputed = ComputeCrc5Bit(LC_DataBit); - - if(CRCExtracted == CRCComputed) CRCCorrect = 1; - else CRCCorrect = 0; - - /* Store the Protect Flag (PF) bit */ - TSVoiceSupFrame->FullLC.ProtectFlag = (unsigned int)(LC_DataBit[0]); - - /* Store the Reserved bit */ - TSVoiceSupFrame->FullLC.Reserved = (unsigned int)(LC_DataBit[1]); - - /* Store the Full Link Control Opcode (FLCO) */ - TSVoiceSupFrame->FullLC.FullLinkControlOpcode = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[2], 6); - - /* Store the Feature set ID (FID) */ - TSVoiceSupFrame->FullLC.FeatureSetID = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[8], 8); - //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - - /* Store the Service Options */ - TSVoiceSupFrame->FullLC.ServiceOptions = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[16], 8); - - /* Store the Group address (Talk Group) */ - TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[24], 24); - - /* Store the Source address */ - TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[48], 24); - - /* Check the CRC values */ - if((IrrecoverableErrors == 0))// && CRCCorrect) - { - /* Data is correct */ - //fprintf(stderr, "\nLink Control (LC) Data CRCs are correct !!! Number of error = %u\n", NbOfError); - - /* CRC is correct so consider the Full LC data as correct/valid */ - TSVoiceSupFrame->FullLC.DataValidity = 1; - } - else - { - /* CRC checking error, so consider the Full LC data as invalid */ - TSVoiceSupFrame->FullLC.DataValidity = 0; - } - - //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 - // 7B-7F misc characters (colon, semicolon, etc) - // let's assume that something has to indicate end of valid characters? - - //Embedded Alias - if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x03 && TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x08) - { - sprintf (state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3], "%s", ""); //blank here so it doesn't grow out of control? - for (i = 0; i < 10; i++) - { - //full range of alphanumerical characters? - if ( (LC_DataBytes[i] > 0x19 && LC_DataBytes[i] < 0x7F) ) - { - sprintf ( state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3] + - strlen(state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3]) , "%c", LC_DataBytes[i]); - } - } - if (opts->use_ncurses_terminal == 1) - { - fprintf (stderr, "%s", KMAG); - if (state->dmr_stereo == 0) - { - fprintf(stderr, "\n"); - } - fprintf (stderr, " SLOT %d", state->currentslot+1); - fprintf (stderr, " Embedded Alias Header and Blocks: [%s%s%s%s%s]", state->dmr_callsign[state->currentslot][0], - state->dmr_callsign[state->currentslot][1], state->dmr_callsign[state->currentslot][2], - state->dmr_callsign[state->currentslot][3], state->dmr_callsign[state->currentslot][4] ); - fprintf (stderr, "%s ", KNRM); - } - } - - if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode == 0x08 && opts->payload == 1) //Embedded GPS - { - sprintf (state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3], "%s", ""); //blank here so it doesn't grow out of control? - for (i = 0; i < 10; i++) - { - //full range of alphanumerical characters? - if ( (LC_DataBytes[i] > 0x19 && LC_DataBytes[i] < 0x7F) ) - { - sprintf ( state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3] + - strlen(state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3]) , "%c", LC_DataBytes[i]); - } - } - if (opts->use_ncurses_terminal == 1) - { - fprintf (stderr, "%s", KCYN); - if (state->dmr_stereo == 0) - { - fprintf(stderr, "\n"); - } - fprintf (stderr, " SLOT %d", state->currentslot+1); - fprintf (stderr, " Embedded GPS: [%s]", state->dmr_callsign[state->currentslot][5] ); - fprintf (stderr, "%s ", KNRM); - } - } - - /* Print the destination ID (TG) and the source ID */ - if((IrrecoverableErrors == 0) && CRCCorrect) - { - if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x08) //other opcodes may convey callsigns, names, etc. was > 0x07 - { - fprintf (stderr, "%s", KGRN); - if (state->dmr_stereo == 0) - { - fprintf(stderr, "\n"); - } - fprintf (stderr, " SLOT %d ", state->currentslot+1); - fprintf(stderr, "TGT=%u SRC=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - fprintf(stderr, "FID=0x%02X SVC=0x%02X", TSVoiceSupFrame->FullLC.FeatureSetID, TSVoiceSupFrame->FullLC.ServiceOptions); - fprintf (stderr, "%s ", KNRM); - - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x80) fprintf(stderr, "Emergency "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x40) - { - fprintf (stderr, "%s ", KRED); - fprintf(stderr, "Encrypted "); - //fprintf (stderr, "%s ", KNRM); - } - else - { - fprintf (stderr, "%s ", KGRN); - fprintf(stderr, "Clear/Unencrypted "); - //fprintf (stderr, "%s ", KNRM); - } - - /* Check the "Reserved" bits */ - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) - { - /* Experimentally determined with DSD+, when the "Reserved" bit field - * is equal to 0x2, this is a TXI call */ - if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) == 0x20) fprintf(stderr, "TXI "); - else fprintf(stderr, "Reserved=%d ", (TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) >> 4); - } - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x08) fprintf(stderr, "Broadcast "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x04) fprintf(stderr, "OVCM "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) - { - if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x01) fprintf(stderr, "Priority 1 "); - else if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x02) fprintf(stderr, "Priority 2 "); - else if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x03) fprintf(stderr, "Priority 3 "); - else fprintf(stderr, "No Priority "); /* We should never go here */ - } - fprintf(stderr, "Call "); - fprintf (stderr, "%s ", KNRM); - - if (state->currentslot == 0) - { - 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; - } - if (state->currentslot == 1) - { - state->lasttgR = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrcR = TSVoiceSupFrame->FullLC.SourceAddress; - //state->dmr_color_code = state->color_code; - state->dmr_fidR = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; - } - } - } - else if(IrrecoverableErrors == 0) - { - - if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x08) //7, or 8? - { - fprintf (stderr, "%s", KGRN); - if (state->dmr_stereo == 0) - { - fprintf(stderr, "\n"); - } - fprintf (stderr, " SLOT %d ", state->currentslot+1); - fprintf(stderr, "TGT=%u SRC=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - fprintf(stderr, "FID=0x%02X SVC=0x%02X", TSVoiceSupFrame->FullLC.FeatureSetID, TSVoiceSupFrame->FullLC.ServiceOptions); - fprintf (stderr, "%s ", KRED); - fprintf(stderr, "RAS (FEC OK/CRC ERR) "); - fprintf (stderr, "%s ", KNRM); - - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x80) fprintf(stderr, "Emergency "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x40) - { - fprintf (stderr, "%s ", KRED); - fprintf(stderr, "Encrypted "); - //fprintf (stderr, "%s ", KNRM); - } - else - { - fprintf (stderr, "%s ", KGRN); - fprintf(stderr, "Clear/Unencrypted "); - //fprintf (stderr, "%s ", KNRM); - } - - /* Check the "Reserved" bits */ - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) - { - /* Experimentally determined with DSD+, when the "Reserved" bit field - * is equal to 0x2, this is a TXI call */ - if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) == 0x20) fprintf(stderr, "TXI "); - else fprintf(stderr, "Reserved=%d ", (TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) >> 4); - } - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x08) fprintf(stderr, "Broadcast "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x04) fprintf(stderr, "OVCM "); - if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) - { - if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x01) fprintf(stderr, "Priority 1 "); - else if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x02) fprintf(stderr, "Priority 2 "); - else if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x03) fprintf(stderr, "Priority 3 "); - else fprintf(stderr, "No Priority "); /* We should never go here */ - } - fprintf(stderr, "Call "); - fprintf (stderr, "%s ", KNRM); - - if (state->currentslot == 0) - { - 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; - } - if (state->currentslot == 1) - { - state->lasttgR = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrcR = TSVoiceSupFrame->FullLC.SourceAddress; - //state->dmr_color_code = state->color_code; - state->dmr_fidR = TSVoiceSupFrame->FullLC.FeatureSetID; - // state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; - } - } - } - else {} //fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); - -#ifdef PRINT_VOICE_BURST_BYTES - //fprintf(stderr, "\n"); - fprintf(stderr, "VOICE BURST BYTES : "); - for(i = 0; i < 8; i++) - { - fprintf(stderr, "0x%02X", LC_DataBytes[i]); - if(i != 9) fprintf(stderr, " - "); - } - - fprintf(stderr, "\n"); - - fprintf(stderr, "CRC extracted = 0x%04X - CRC computed = 0x%04X - ", CRCExtracted, CRCComputed); - - if((IrrecoverableErrors == 0) && CRCCorrect) - { - fprintf(stderr, "CRCs are equal + FEC OK !\n"); - } - else if(IrrecoverableErrors == 0) - { - else fprintf(stderr, "FEC correctly corrected but CRCs are incorrect\n"); - } - else - { - fprintf(stderr, "ERROR !!! CRCs are different and FEC Failed !\n"); - } - - fprintf(stderr, "Hamming Irrecoverable Errors = %u\n", IrrecoverableErrors); -#endif /* PRINT_VOICE_BURST_BYTES */ - -//Full - if (opts->payload == 1) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull Voice Burst Payload "); - for (i = 0; i < 10; i++) - { - fprintf (stderr, "[%02X]", LC_DataBytes[i]); - } - fprintf (stderr, "%s", KNRM); - - - } - -} /* End ProcessVoiceBurstSync() */ - -//LFSR code courtesy of https://github.com/mattames/LFSR/ -void LFSR(dsd_state * state) -{ - - int lfsr = 0; - if (state->currentslot == 0) - { - lfsr = state->payload_mi; - } - else lfsr = state->payload_miR; - - uint8_t cnt = 0; - - for(cnt=0;cnt<32;cnt++) - { - // Polynomial is C(x) = x^32 + x^4 + x^2 + 1 - int bit = ((lfsr >> 31) ^ (lfsr >> 3) ^ (lfsr >> 1)) & 0x1; - lfsr = (lfsr << 1) | (bit); - } - if (state->currentslot == 0) - { - if (1 == 1) - { - fprintf (stderr, "%s", KYEL); - fprintf (stderr, "\n Slot 1"); - fprintf (stderr, " DMR PI Continuation ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid); - fprintf(stderr, " Next MI: 0x%08X", lfsr); - fprintf (stderr, "%s", KNRM); - } - state->payload_mi = lfsr; - } - if (state->currentslot == 1) //else - { - if (1 == 1) - { - fprintf (stderr, "%s", KYEL); - fprintf (stderr, "\n Slot 2"); - fprintf (stderr, " DMR PI Continuation ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR); - fprintf(stderr, " Next MI: 0x%08X", lfsr); - fprintf (stderr, "%s", KNRM); - } - state->payload_miR = lfsr; - } -} - -/* - * @brief : This function compute the CRC-CCITT of the DMR data - * by using the polynomial x^16 + x^12 + x^5 + 1 - * - * @param Input : A buffer pointer of the DMR data (80 bytes) - * - * @return The 16 bit CRC - */ -uint16_t ComputeCrcCCITT(uint8_t * DMRData) -{ - uint32_t i; - uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */ - /* Polynomial x^16 + x^12 + x^5 + 1 - * Normal = 0x1021 - * Reciprocal = 0x0811 - * Reversed = 0x8408 - * Reversed reciprocal = 0x8810 */ - uint16_t Polynome = 0x1021; - for(i = 0; i < 80; i++) - { - if(((CRC >> 15) & 1) ^ (DMRData[i] & 1)) - { - CRC = (CRC << 1) ^ Polynome; - } - else - { - CRC <<= 1; - } - } - - /* Invert the CRC */ - CRC ^= 0xFFFF; - - /* Return the CRC */ - return CRC; -} /* End ComputeCrcCCITT() */ - - -/* - * @brief : This function compute the CRC-24 bit of the full - * link control by using the Reed-Solomon(12,9) FEC - * - * @param FullLinkControlDataBytes : A buffer pointer of the DMR data bytes (12 bytes) - * - * @param CRCComputed : A 32 bit pointer where the computed CRC 24-bit will be stored - * - * @param CRCMask : The 24 bit CRC mask to apply - * - * @return 0 = CRC error - * 1 = CRC is correct - */ -uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask) -{ - uint32_t i; - rs_12_9_codeword_t VoiceLCHeaderStr; - rs_12_9_poly_t syndrome; - uint8_t errors_found = 0; - rs_12_9_correct_errors_result_t result = RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND; - uint32_t CrcIsCorrect = 0; - - for(i = 0; i < 12; i++) - { - VoiceLCHeaderStr.data[i] = FullLinkControlDataBytes[i]; - - /* Apply CRC mask on each 3 last bytes - * of the full link control */ - if(i == 9) - { - VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask >> 16); - } - else if(i == 10) - { - VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask >> 8); - } - else if(i == 11) - { - VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask); - } - else - { - /* Nothing to do */ - } - } - - /* Check and correct the full link LC control with Reed Solomon (12,9) FEC */ - rs_12_9_calc_syndrome(&VoiceLCHeaderStr, &syndrome); - if(rs_12_9_check_syndrome(&syndrome) != 0) result = rs_12_9_correct_errors(&VoiceLCHeaderStr, &syndrome, &errors_found); - - /* Reconstitue the CRC */ - *CRCComputed = (uint32_t)((VoiceLCHeaderStr.data[9] << 16) & 0xFF0000); - *CRCComputed |= (uint32_t)((VoiceLCHeaderStr.data[10] << 8) & 0x00FF00); - *CRCComputed |= (uint32_t)((VoiceLCHeaderStr.data[11] << 0) & 0x0000FF); - - if((result == RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND) || - (result == RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CORRECTED)) - { - //fprintf(stderr, "CRC OK : 0x%06X\n", *CRCComputed); - CrcIsCorrect = 1; - - /* Reconstitue full link control data after FEC correction */ - for(i = 0; i < 12; i++) - { - FullLinkControlDataBytes[i] = VoiceLCHeaderStr.data[i]; - - /* Apply CRC mask on each 3 last bytes - * of the full link control */ - if(i == 9) - { - FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask >> 16); - } - else if(i == 10) - { - FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask >> 8); - } - else if(i == 11) - { - FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask); - } - else - { - /* Nothing to do */ - } - } - } - else - { - //fprintf(stderr, "CRC ERROR : 0x%06X\n", *CRCComputed); - CrcIsCorrect = 0; - } - - /* Return the CRC status */ - return CrcIsCorrect; -} /* End ComputeAndCorrectFullLinkControlCrc() */ - - -/* - * @brief : This function compute the 5 bit CRC of the DMR voice burst data - * See ETSI TS 102 361-1 chapter B.3.11 - * - * @param Input : A buffer pointer of the DMR data (72 bytes) - * - * @return The 5 bit CRC - */ -uint8_t ComputeCrc5Bit(uint8_t * DMRData) -{ - uint32_t i, j, k; - uint8_t Buffer[9]; - uint32_t Sum; - uint8_t CRC = 0; - - /* Convert the 72 bit into 9 bytes */ - k = 0; - for(i = 0; i < 9; i++) - { - Buffer[i] = 0; - for(j = 0; j < 8; j++) - { - Buffer[i] = Buffer[i] << 1; - Buffer[i] = Buffer[i] | DMRData[k++]; - } - } - - /* Add all 9 bytes */ - Sum = 0; - for(i = 0; i < 9; i++) - { - Sum += (uint32_t)Buffer[i]; - } - - /* Sum MOD 31 = CRC */ - CRC = (uint8_t)(Sum % 31); - - /* Return the CRC */ - return CRC; -} /* End ComputeCrc5Bit() */ - -uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength) - { - uint32_t Output = 0; - uint32_t i; - - for(i = 0; i < BitLength; i++) - { - Output <<= 1; - Output |= (uint32_t)(BufferIn[i] & 1); - } - - return Output; - } /* End ConvertBitIntoBytes() */ - -/* End of file */ diff --git a/src/dmr_utils.c b/src/dmr_utils.c new file mode 100644 index 0000000..1461bf8 --- /dev/null +++ b/src/dmr_utils.c @@ -0,0 +1,302 @@ +//DMR CRC/Utility Functions +//Original File - dmr_sync.c +//ConvertBitIntoBytes, ComputeCrcCCITT, ComputeCrc5Bit, ComputeAndCorrectFullLinkControlCrc, CRC32, CRC9 +//Original Source - https://github.com/LouisErigHerve/dsd + +//Additional Functions +//Hamming17123, crc8, crc8ok functions +//Original Souce - https://github.com/boatbod/op25 + +#include "dsd.h" + +// A Hamming (17,12,3) Check for completed SLC message +bool Hamming17123(uint8_t* d) +{ + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9]; + bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10]; + bool c2 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11]; + bool c3 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10]; + bool c4 = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11]; + + // Compare these with the actual bits + unsigned char n = 0x00U; + n |= (c0 != d[12]) ? 0x01U : 0x00U; + n |= (c1 != d[13]) ? 0x02U : 0x00U; + n |= (c2 != d[14]) ? 0x04U : 0x00U; + n |= (c3 != d[15]) ? 0x08U : 0x00U; + n |= (c4 != d[16]) ? 0x10U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[12] = !d[12]; return true; + case 0x02U: d[13] = !d[13]; return true; + case 0x04U: d[14] = !d[14]; return true; + case 0x08U: d[15] = !d[15]; return true; + case 0x10U: d[16] = !d[16]; return true; + + // Data bit errors + case 0x1BU: d[0] = !d[0]; return true; + case 0x1FU: d[1] = !d[1]; return true; + case 0x17U: d[2] = !d[2]; return true; + case 0x07U: d[3] = !d[3]; return true; + case 0x0EU: d[4] = !d[4]; return true; + case 0x1CU: d[5] = !d[5]; return true; + case 0x11U: d[6] = !d[6]; return true; + case 0x0BU: d[7] = !d[7]; return true; + case 0x16U: d[8] = !d[8]; return true; + case 0x05U: d[9] = !d[9]; return true; + case 0x0AU: d[10] = !d[10]; return true; + case 0x14U: d[11] = !d[11]; return true; + + // No bit errors + case 0x00U: return true; + + // Unrecoverable errors + default: return false; + } +} + +uint8_t crc8(uint8_t bits[], unsigned int len) +{ + uint8_t crc=0; + unsigned int K = 8; + uint8_t poly[9] = {1,0,0,0,0,0,1,1,1}; // crc8 poly + uint8_t buf[256]; + if (len+K > sizeof(buf)) { + //fprintf (stderr, "crc8: buffer length %u exceeds maximum %lu\n", len+K, sizeof(buf)); + return 0; + } + memset (buf, 0, sizeof(buf)); + for (unsigned int i=0; i> 15) & 1) ^ (DMRData[i] & 1)) + { + CRC = (CRC << 1) ^ Polynome; + } + else + { + CRC <<= 1; + } + } + + /* Invert the CRC */ + CRC ^= 0xFFFF; + + /* Return the CRC */ + return CRC; +} /* End ComputeCrcCCITT() */ + + +/* + * @brief : This function compute the CRC-24 bit of the full + * link control by using the Reed-Solomon(12,9) FEC + * + * @param FullLinkControlDataBytes : A buffer pointer of the DMR data bytes (12 bytes) + * + * @param CRCComputed : A 32 bit pointer where the computed CRC 24-bit will be stored + * + * @param CRCMask : The 24 bit CRC mask to apply + * + * @return 0 = CRC error + * 1 = CRC is correct + */ + +uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask) +{ + uint32_t i; + rs_12_9_codeword_t VoiceLCHeaderStr; + rs_12_9_poly_t syndrome; + uint8_t errors_found = 0; + rs_12_9_correct_errors_result_t result = RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND; + uint32_t CrcIsCorrect = 0; + + for(i = 0; i < 12; i++) + { + VoiceLCHeaderStr.data[i] = FullLinkControlDataBytes[i]; + + /* Apply CRC mask on each 3 last bytes + * of the full link control */ + if(i == 9) + { + VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask >> 16); + } + else if(i == 10) + { + VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask >> 8); + } + else if(i == 11) + { + VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask); + } + else + { + /* Nothing to do */ + } + } + + /* Check and correct the full link LC control with Reed Solomon (12,9) FEC */ + rs_12_9_calc_syndrome(&VoiceLCHeaderStr, &syndrome); + if(rs_12_9_check_syndrome(&syndrome) != 0) result = rs_12_9_correct_errors(&VoiceLCHeaderStr, &syndrome, &errors_found); + + /* Reconstitue the CRC */ + *CRCComputed = (uint32_t)((VoiceLCHeaderStr.data[9] << 16) & 0xFF0000); + *CRCComputed |= (uint32_t)((VoiceLCHeaderStr.data[10] << 8) & 0x00FF00); + *CRCComputed |= (uint32_t)((VoiceLCHeaderStr.data[11] << 0) & 0x0000FF); + + if((result == RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND) || + (result == RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CORRECTED)) + { + //fprintf(stderr, "CRC OK : 0x%06X\n", *CRCComputed); + CrcIsCorrect = 1; + + /* Reconstitue full link control data after FEC correction */ + for(i = 0; i < 12; i++) + { + FullLinkControlDataBytes[i] = VoiceLCHeaderStr.data[i]; + + /* Apply CRC mask on each 3 last bytes + * of the full link control */ + if(i == 9) + { + FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask >> 16); + } + else if(i == 10) + { + FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask >> 8); + } + else if(i == 11) + { + FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask); + } + else + { + /* Nothing to do */ + } + } + } + else + { + //fprintf(stderr, "CRC ERROR : 0x%06X\n", *CRCComputed); + CrcIsCorrect = 0; + } + + /* Return the CRC status */ + return CrcIsCorrect; +} /* End ComputeAndCorrectFullLinkControlCrc() */ + + +/* + * @brief : This function compute the 5 bit CRC of the DMR voice burst data + * See ETSI TS 102 361-1 chapter B.3.11 + * + * @param Input : A buffer pointer of the DMR data (72 bytes) + * + * @return The 5 bit CRC + */ + +uint8_t ComputeCrc5Bit(uint8_t * DMRData) +{ + uint32_t i, j, k; + uint8_t Buffer[9]; + uint32_t Sum; + uint8_t CRC = 0; + + /* Convert the 72 bit into 9 bytes */ + k = 0; + for(i = 0; i < 9; i++) + { + Buffer[i] = 0; + for(j = 0; j < 8; j++) + { + Buffer[i] = Buffer[i] << 1; + Buffer[i] = Buffer[i] | DMRData[k++]; + } + } + + /* Add all 9 bytes */ + Sum = 0; + for(i = 0; i < 9; i++) + { + Sum += (uint32_t)Buffer[i]; + } + + /* Sum MOD 31 = CRC */ + CRC = (uint8_t)(Sum % 31); + + /* Return the CRC */ + return CRC; +} /* End ComputeCrc5Bit() */ + +uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength) + { + uint32_t Output = 0; + uint32_t i; + + for(i = 0; i < BitLength; i++) + { + Output <<= 1; + Output |= (uint32_t)(BufferIn[i] & 1); + } + + return Output; + } /* End ConvertBitIntoBytes() */ + +/* + * @brief : This function compute the CRC-9 of the DMR data + * by using the polynomial x^9 + x^6 + x^4 + x^3 + 1 + * + * @param Input : A buffer pointer of the DMR data (80 bytes) + * Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes) + * Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes) + * Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes) + * + * @param NbData : The number of bit to compute + * Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes) + * Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes) + * Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes) + * + * @return The 9 bit CRC + */ \ No newline at end of file diff --git a/src/dmr_voice.c b/src/dmr_voice.c deleted file mode 100644 index db0fd24..0000000 --- a/src/dmr_voice.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Copyright (C) 2010 DSD Author - * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include "dsd.h" -#include "dmr_const.h" - -void processDMRvoice (dsd_opts * opts, dsd_state * state) -{ - // extracts AMBE frames from DMR frame - int i, j, k, l, dibit; - int *dibit_p; - char ambe_fr[4][24] = {0}; - char ambe_fr2[4][24] = {0}; - char ambe_fr3[4][24] = {0}; - const int *w, *x, *y, *z; - char sync[25]; - char syncdata[48]; - char cachdata[13] = {0}; - int mutecurrentslot; - int msMode; - char cc[4]; - unsigned char EmbeddedSignalling[16]; - unsigned int EmbeddedSignallingOk; - -#ifdef DMR_DUMP - int k; - char syncbits[49]; - char cachbits[25];12 -#endif - - /* Init the superframe buffers */ - memset(&state->TS1SuperFrame, 0, sizeof(TimeSlotVoiceSuperFrame_t)); - memset(&state->TS2SuperFrame, 0, sizeof(TimeSlotVoiceSuperFrame_t)); - - /* Init the color code status */ - state->color_code_ok = 0; - - mutecurrentslot = 0; - msMode = 0; - - dibit_p = state->dibit_buf_p - 144; - for(j = 0; j < 6; j++) - { - // 2nd half of previous slot - for(i = 0; i < 54; i++) - { - if(j > 0) - { - dibit = getDibit(opts, state); - } - else - { - dibit = *dibit_p; - dibit_p++; - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } - } - } - - // CACH - for(i = 0; i < 12; i++) - { - if(j > 0) - { - dibit = getDibit(opts, state); - } - else - { - dibit = *dibit_p; - dibit_p++; - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } - } - cachdata[i] = dibit; - if(i == 2) - { - /* Change the current slot only if we are in relayed mode (not in direct mode) */ - if(state->directmode == 0) state->currentslot = (1 & (dibit >> 1)); // bit 1 - - if(state->currentslot == 0) - { - state->slot1light[0] = '['; - state->slot1light[6] = ']'; - state->slot2light[0] = ' '; - state->slot2light[6] = ' '; - } - else - { - state->slot2light[0] = '['; - state->slot2light[6] = ']'; - state->slot1light[0] = ' '; - state->slot1light[6] = ' '; - } - - } - } - cachdata[12] = 0; - - //set state-dmrburstL and R here to a value for ncurses - if (state->currentslot == 0) - { - state->dmrburstL = 16; //use 16 for Voice? - } - if (state->currentslot == 1) - { - state->dmrburstR = 16; //Use 16 for Voice? - } - -#ifdef DMR_DUMP - k = 0; - for(i = 0; i < 12; i++) - { - dibit = cachdata[i]; - cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 - k++; - cachbits[k] = (1 & dibit) + 48; // bit 0 - k++; - } - cachbits[24] = 0; - fprintf(stderr, "%s ", cachbits); -#endif - - // current slot frame 1 - w = rW; - x = rX; - y = rY; - z = rZ; - k = 0; - for(i = 0; i < 36; i++) - { - if(j > 0) - { - dibit = getDibit(opts, state); - } - else - { - dibit = *dibit_p; - dibit_p++; - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } - } - ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 - ambe_fr[*y][*z] = (1 & dibit); // bit 0 - - /* Save the current frame in the appropriate superframe buffer */ - if(state->currentslot == 0) - { - /* Time slot 1 superframe buffer filling => RAW voice bit */ - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & dibit); // bit 0 - - /* Time slot 1 superframe buffer filling => Deinterleaved voice bit */ - state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*w][*x] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*y][*z] = (1 & dibit); // bit 0 - } - else - { - /* Time slot 2 superframe buffer filling => RAW voice bit */ - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & dibit); // bit 0 - - /* Time slot 2 superframe buffer filling => Deinterleaved voice bit */ - state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*w][*x] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*y][*z] = (1 & dibit); // bit 0 - } - - w++; - x++; - y++; - z++; - } - - // current slot frame 2 first half - w = rW; - x = rX; - y = rY; - z = rZ; - k = 0; - for(i = 0; i < 18; i++) - { - if(j > 0) - { - dibit = getDibit(opts, state); - } - else - { - dibit = *dibit_p; - dibit_p++; - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } - } - ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 - ambe_fr2[*y][*z] = (1 & dibit); // bit 0 - - /* Save the current frame in the appropriate superframe buffer */ - if(state->currentslot == 0) - { - /* Time slot 1 superframe buffer filling => RAW voice bit */ - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0 - - /* Time slot 1 superframe buffer filling => Deinterleaved voice bit */ - state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0 - } - else - { - /* Time slot 2 superframe buffer filling => RAW voice bit */ - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0 - - /* Time slot 2 superframe buffer filling => Deinterleaved voice bit */ - state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0 - } - - w++; - x++; - y++; - z++; - } - - l = 0; - // signaling data or sync - for(i = 0; i < 24; i++) - { - if(j > 0) - { - dibit = getDibit(opts, state); - } - else - { - dibit = *dibit_p; - dibit_p++; - if(opts->inverted_dmr == 1) - { - dibit = (dibit ^ 2); - } - } - syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1 - syncdata[(2*i)+1] = (1 & dibit); // bit 0 - sync[i] = (dibit | 1) + 48; - - /* Save the current frame in the appropriate superframe buffer */ - if(state->currentslot == 0) - { - /* Time slot 1 superframe buffer filling => SYNC data */ - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & dibit); // bit 0 - } - else - { - /* Time slot 2 superframe buffer filling => SYNC data */ - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & dibit); // bit 0 - } - } - sync[24] = 0; - - /* Copy the Embedded signaling (1st part) */ - for(i = 0; i < 8; i++) - { - EmbeddedSignalling[i] = syncdata[i]; - } - /* Copy the Embedded signaling (2nd part) */ - for(i = 0; i < 8; i++) - { - EmbeddedSignalling[i + 8] = syncdata[i + 40]; - } - - /* Check and correct the SlotType (apply Golay(20,8) FEC check) */ - if(QR_16_7_6_decode(EmbeddedSignalling)) EmbeddedSignallingOk = 1; - else EmbeddedSignallingOk = 0; - - /* Get the color code */ - cc[0] = EmbeddedSignalling[0]; - cc[1] = EmbeddedSignalling[1]; - cc[2] = EmbeddedSignalling[2]; - cc[3] = EmbeddedSignalling[3]; - - /* The color code is normally the same for all - * 6 received voice frame, so in case of error - * do not store it except if the last SYNC frame - * has been received. */ - if(EmbeddedSignallingOk || ((state->color_code_ok == 0) && (j == 5))) - { - /* Save the color code */ - state->color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]); - state->color_code_ok = EmbeddedSignallingOk; - } - - /* Save the Power Control (PI) indicator */ - state->PI = (unsigned int)EmbeddedSignalling[4]; - state->PI_ok = EmbeddedSignallingOk; - - /* Save the Link Control Start Stop (LCSS) indicator */ - state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]); - state->LCSS_ok = EmbeddedSignallingOk; - - if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0)) - { - mutecurrentslot = 1; - state->directmode = 0; - if(state->currentslot == 0) - { - sprintf(state->slot1light, "[slot1]"); - } - else - { - sprintf(state->slot2light, "[slot2]"); - } - } - else if(strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0) - { - mutecurrentslot = 1; - state->currentslot = 0; - state->directmode = 1; /* Direct mode */ - sprintf(state->slot1light, "[sLoT1]"); - } - else if(strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0) - { - mutecurrentslot = 1; - state->currentslot = 1; - state->directmode = 1; /* Direct mode */ - sprintf(state->slot1light, "[sLoT2]"); - } - else if((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) ) //|| (strcmp (sync, DMR_MS_VOICE_SYNC) == 0)) - { - mutecurrentslot = 0; - state->directmode = 0; - if(state->currentslot == 0) - { - sprintf(state->slot1light, "[SLOT1]"); - } - else - { - sprintf(state->slot2light, "[SLOT2]"); - } - } - else if(strcmp (sync, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0) - { - mutecurrentslot = 0; - state->currentslot = 0; - state->directmode = 1; /* Direct mode */ - sprintf(state->slot1light, "[sLoT1]"); - } - else if(strcmp (sync, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0) - { - mutecurrentslot = 0; - state->currentslot = 1; - state->directmode = 1; /* Direct mode */ - sprintf(state->slot2light, "[sLoT2]"); - } - -#ifdef DMR_DUMP - k = 0; - for(i = 0; i < 24; i++) - { - dibit = syncdata[i]; - syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 - k++; - syncbits[k] = (1 & dibit) + 48; // bit 0 - k++; - } - syncbits[48] = 0; - fprintf(stderr, "%s ", syncbits); -#endif - - // current slot frame 2 second half - for(i = 0; i < 18; i++) - { - dibit = getDibit(opts, state); - ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 - ambe_fr2[*y][*z] = (1 & dibit); // bit 0 - - /* Save the current frame in the appropriate superframe buffer */ - if(state->currentslot == 0) - { - /* Time slot 1 superframe buffer filling => RAW voice bit */ - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0 - - /* Time slot 1 superframe buffer filling => Deinterleaved voice bit */ - state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0 - } - else - { - /* Time slot 2 superframe buffer filling */ - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0 - - /* Time slot 2 superframe buffer filling => Deinterleaved voice bit */ - state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0 - } - - w++; - x++; - y++; - z++; - } - - if(mutecurrentslot == 0) - { - if(state->firstframe == 1) - { // we don't know if anything received before the first sync after no carrier is valid - state->firstframe = 0; - } - else - { - //processMbeFrame (opts, state, NULL, ambe_fr, NULL); - //processMbeFrame (opts, state, NULL, ambe_fr2, NULL); - } - } - - // current slot frame 3 - w = rW; - x = rX; - y = rY; - z = rZ; - k = 0; - for(i = 0; i < 36; i++) - { - dibit = getDibit(opts, state); - ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 - ambe_fr3[*y][*z] = (1 & dibit); // bit 0 - - /* Save the current frame in the appropriate superframe buffer */ - if(state->currentslot == 0) - { - /* Time slot 1 superframe buffer filling => RAW voice bit */ - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & dibit); // bit 0 - - /* Time slot 1 superframe buffer filling => Deinterleaved voice bit */ - state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*w][*x] = (1 & (dibit >> 1)); // bit 1 - state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*y][*z] = (1 & dibit); // bit 0 - } - else - { - /* Time slot 2 superframe buffer filling => RAW voice bit */ - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & dibit); // bit 0 - - /* Time slot 2 superframe buffer filling => Deinterleaved voice bit */ - state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*w][*x] = (1 & (dibit >> 1)); // bit 1 - state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*y][*z] = (1 & dibit); // bit 0 - } - - w++; - x++; - y++; - z++; - } - if(mutecurrentslot == 0) - { - //processMbeFrame (opts, state, NULL, ambe_fr3, NULL); - } - - // CACH - for(i = 0; i < 12; i++) - { - dibit = getDibit(opts, state); - cachdata[i] = dibit; - } - cachdata[12] = 0; - -#ifdef DMR_DUMP - k = 0; - for(i = 0; i < 12; i++) - { - dibit = cachdata[i]; - cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 - k++; - cachbits[k] = (1 & dibit) + 48; // bit 0 - k++; - } - cachbits[24] = 0; - fprintf(stderr, "%s ", cachbits); -#endif - - - // next slot - skipDibit (opts, state, 54); - - // signaling data or sync - for(i = 0; i < 24; i++) - { - dibit = getDibit(opts, state); - syncdata[i] = dibit; - sync[i] = (dibit | 1) + 48; - } - sync[24] = 0; - syncdata[24] = 0; - - if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (msMode == 1)) - { - state->directmode = 0; - if(state->currentslot == 0) - { - sprintf(state->slot2light, " slot2 "); - } - else - { - sprintf(state->slot1light, " slot1 "); - } - } - else if(strcmp (sync, DMR_BS_VOICE_SYNC) == 0) - { - state->directmode = 0; - if(state->currentslot == 0) - { - sprintf(state->slot2light, " SLOT2 "); - } - else - { - sprintf(state->slot1light, " SLOT1 "); - } - } - else if((strcmp (sync, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0) || (strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0)) - { - state->currentslot = 0; - state->directmode = 1; /* Direct mode */ - sprintf(state->slot1light, " sLoT1 "); - } - else if((strcmp (sync, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0) || (strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)) - { - state->currentslot = 1; - state->directmode = 1; /* Direct mode */ - sprintf(state->slot1light, " sLoT2 "); - } - -#ifdef DMR_DUMP - k = 0; - for(i = 0; i < 24; i++) - { - dibit = syncdata[i]; - syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1 - k++; - syncbits[k] = (1 & dibit) + 48; // bit 0 - k++; - } - syncbits[48] = 0; - fprintf(stderr, "%s ", syncbits); -#endif - - if(j == 5) //j == 5 - { - - // 2nd half next slot - skipDibit (opts, state, 54); - - // CACH - skipDibit (opts, state, 12); - - // first half current slot - skipDibit (opts, state, 54); - } - - /* Extract the 49 bits AMBE of the voice frame */ - if(state->currentslot == 0) - { - /* 3 x 49 bit of AMBE sample per voice frame => Slot 1buffer here */ - for(i = 0; i < 3; i++) - { - state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i] = mbe_eccAmbe3600x2450C0(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]); - - state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i]; - - mbe_demodulateAmbe3600x2450Data(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]); - state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] += mbe_eccAmbe3600x2450Data(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i], - &(state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].AmbeBit[i][0])); - } - - } - else - { - /* 3 x 49 bit of AMBE sample per voice frame => Slot 2 buffer here */ - for(i = 0; i < 3; i++) - { - state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i] = mbe_eccAmbe3600x2450C0(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]); - - state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i]; - - mbe_demodulateAmbe3600x2450Data(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]); - state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] += mbe_eccAmbe3600x2450Data(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i], - &(state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].AmbeBit[i][0])); - } - - } - - } /* End for(j = 0; j < 6; j++) */ - - if(opts->errorbars == 1) - { - fprintf(stderr, "%s %s ", state->slot1light, state->slot2light); - - /* Print the color code */ - fprintf (stderr, "%s", KCYN); - fprintf(stderr, "| Color Code=%02d ", (int)state->color_code); - fprintf (stderr, "%s", KNRM); - - //if(state->color_code_ok) fprintf(stderr, "(OK) |"); - if(state->color_code_ok) - { - fprintf(stderr, "| (CRC OK ) |"); //add line break - state->dmr_color_code = state->color_code; //set here when voice? otherwise is set off of idle. - } - else - { - fprintf (stderr, "%s", KRED); - fprintf(stderr, "| (CRC ERR) |"); //add line break - fprintf (stderr, "%s", KNRM); - } - - fprintf(stderr, " VOICE "); - } - - /* Perform the SYNC DMR data embedded decoding */ - ProcessVoiceBurstSync(opts, state); - - /* Perform the DMR voice decoding */ - ProcessDMR(opts, state); - - //LFSR if required, change condition? - if ( (state->currentslot == 0 && state->payload_algid == 0x21 ) || //&& opts->payload == 1 - (state->currentslot == 1 && state->payload_algidR == 0x21 ) ) //&& opts->payload == 1 - { - LFSR(state); - } - - if(opts->errorbars == 1) - { - fprintf(stderr, "\n"); - } - -} /* End processDMRvoice() */ diff --git a/src/dsd_file.c b/src/dsd_file.c index b62af6c..ba477dc 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -166,7 +166,7 @@ PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and } void -PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stereo, may use this for NXDN too +PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) { int i, j, k; unsigned char b; @@ -174,7 +174,7 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere err = (unsigned char) state->errs2; k = 0; - if (opts->dmr_stereo == 0) + if (opts->dmr_stereo == 0 && opts->dmr_mono == 0) { fprintf (stderr, "\n"); } @@ -183,7 +183,7 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere fprintf(stderr, " AMBE "); } - 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 + for (i = 0; i < 7; i++) { b = 0; for (j = 0; j < 8; j++) @@ -192,13 +192,13 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere b = b + ambe_d[k]; k++; } - if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this + if (opts->payload == 1 && i < 6) { fprintf (stderr, "%02X", b); } - if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit, value will be either 0x00 or 0x80? + if (opts->payload == 1 && i == 6) { - fprintf (stderr, "%02X", b & 0x80); //7th octet should only contain 1 bit + fprintf (stderr, "%02X", b & 0x80); } } if (state->currentslot == 0) @@ -207,7 +207,7 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere } else fprintf(stderr, " err = [%X] [%X] ", state->errsR, state->errs2R); b = ambe_d[48]; - if (opts->dmr_stereo == 1) //need to fix the printouts again + if (opts->dmr_stereo == 1 || opts->dmr_mono == 1) //need to fix the printouts again { fprintf (stderr, "\n"); } @@ -226,7 +226,7 @@ readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d) k = 0; - if (opts->payload == 1) //make opt variable later on to toggle this + if (opts->payload == 1) { fprintf(stderr, "\n"); } @@ -248,12 +248,12 @@ readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d) b = b & 255; k++; } - //new printout on reading MBE files back in - if (opts->payload == 1) //make opt variable later on to toggle this + + if (opts->payload == 1) { fprintf (stderr, "%02X", x); } - // + } if (opts->payload == 1) { @@ -273,11 +273,11 @@ readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d) state->errs = state->errs2; k = 0; - if (opts->payload == 1) //make opt variable later on to toggle this + if (opts->payload == 1) { fprintf(stderr, "\n"); } - //for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) //breaks backwards compatablilty with 6 files { b = fgetc (opts->mbe_in_f); @@ -296,13 +296,13 @@ readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d) b = b & 255; k++; } - if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this + if (opts->payload == 1 && i < 6) { fprintf (stderr, "%02X", x); } - if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit? value will be either 0x00 or 0x80? + if (opts->payload == 1 && i == 6) { - fprintf (stderr, "%02X", x & 0x80); //7th octet should only contain 1 bit? + fprintf (stderr, "%02X", x & 0x80); } } if (opts->payload == 1) @@ -349,82 +349,6 @@ openMbeInFile (dsd_opts * opts, dsd_state * state) } -//temporarily disabled until the compiler warnings can be fixed, use symbol capture or per call instead! -//probably the easiest thing is to just have this run fclose, and have name assignment on open instead. -// void -// closeMbeOutFile (dsd_opts * opts, dsd_state * state) -// { -// -// char shell[255], newfilename[64], ext[5], datestr[32], new_path[1024]; -// char tgid[17]; -// int sum, i, j; -// int talkgroup; -// struct tm timep; -// int result; -// -// if (opts->mbe_out_f != NULL) -// { -// if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15)) -// { -// sprintf (ext, ".imb"); -// //strptime (opts->mbe_out_file, "%s.imb", &timep); -// } -// else -// { -// sprintf (ext, ".amb"); -// //strptime (opts->mbe_out_file, "%s.amb", &timep); -// } -// -// if (state->tgcount > 0) -// { -// for (i = 0; i < 16; i++) -// { -// sum = 0; -// for (j = 0; j < state->tgcount; j++) -// { -// sum = sum + state->tg[j][i] - 48; -// } -// tgid[i] = (char) (((float) sum / (float) state->tgcount) + 48.5); -// } -// tgid[16] = 0; -// talkgroup = (int) strtol (tgid, NULL, 2); -// } -// else -// { -// talkgroup = 0; -// } -// -// fflush (opts->mbe_out_f); -// fclose (opts->mbe_out_f); -// opts->mbe_out_f = NULL; -// strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep); -// -// sprintf (newfilename, "%s%s", datestr, ext); //this one -// -// if (state->lastsynctype == 0 || state->lastsynctype == 1) -// { -// sprintf (newfilename, "%s-nac%X-tg%i%s", datestr, state->nac, talkgroup, ext); -// } -// -// //sprintf (new_path, "%s%s", opts->mbe_out_dir, newfilename); -// #ifdef _WIN32 -// //sprintf (shell, "move %s %s", opts->mbe_out_path, new_path); -// #else -// //sprintf (shell, "mv %s %s", opts->mbe_out_path, new_path); -// #endif -// //result = system (shell); -// -// state->tgcount = 0; -// for (i = 0; i < 25; i++) -// { -// for (j = 0; j < 16; j++) -// { -// state->tg[i][j] = 48; -// } -// } -// } -// } - //much simpler version void closeMbeOutFile (dsd_opts * opts, dsd_state * state) { @@ -447,7 +371,6 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state) { - //struct timeval tv; int i, j; char ext[5]; @@ -471,10 +394,6 @@ openMbeOutFile (dsd_opts * opts, dsd_state * state) state->tgcount = 0; - //gettimeofday (&tv, NULL); - //rewrite below line to take getTime function instead? - // sprintf (opts->mbe_out_file, "%i%s", (int) tv.tv_sec, ext); - sprintf (opts->mbe_out_file, "%s %s%s", getDateF(), getTimeF(), ext); sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file); @@ -500,7 +419,6 @@ openWavOutFile (dsd_opts * opts, dsd_state * state) info.samplerate = 8000; //8000 info.channels = 1; info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; - //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file if (opts->wav_out_f == NULL) @@ -508,18 +426,15 @@ openWavOutFile (dsd_opts * opts, dsd_state * state) fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file); return; } - -// state->wav_out_bytes = 0; - } + void openWavOutFileL (dsd_opts * opts, dsd_state * state) { SF_INFO info; - info.samplerate = 8000; //8000 + info.samplerate = 8000; info.channels = 1; info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; - //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file if (opts->wav_out_f == NULL) @@ -527,9 +442,6 @@ void openWavOutFileL (dsd_opts * opts, dsd_state * state) fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file); return; } - -// state->wav_out_bytes = 0; - } void openWavOutFileR (dsd_opts * opts, dsd_state * state) @@ -539,7 +451,6 @@ void openWavOutFileR (dsd_opts * opts, dsd_state * state) info.samplerate = 8000; //8000 info.channels = 1; info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; - //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); opts->wav_out_fR = sf_open (opts->wav_out_fileR, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file if (opts->wav_out_f == NULL) @@ -547,9 +458,6 @@ void openWavOutFileR (dsd_opts * opts, dsd_state * state) fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_fileR); return; } - -// state->wav_out_bytes = 0; - } void openWavOutFileRaw (dsd_opts * opts, dsd_state * state) @@ -559,17 +467,12 @@ void openWavOutFileRaw (dsd_opts * opts, dsd_state * state) info.samplerate = 48000; //8000 info.channels = 1; info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; - //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); - //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_RDWR, &info); if (opts->wav_out_raw == NULL) { fprintf (stderr,"Error - could not open raw wav output file %s\n", opts->wav_out_file_raw); return; } - -// state->wav_out_bytes = 0; - } void closeWavOutFile (dsd_opts * opts, dsd_state * state) @@ -609,15 +512,12 @@ void closeSymbolOutFile (dsd_opts * opts, dsd_state * state) //Do something if (opts->symbol_out == 1) { - if (opts->symbol_out_file != NULL) //check first, or issuing a second fclose will crash the SOFTWARE + if (opts->symbol_out_file != NULL) { - fclose(opts->symbol_out_f); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once - //noCarrier(opts, state); //free(): double free detected in tcache 2 (this is a new one) + fclose(opts->symbol_out_f); } opts->symbol_out = 0; //set flag to 1 - //sprintf (opts->symbol_out_file, "fme-capture.bin"); //use fme for the symbol bin ext - //openSymbolOutFile (opts, state); } diff --git a/src/dsd_frame.c b/src/dsd_frame.c index badc17e..08a9eb9 100644 --- a/src/dsd_frame.c +++ b/src/dsd_frame.c @@ -163,13 +163,14 @@ processFrame (dsd_opts * opts, dsd_state * state) { sprintf (state->slot1light, " slot1 "); sprintf (state->slot2light, " slot2 "); - processDMRvoice (opts, state); + dmrMSBootstrap (opts, state); } - if (opts->dmr_stereo == 0 && state->synctype == 32) + if (opts->dmr_mono == 1 && state->synctype == 32) { - fprintf (stderr, "%s", KRED); - fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n"); - fprintf (stderr, "%s", KNRM); + // fprintf (stderr, "%s", KRED); + // fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n"); + // fprintf (stderr, "%s", KNRM); + dmrMSBootstrap (opts, state); } if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1 { @@ -183,19 +184,20 @@ processFrame (dsd_opts * opts, dsd_state * state) } else if ( (state->synctype == 33) || (state->synctype == 34) ) //MS Data and RC data { - if (opts->dmr_stereo == 0) - { - closeMbeOutFile (opts, state); - state->err_str[0] = 0; - fprintf (stderr, "%s", KRED); - fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n"); - fprintf (stderr, "%s", KNRM); - } - if (opts->dmr_stereo == 1) - { - dmrMSData (opts, state); + dmrMSData (opts, state); + // if (opts->dmr_stereo == 0) + // { + // closeMbeOutFile (opts, state); + // state->err_str[0] = 0; + // fprintf (stderr, "%s", KRED); + // fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n"); + // fprintf (stderr, "%s", KNRM); + // } + // if (opts->dmr_stereo == 1) + // { + // dmrMSData (opts, state); - } + // } } else { @@ -206,7 +208,7 @@ processFrame (dsd_opts * opts, dsd_state * state) sprintf (state->slot1light, " slot1 "); sprintf (state->slot2light, " slot2 "); state->payload_miP = 0; //zero out when switching back to data sync - processDMRdata (opts, state); + dmr_data_sync (opts, state); } //switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata if (opts->dmr_stereo == 1) @@ -215,7 +217,7 @@ processFrame (dsd_opts * opts, dsd_state * state) sprintf (state->slot1light, " slot1 "); sprintf (state->slot2light, " slot2 "); state->payload_miP = 0; //zero out when switching back to data sync - processDMRdata (opts, state); + dmr_data_sync (opts, state); } } return; diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index a5c44fb..e11e864 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -889,7 +889,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) sprintf(state->ftype, "DMR "); if (opts->errorbars == 1 && opts->dmr_stereo == 0) { - printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); + //printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); } if (state->lastsynctype != 11) { @@ -1003,7 +1003,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) sprintf(state->ftype, "DMR "); if (opts->errorbars == 1 && opts->dmr_stereo == 0) { - printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation); + //printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation); } if (state->lastsynctype != 12) { diff --git a/src/dsd_main.c b/src/dsd_main.c index cd4ed57..a3d489f 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -201,6 +201,8 @@ noCarrier (dsd_opts * opts, dsd_state * state) state->HYTR = 0; state->DMRvcL = 0; state->DMRvcR = 0; + state->dropL = 256; + state->dropR = 256; state->payload_miN = 0; state->p25vc = 0; @@ -210,19 +212,6 @@ noCarrier (dsd_opts * opts, dsd_state * state) state->dmr_lrrp_source[0] = 0; state->dmr_lrrp_source[1] = 0; - //initialize 12 rate superframe - for (short i = 0; i < 288; i++) - { - state->dmr_12_rate_sf[0][i] = 0; - state->dmr_12_rate_sf[1][i] = 0; - } - - //initialize 34 rate superframe - for (short i = 0; i < 288; i++) - { - state->dmr_34_rate_sf[0][i] = 0; - state->dmr_34_rate_sf[1][i] = 0; - } //initialize data header bits state->data_header_blocks[0] = 1; //initialize with 1, otherwise we may end up segfaulting when no/bad data header @@ -268,7 +257,29 @@ noCarrier (dsd_opts * opts, dsd_state * state) memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment)); sprintf (state->nxdn_call_type, "%s", ""); -} + state->dmr_rest_channel = -1; //init on -1 + sprintf(state->dmr_branding_sub, "%s", ""); + sprintf(state->dmr_branding, "%s", ""); + state->dmr_mfid = 0; + + //dmr slco stuff + memset(state->dmr_cach_fragment, 0, sizeof(state->dmr_cach_fragment)); + state->dmr_cach_counter = 0; + + //initialize unified dmr pdu 'superframe' + memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf)); + + //init confirmed data individual block crc as invalid + memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid)); + + //embedded signalling + memset(state->dmr_embedded_signalling, 0, sizeof(state->dmr_embedded_signalling)); + + //late entry mi fragments + memset (state->late_entry_mi_fragment, 0, sizeof (state->late_entry_mi_fragment)); + + +} //nocarrier void initOpts (dsd_opts * opts) @@ -376,6 +387,7 @@ initOpts (dsd_opts * opts) opts->ncurses_history = 1; opts->payload = 0; opts->inverted_dpmr = 0; + opts->dmr_mono = 0; opts->dmr_stereo = 1; opts->aggressive_framesync = 1; //more aggressive to combat wonk wonk voice decoding //see if initializing these values causes issues elsewhere, if so, then disable. @@ -414,7 +426,7 @@ initOpts (dsd_opts * opts) opts->p25_is_tuned = 0; //set to 1 if currently on VC, set back to 0 on carrier drop opts->trunk_hangtime = 1; //1 second hangtime by default before tuning back to CC -} +} //initopts void initState (dsd_state * state) @@ -569,7 +581,6 @@ initState (dsd_state * state) state->fourv_counter[0] = 0; state->fourv_counter[1] = 0; - sprintf (state->dmr_branding, "%s", ""); sprintf (state->dmr_callsign[0][0], "%s", ""); sprintf (state->dmr_callsign[0][1], "%s", ""); sprintf (state->dmr_callsign[0][2], "%s", ""); @@ -618,6 +629,8 @@ initState (dsd_state * state) state->HYTR = 0; state->DMRvcL = 0; state->DMRvcR = 0; + state->dropL = 256; + state->dropR = 256; state->p25vc = 0; @@ -629,19 +642,6 @@ initState (dsd_state * state) state->dmr_lrrp_source[0] = 0; state->dmr_lrrp_source[1] = 0; - //initialize 12 rate superframe - for (short i = 0; i < 288; i++) - { - state->dmr_12_rate_sf[0][i] = 0; - state->dmr_12_rate_sf[1][i] = 0; - } - - //initialize 34 rate superframe - for (short i = 0; i < 288; i++) - { - state->dmr_34_rate_sf[0][i] = 0; - state->dmr_34_rate_sf[1][i] = 0; - } //initialize data header bits state->data_header_blocks[0] = 1; //initialize with 1, otherwise we may end up segfaulting when no/bad data header @@ -735,6 +735,30 @@ initState (dsd_state * state) state->dmr_end_alert[0] = 0; state->dmr_end_alert[1] = 0; + sprintf (state->dmr_branding, "%s", ""); + sprintf (state->dmr_branding_sub, "%s", ""); + + //initialize unified dmr pdu 'superframe' + memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf)); + + //init confirmed data individual block crc as invalid + memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid)); + + //dmr slco stuff + memset(state->dmr_cach_fragment, 0, sizeof(state->dmr_cach_fragment)); + state->dmr_cach_counter = 0; + + //embedded signalling + memset(state->dmr_embedded_signalling, 0, sizeof(state->dmr_embedded_signalling)); + + //dmr talker alias new/fixed stuff + memset(state->dmr_alias_format, 0, sizeof(state->dmr_alias_format)); + memset(state->dmr_alias_len, 0, sizeof(state->dmr_alias_len)); + memset(state->dmr_alias_block_segment, 0, sizeof(state->dmr_alias_block_segment)); + + //late entry mi fragments + memset (state->late_entry_mi_fragment, 0, sizeof (state->late_entry_mi_fragment)); + initialize_p25_heuristics(&state->p25_heuristics); } @@ -805,7 +829,7 @@ usage () printf (" -fs DMR Stereo BS and MS Simplex only\n"); printf (" -f1 Decode only P25 Phase 1\n"); printf (" -fd Decode only D-STAR\n"); - printf (" -fr Decode only DMR (LEH)\n"); + printf (" -fr Decode only DMR Mono - Single Slot Voice\n"); printf (" -fx Decode only X2-TDMA\n"); printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n"); printf (" -fn Decode only NXDN96* (12.5 kHz)\n"); @@ -860,7 +884,7 @@ usage () printf (" (See channel_map.csv for example)\n"); printf (" -2 Import Group List Allow/Block and Label from csv file (numeral 'two')\n"); printf (" (See group.csv for example)\n"); - printf (" -3 Enable Extremely Experimental Trunking Features (NXDN/P25/EDACS for now) with RIGCTL/TCP or RTL Input\n"); + printf (" -3 Enable Extremely Experimental Trunking Features (NXDN/P25/EDACS/DMR TIII, Con+) with RIGCTL/TCP or RTL Input\n"); printf (" -5 Enable RIGCTL/TCP; Set UDP Port for RIGCTL. (4532 on SDR++)\n"); printf (" -6 Set Trunking VC/sync loss hangtime in seconds. (default = 1 second)\n"); //printf (" (Currently only available on UDP port 4532)\n"); @@ -1000,29 +1024,6 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) fprintf (stderr,"Total audio errors: %i\n", state->debug_audio_errors); fprintf (stderr,"Total header errors: %i\n", state->debug_header_errors); fprintf (stderr,"Total irrecoverable header errors: %i\n", state->debug_header_critical_errors); - - //debug_print_heuristics(&(state->p25_heuristics)); - - fprintf (stderr,"\n"); - fprintf (stderr,"+P25 BER estimate: %.2f%%\n", get_P25_BER_estimate(&state->p25_heuristics)); - fprintf (stderr,"-P25 BER estimate: %.2f%%\n", get_P25_BER_estimate(&state->inv_p25_heuristics)); - fprintf (stderr,"\n"); - -#ifdef TRACE_DSD - if (state->debug_label_file != NULL) { - fclose(state->debug_label_file); - state->debug_label_file = NULL; - } - if(state->debug_label_dibit_file != NULL) { - fclose(state->debug_label_dibit_file); - state->debug_label_dibit_file = NULL; - } - if(state->debug_label_imbe_file != NULL) { - fclose(state->debug_label_imbe_file); - state->debug_label_imbe_file = NULL; - } -#endif - fprintf (stderr,"Exiting.\n"); exit (0); } @@ -1103,10 +1104,9 @@ main (int argc, char **argv) usage (); exit (0); case 'a': - //printPortAudioDevices(); - //exit(0); opts.call_alert = 1; break; + //placeholder until letters get re-arranged (or opt_long switched in) case '1': //LCN to Frequency CSV Import strncpy(opts.lcn_in_file, optarg, 1023); @@ -1169,7 +1169,6 @@ main (int argc, char **argv) } break; case 'P': - //can't handle negative numbers? sscanf (optarg, "%d", &opts.rtlsdr_ppm_error); break; case 'q': @@ -1177,18 +1176,10 @@ main (int argc, char **argv) opts.verbose = 0; break; case 's': - // opts.errorbars = 0; - // opts.p25enc = 0; - // opts.p25lc = 0; - // opts.p25status = 0; - // opts.p25tg = 0; - // opts.datascope = 1; - // opts.symboltiming = 0; sscanf (optarg, "%d", &opts.wav_sample_rate); opts.wav_interpolator = opts.wav_sample_rate / opts.wav_decimator; state.samplesPerSymbol = state.samplesPerSymbol * opts.wav_interpolator; state.symbolCenter = state.symbolCenter * opts.wav_interpolator; - //fprintf (stderr, "Are we getting this far?\n"); break; case 't': opts.symboltiming = 1; @@ -1249,21 +1240,6 @@ main (int argc, char **argv) opts.dmr_mute_encR = 1; } state.H = state.K1; //shim still required? - - //old handling for 10 Char Key - // sscanf (optarg, "%llX", &state.H); - // if (state.H > 0xFFFFFFFFFF) - // { - // state.H = 0xFFFFFFFFFF; - // } - // opts.dmr_mute_encL = 0; - // opts.dmr_mute_encR = 0; - // if (state.H == 0) - // { - // opts.dmr_mute_encL = 1; - // opts.dmr_mute_encR = 1; - // } - // state.K1 = state.H; //shim break; case '4': @@ -1423,11 +1399,6 @@ main (int argc, char **argv) opts.serial_dev[1023] = '\0'; break; - // case 'R': - // sscanf (optarg, "%d", &opts.resume); - // fprintf (stderr,"Enabling scan resume after %i TDULC frames\n", opts.resume); - // break; - case 'f': if (optarg[0] == 'a') { @@ -1444,6 +1415,7 @@ main (int argc, char **argv) opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; + opts.dmr_mono = 1; state.dmr_stereo = 0; sprintf (opts.output_name, "Legacy Auto"); } @@ -1463,6 +1435,7 @@ main (int argc, char **argv) opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; state.dmr_stereo = 0; + opts.dmr_mono = 0; state.rf_mod = 0; sprintf (opts.output_name, "D-STAR"); fprintf (stderr,"Decoding only D-STAR frames.\n"); @@ -1482,6 +1455,7 @@ main (int argc, char **argv) opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; + opts.dmr_mono = 0; state.dmr_stereo = 0; sprintf (opts.output_name, "X2-TDMA"); fprintf (stderr,"Decoding only X2-TDMA frames.\n"); @@ -1507,6 +1481,7 @@ main (int argc, char **argv) opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; + opts.dmr_mono = 0; state.dmr_stereo = 0; sprintf (opts.output_name, "EDACS/PV"); fprintf (stderr,"Setting symbol rate to 9600 / second\n"); @@ -1530,6 +1505,8 @@ main (int argc, char **argv) opts.mod_qpsk = 0; opts.mod_gfsk = 0; state.rf_mod = 0; // + opts.dmr_stereo = 0; + opts.dmr_mono = 0; opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; sprintf (opts.output_name, "P25P1"); @@ -1557,6 +1534,7 @@ main (int argc, char **argv) opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; state.dmr_stereo = 0; + opts.dmr_mono = 0; sprintf (opts.output_name, "NXDN48"); fprintf (stderr,"Setting symbol rate to 2400 / second\n"); fprintf (stderr,"Decoding only NXDN 4800 baud frames.\n"); @@ -1584,6 +1562,7 @@ main (int argc, char **argv) opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; state.dmr_stereo = 0; + opts.dmr_mono = 0; sprintf (opts.output_name, "YSF"); fprintf (stderr,"Setting symbol rate to 2400 / second\n"); fprintf (stderr,"Decoding only YSF frames.\nNot working yet!\n"); @@ -1608,6 +1587,7 @@ main (int argc, char **argv) state.rf_mod = 0; opts.dmr_stereo = 1; state.dmr_stereo = 0; + opts.dmr_mono = 0; sprintf (opts.output_name, "P25P2"); fprintf (stderr,"Decoding P25-P2 frames C4FM or OP25 Symbol Captures!\n"); } @@ -1629,7 +1609,7 @@ main (int argc, char **argv) opts.mod_gfsk = 0; state.rf_mod = 0; opts.dmr_stereo = 1; - //state.dmr_stereo = 1; //manually set to 1 + opts.dmr_mono = 0; opts.pulse_digi_rate_out = 24000; opts.pulse_digi_out_channels = 2; sprintf (opts.output_name, "DMR Stereo"); @@ -1655,7 +1635,7 @@ main (int argc, char **argv) //or consider using an external modulator (GNURadio?) state.rf_mod = 0; opts.dmr_stereo = 1; - //state.dmr_stereo = 1; + opts.dmr_mono = 0; opts.pulse_digi_rate_out = 24000; opts.pulse_digi_out_channels = 2; sprintf (opts.output_name, "XDMA"); @@ -1680,6 +1660,7 @@ main (int argc, char **argv) opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; + opts.dmr_mono = 0; state.dmr_stereo = 0; sprintf (opts.output_name, "NXDN96"); fprintf (stderr,"Decoding only NXDN 9600 baud frames.\n"); @@ -1702,11 +1683,34 @@ main (int argc, char **argv) state.rf_mod = 0; // opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; + opts.dmr_mono = 1; opts.dmr_stereo = 0; - state.dmr_stereo = 0; - sprintf (opts.output_name, "DMR LEH"); - fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n"); - fprintf (stderr,"Decoding only DMR frames.\n"); + state.dmr_stereo = 0; //0 + sprintf (opts.output_name, "DMR Mono"); + //fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n"); + fprintf (stderr,"Decoding only DMR Mono. \nUsing DMR Stereo or XDMA is highly encouraged.\n"); + //dmr stereo below + // opts.frame_dstar = 0; + // opts.frame_x2tdma = 0; + // opts.frame_p25p1 = 0; + // opts.frame_p25p2 = 0; + // opts.inverted_p2 = 0; + // opts.frame_nxdn48 = 0; + // opts.frame_nxdn96 = 0; + // opts.frame_dmr = 1; + // opts.frame_dpmr = 0; + // opts.frame_provoice = 0; + // opts.frame_ysf = 0; + // opts.mod_c4fm = 1; + // opts.mod_qpsk = 0; + // opts.mod_gfsk = 0; + // state.rf_mod = 0; + // opts.dmr_stereo = 1; + // state.dmr_stereo = 0; + // opts.pulse_digi_rate_out = 24000; + // opts.pulse_digi_out_channels = 2; + // sprintf (opts.output_name, "DMR Stereo"); + // fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n"); } else if (optarg[0] == 'm') { @@ -1729,6 +1733,7 @@ main (int argc, char **argv) opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; + opts.dmr_mono = 0; state.dmr_stereo = 0; sprintf (opts.output_name, "dPMR"); fprintf(stderr, "Notice: dPMR cannot autodetect polarity. \n Use -xd option if Inverted Signal expected.\n"); @@ -1739,10 +1744,11 @@ main (int argc, char **argv) case 'm': if (optarg[0] == 'a') { - opts.mod_c4fm = 1; - opts.mod_qpsk = 1; - opts.mod_gfsk = 1; - state.rf_mod = 0; + // opts.mod_c4fm = 1; + // opts.mod_qpsk = 1; + // opts.mod_gfsk = 1; + // state.rf_mod = 0; + fprintf (stderr,"Don't use the -ma switch.\n"); } else if (optarg[0] == 'c') { @@ -1927,8 +1933,6 @@ main (int argc, char **argv) opts.audio_out_type = 0; } - - if((strncmp(opts.audio_in_dev, "pulse", 5) == 0)) { opts.audio_in_type = 0; diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index d1ced58..425948e 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -245,7 +245,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a else { //stereo slots and slot 0 (left slot) - if (state->currentslot == 0 && opts->dmr_stereo == 1) + if (state->currentslot == 0) //&& opts->dmr_stereo == 1 { state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr); @@ -340,7 +340,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } } //stereo slots and slot 1 (right slot) - if (state->currentslot == 1 && opts->dmr_stereo == 1) + if (state->currentslot == 1) //&& opts->dmr_stereo == 1 { state->errsR = mbe_eccAmbe3600x2450C0 (ambe_fr); @@ -435,19 +435,19 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } //X2-TDMA? Not sure what still makes it this far to run under Framef - if (opts->dmr_stereo == 0) - { - mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - if (opts->payload == 1) - { - PrintAMBEData (opts, state, ambe_d); - } - //only save MBE files if not enc or unmuted, THIS does not seem to work for some reason - if (opts->mbe_out_f != NULL && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) ) - { - saveAmbe2450Data (opts, state, ambe_d); - } - } + // if (opts->dmr_stereo == 0) + // { + // mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + // if (opts->payload == 1) + // { + // PrintAMBEData (opts, state, ambe_d); + // } + // //only save MBE files if not enc or unmuted, THIS does not seem to work for some reason + // if (opts->mbe_out_f != NULL && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) ) + // { + // saveAmbe2450Data (opts, state, ambe_d); + // } + // } } @@ -456,7 +456,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a int enc_bit = 0; //end enc check - if (opts->dmr_stereo == 1 && state->currentslot == 0) + if ( (opts->dmr_mono == 1 ||opts->dmr_stereo == 1) && state->currentslot == 0) //all mono traffic routed through 'left' { enc_bit = (state->dmr_so >> 6) & 0x1; if (enc_bit == 1) @@ -494,7 +494,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } } - if (opts->dmr_stereo == 1 && state->currentslot == 1) + if (opts->dmr_stereo == 1 && state->currentslot == 1) { enc_bit = (state->dmr_soR >> 6) & 0x1; if (enc_bit == 0x1) @@ -533,7 +533,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } //if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types - if (opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) ) + if (opts->dmr_mono == 0 && opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) ) { state->debug_audio_errors += state->errs2; if (opts->audio_out == 1)