diff --git a/include/dsd.h b/include/dsd.h index 3b2e04a..7ad75b5 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -527,11 +527,12 @@ typedef struct int directmode; 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 + int data_header_blocks[2]; //collect number of blocks to follow from data header per slot + int data_block_counter[2]; //counter for number of data blocks collected + uint8_t data_header_valid[2]; //flag for verifying the data header if still valid (in case of tact/burst fec errs) uint8_t data_header_padding[2]; //collect number of padding octets in last block per slot uint8_t data_header_format[2]; //collect format of data header (conf or unconf) per slot uint8_t data_header_sap[2]; //collect sap info per slot - 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 @@ -927,11 +928,12 @@ 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_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t dheader_bits[], 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 block_len, uint8_t DMR_PDU[]); void dmr_reset_blocks (dsd_opts * opts, dsd_state * state); -uint8_t dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]); +void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]); +void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]); //dmr alg stuff void dmr_alg_reset (dsd_opts * opts, dsd_state * state); @@ -951,6 +953,7 @@ uint8_t crc7(uint8_t bits[], unsigned int len); //LFSR code courtesy of https://github.com/mattames/LFSR/ void LFSR(dsd_state * state); void LFSRN (char * BufferIn, char * BufferOut, dsd_state * state); +void LFSR64(dsd_state * state); void Hamming_7_4_init(); void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits); diff --git a/src/dmr_block.c b/src/dmr_block.c index 1ef754c..7ba5678 100644 --- a/src/dmr_block.c +++ b/src/dmr_block.c @@ -8,286 +8,377 @@ #include "dsd.h" -void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors) +//hopefully a more simplified (or logical) version...once you get past all the variables +void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t dheader_bits[], 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; - } + for (short int i = 0; i < 288; i++) state->dmr_pdu_sf[slot][i] = 0; - //TODO: ONLY RUN ON GOOD CRC? + //reset block counter to 1 + state->data_block_counter[slot] = 1; - //collect relevant data header info, figure out format, and grab appropriate info from it - if (state->data_p_head[slot] == 0) + if (IrrecoverableErrors == 0 && CRCCorrect == 1) //&&CRCCorrect == 1 { + + uint8_t gi = dheader_bits[0]; //group or individual data + uint8_t a = dheader_bits[1]; //response requested flag + uint8_t ab = (uint8_t)ConvertBitIntoBytes(&dheader_bits[2], 2); //appended blocks + uint8_t dpf = (uint8_t)ConvertBitIntoBytes(&dheader_bits[4], 4); //data packet format + uint8_t sap = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 4); //service access point + uint8_t poc = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 4); //padding octets + + uint32_t target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[16], 24); //destination llid + uint32_t source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[40], 24); //source llid + + //store source for dmr pdu packet handling (lrrp) when not available in completed message + if (dpf != 15) state->dmr_lrrp_source[slot] = source; + + //set dpf to storage for later use (UDT, SD, etc) + state->data_header_format[slot] = dpf; + + //Type Strings + char sap_string[20]; + char mfid_string[20]; + char udtf_string[20]; + char sddd_string[20]; + sprintf (sap_string, "%s", ""); + sprintf (mfid_string, "%s", ""); + sprintf (udtf_string, "%s", ""); + sprintf (sddd_string, "%s", ""); + + //see 9.3 - ETSI TS 102 361-1 V2.5.1 (2017-10) for more info + uint8_t f = dheader_bits[64]; //F -- Full message flag (F) + uint8_t bf = (uint8_t)ConvertBitIntoBytes(&dheader_bits[65], 7); //Blocks to Follow (BF) + + //confirmed data header + uint8_t s = dheader_bits[72]; //S -- Re-Synchronize Flag + uint8_t ns = (uint8_t)ConvertBitIntoBytes(&dheader_bits[73], 3); //N(S) -- send sequence number + uint8_t fsn = (uint8_t)ConvertBitIntoBytes(&dheader_bits[76], 4); //Fragment Sequence Number (FSN) + + //response header + uint8_t r_class = (uint8_t)ConvertBitIntoBytes(&dheader_bits[72], 2); + uint8_t r_type = (uint8_t)ConvertBitIntoBytes(&dheader_bits[74], 3); + uint8_t r_status = (uint8_t)ConvertBitIntoBytes(&dheader_bits[77], 3); + + //short data - status/precoded + uint8_t s_ab_msb = (uint8_t)ConvertBitIntoBytes(&dheader_bits[2], 2); //appended block, msb + uint8_t s_ab_lsb = (uint8_t)ConvertBitIntoBytes(&dheader_bits[12], 4);//appended block, lsb + uint8_t s_ab_fin = (s_ab_msb << 2) | s_ab_lsb; //appended blocks, final value + uint8_t s_source_port = (uint8_t)ConvertBitIntoBytes(&dheader_bits[64], 3); + uint8_t s_dest_port = (uint8_t)ConvertBitIntoBytes(&dheader_bits[67], 3); + uint8_t s_status_precoded = (uint8_t)ConvertBitIntoBytes(&dheader_bits[70], 10); + + //short data - raw + uint8_t sd_sarq = dheader_bits[70]; //Selective Automatic Repeat reQuest + uint8_t sd_f = dheader_bits[71]; //full message flag + uint8_t sd_bp = (uint8_t)ConvertBitIntoBytes(&dheader_bits[72], 8); //bit padding + + //short data - defined + uint8_t dd_format = (uint8_t)ConvertBitIntoBytes(&dheader_bits[64], 6); + + //Unified Data Transport (UDT) + uint8_t udt_format = (uint8_t)ConvertBitIntoBytes(&dheader_bits[12], 4); + uint8_t udt_padnib = (uint8_t)ConvertBitIntoBytes(&dheader_bits[64], 5); + uint8_t udt_uab = (uint8_t)ConvertBitIntoBytes(&dheader_bits[70], 2); //udt appended blocks + uint8_t udt_sf = dheader_bits[72]; + uint8_t udt_pf = dheader_bits[73]; + uint8_t udt_op = (uint8_t)ConvertBitIntoBytes(&dheader_bits[74], 6); + + //p_head + uint8_t p_sap = (uint8_t)ConvertBitIntoBytes(&dheader_bits[0], 4); + uint8_t p_mfid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8); + uint8_t p_pot = (uint8_t)ConvertBitIntoBytes(&dheader_bits[3], 5); //looking for LRRP pot_report + 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; + fprintf (stderr, "\n"); + fprintf (stderr, " Slot %d Data Header - ", slot+1); - if ( (state->data_header_format[slot] & 0xF) == 0x2) + if (gi == 1 && dpf != 15) fprintf(stderr, "GROUP - "); + if (gi == 0 && dpf != 15) fprintf(stderr, "INDIV - "); + + if (dpf == 0) fprintf (stderr, "Unified Data Transport (UDT) "); + else if (dpf == 1) fprintf (stderr, "Response Packet "); + else if (dpf == 2) fprintf (stderr, "Unconfirmed Delivery "); + else if (dpf == 3) fprintf (stderr, "Confirmed Delivery "); + else if (dpf == 13) fprintf (stderr, "Short Data: Defined "); + else if (dpf == 14) fprintf (stderr, "Short Data: Raw or S/P "); + else if (dpf == 15) fprintf (stderr, "Proprietary Packet Data"); + else fprintf (stderr, "Reserved/Unknown DPF %X ", dpf); + + if (a == 1 && dpf != 15) fprintf(stderr, "- Response Requested "); + if (dpf != 15) fprintf (stderr, "- Source: %d Target: %d ", source, target); + + //sap string handling + if (dpf == 15) sap = p_sap; + + if (sap == 0) sprintf (sap_string, "%s", "UDT Data"); //apparently, both dpf and sap for UDT is 0 + else if (sap == 2) sprintf (sap_string, "%s", "TCP Comp"); //TCP/IP header compression + else if (sap == 3) sprintf (sap_string, "%s", "UDP Comp"); //UDP/IP header compression + else if (sap == 4) sprintf (sap_string, "%s", "IP Based"); //IP based Packet Data + else if (sap == 5) sprintf (sap_string, "%s", "ARP Prot"); //Address Resoution Protocol (ARP) + else if (sap == 9) sprintf (sap_string, "%s", "Prop PDU"); //Proprietary Packet Data + else if (sap == 10) sprintf (sap_string, "%s", "Short DT"); //Short Data + else sprintf (sap_string, "%s", "Reserved"); //reserved, or err/unk + + //mfid string handling + if (dpf == 15) { - 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 (p_mfid == 0x10) sprintf (mfid_string, "%s", "Motorola"); + else if (p_mfid == 0x58) sprintf (mfid_string, "%s", "Tait "); + else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera "); + else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera "); + else if (p_mfid == 0x06) sprintf (mfid_string, "%s", "Trid/Mot"); + else if (p_mfid == 0x00) sprintf (mfid_string, "%s", "Standard"); + else sprintf (mfid_string, "%s", "Other "); } - if ( (state->data_header_format[slot] & 0xF) == 0x3) + //udt format string handling + if (dpf == 0) { - 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 (udt_format == 0x00) sprintf (udtf_string, "%s", "Binary"); + else if (udt_format == 0x01) sprintf (udtf_string, "%s", "MS/TG Adr"); + else if (udt_format == 0x02) sprintf (udtf_string, "%s", "4-bit BCD"); + else if (udt_format == 0x03) sprintf (udtf_string, "%s", "ISO7 Char"); + else if (udt_format == 0x04) sprintf (udtf_string, "%s", "ISO8 Char"); + else if (udt_format == 0x05) sprintf (udtf_string, "%s", "NMEA LOCN"); + else if (udt_format == 0x06) sprintf (udtf_string, "%s", "IP Addr"); + else if (udt_format == 0x07) sprintf (udtf_string, "%s", "UTF-16"); //16-bit Unicode Chars + else if (udt_format == 0x08) sprintf (udtf_string, "%s", "Manu Spec"); //Manufacturer Specific + else if (udt_format == 0x09) sprintf (udtf_string, "%s", "Manu Spec"); //Manufacturer Specific + else if (udt_format == 0x0A) sprintf (udtf_string, "%s", "Mixed UTF"); //Appended block contains addr and 16-bit UTF-16BE + else sprintf (udtf_string, "%s", "Reserved"); } - if ( (state->data_header_format[slot] & 0xF) == 0xD) //DD_HEAD + //short data dd_head format string + if (dpf == 13) { - //The Response Requested (A) information element of the header shall be set to 0 for unconfirmed data and shall be set - //to 1 for confirmed data. ETSI TS 102 361-3 V1.2.1 (2013-07) - 6.1.2 - if ( (state->data_header_format[slot] & 0x40) == 0x40 && state->data_p_head[slot] == 0) //check response req bit + if (dd_format == 0x00) sprintf (sddd_string, "%s", "Binary"); + else if (dd_format == 0x01) sprintf (sddd_string, "%s", "BCD "); + else if (dd_format == 0x02) sprintf (sddd_string, "%s", "7-bit Char"); + else if (dd_format == 0x03) sprintf (sddd_string, "%s", "IEC 8859-1"); + else if (dd_format == 0x04) sprintf (sddd_string, "%s", "IEC 8859-2"); + else if (dd_format == 0x05) sprintf (sddd_string, "%s", "IEC 8859-3"); + else if (dd_format == 0x06) sprintf (sddd_string, "%s", "IEC 8859-4"); + else if (dd_format == 0x07) sprintf (sddd_string, "%s", "IEC 8859-5"); + else if (dd_format == 0x08) sprintf (sddd_string, "%s", "IEC 8859-6"); + else if (dd_format == 0x09) sprintf (sddd_string, "%s", "IEC 8859-7"); + else if (dd_format == 0x0A) sprintf (sddd_string, "%s", "IEC 8859-8"); + else if (dd_format == 0x0B) sprintf (sddd_string, "%s", "IEC 8859-9"); + else if (dd_format == 0x0C) sprintf (sddd_string, "%s", "IEC 8859-10"); + else if (dd_format == 0x0D) sprintf (sddd_string, "%s", "IEC 8859-11"); + else if (dd_format == 0x0E) sprintf (sddd_string, "%s", "IEC 8859-13"); //there is no 8059-12 + else if (dd_format == 0x0F) sprintf (sddd_string, "%s", "IEC 8859-14"); + else if (dd_format == 0x10) sprintf (sddd_string, "%s", "IEC 8859-15"); + else if (dd_format == 0x11) sprintf (sddd_string, "%s", "IEC 8859-16"); + else if (dd_format == 0x12) sprintf (sddd_string, "%s", "UTF-8 "); + else if (dd_format == 0x13) sprintf (sddd_string, "%s", "UTF-16 "); + else if (dd_format == 0x14) sprintf (sddd_string, "%s", "UTF-16BE"); + else if (dd_format == 0x15) sprintf (sddd_string, "%s", "UTF-16LE"); + else if (dd_format == 0x16) sprintf (sddd_string, "%s", "UTF-32 "); + else if (dd_format == 0x17) sprintf (sddd_string, "%s", "UTF-32BE"); + else if (dd_format == 0x18) sprintf (sddd_string, "%s", "UTF-32LE"); + else sprintf (sddd_string, "%s", "Reserved"); + } + + if (dpf == 0) //UDT + { + //UDT packet info -- samples needed for testing + //NOTE: This format's completed message has a CRC16 - like MBC - but has number of blocks (appended blocks) like R 1/2, etc. + fprintf (stderr, "\n SAP %02X [%s] - FMT %d [%s] - PDn %d - BLOCKS %d SF %d - PF %d OP %02X", sap, sap_string, udt_format, udtf_string, udt_padnib, udt_uab, udt_sf, udt_pf, udt_op); + + //set number of blocks to follow (appended blocks) for block assembler + state->data_header_blocks[slot] = udt_uab; + + //set data header to valid + state->data_header_valid[slot] = 1; + + //send to assembler as type 3, rearrange into CSBK type PDU (to verify), and send to dmr_cspdu + dmr_block_assembler (opts, state, dheader, 12, 0x0B, 3); + + } + + if (dpf == 1) //response data packet header + { + //mostly fleshed out response packet info + fprintf (stderr, "\n SAP %02X [%s] - Class %d - Type %0d - ", sap, sap_string, r_class, r_type); + if (r_class == 0 && r_type == 1) fprintf (stderr, "ACK - Success"); + if (r_class == 1) { - state->data_conf_data[slot] = 1; + fprintf (stderr, "NACK - "); + if (r_type == 0) fprintf (stderr, "Illegal Format"); + if (r_type == 1) fprintf (stderr, "Illegal Format"); + if (r_type == 2) fprintf (stderr, "Packet CRC ERR"); + if (r_type == 3) fprintf (stderr, "Memory Full"); + if (r_type == 4) fprintf (stderr, "FSN Out of Seq"); + if (r_type == 5) fprintf (stderr, "Undeliverable"); + if (r_type == 6) fprintf (stderr, "PKT Out of Seq"); + if (r_type == 7) fprintf (stderr, "Invalid User"); } - else state->data_conf_data[slot] = 0; + if (r_class == 2) fprintf (stderr, "SACK - Retry"); + if (r_status) fprintf (stderr, " - %d", r_status); //the object/value of the ack/nack/sack - 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 + //Confirmed or Unconfirmed Data Packets Header + if (dpf == 2 || dpf == 3) { - //The Response Requested (A) information element of the header shall be set to 0 for unconfirmed data and shall be set - //to 1 for confirmed data. ETSI TS 102 361-3 V1.2.1 (2013-07) - 6.2.2 - if ( (state->data_header_format[slot] & 0x40) == 0x40 && state->data_p_head[slot] == 0) //check response req bit + if (dpf == 2) fprintf (stderr, "\n SAP %02X [%s] - FMF %d - BLOCKS %02d - PAD %02d - FSN %d", sap, sap_string, f, bf, poc, fsn); + if (dpf == 3) fprintf (stderr, "\n SAP %02X [%s] - FMF %d - BLOCKS %02d - PAD %02d - S %d - NS %d - FSN %d", sap, sap_string, f, bf, poc, s, ns, fsn); + state->data_header_blocks[slot] = bf; + if (dpf == 3) state->data_conf_data[slot] = 1; //set confirmed data delivery flag for additional CRC checks, block assembly, etc. + + } + + //Short Data DD_Head (13), and R_Head or SP_Head (14) + if (dpf == 13 || dpf == 14) + { + //only set if not all zeroes + if (s_ab_fin) state->data_header_blocks[slot] = s_ab_fin; + + //Short Data: Defined + if (dpf == 13) fprintf (stderr, "\n SD:D [DD_HEAD] - SAP %02d [%s] - BLOCKS %02d - DD %02X - PADb %d - FMT %02X [%s]", sap, sap_string, s_ab_fin, dd_format, sd_bp, dd_format, sddd_string); + //Short Data: Raw or S/P + if (dpf == 14) { - state->data_conf_data[slot] = 1; + //S/P has all appended block bits set to zero -- any other way to tell difference? + if (s_ab_fin == 0) fprintf (stderr, "\n SD:S/P [SP_HEAD] - SAP %02d [%s] - SP %02d - DP %02d - S/P %02X", sap, sap_string, s_source_port, s_dest_port, s_status_precoded); + + //Raw + else fprintf (stderr, "\n SD:RAW [R_HEAD] - SAP %02d [%s] - BLOCKS %02d - SP %02d - DP %02d - SARQ %d - FMF %d - PDb %d", sap, sap_string, s_ab_fin, s_source_port, s_dest_port, sd_sarq, sd_f, sd_bp); } - else 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] ); + //6.2.2 The Response Requested (A) information element of the header shall be set to 0 + //for unconfirmed data and shall be set to 1 for confirmed data. DD_HEAD, R_HEAD, or SP_HEAD (double check) + if (a == 1) + { + state->data_conf_data[slot] = 1; + fprintf (stderr, " - Confirmed Data"); + } + } - - - } - - //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 ", KYEL); - - 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] ); - - state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]; - - //Remus! Uncomment these line - // if ( (state->data_header_format[slot] & 0xF ) != 0x1 && state->data_p_head[slot] == 0) - // sprintf (state->dmr_lrrp_gps[slot], "IP DATA SRC [%d] DST [%d] ", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7], (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]); - - } - - 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] ); - - state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]; - - //Remus! Uncomment these line - // if ( (state->data_header_format[slot] & 0xF ) != 0x1 && state->data_p_head[slot] == 0) - // sprintf (state->dmr_lrrp_gps[slot], "UDT SRC [%d] DST [%d] ", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7], (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]); - - } - - 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] ); - - state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]; - - //Remus! Uncomment this line - // sprintf (state->dmr_lrrp_gps[slot], "P_HEAD SRC [%d] DST [%d] ", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7], (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]); - - } - - 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]); - - state->dmr_lrrp_source[slot] = dheader[3]; - - //Remus! Uncomment these line - // if ( (state->data_header_format[slot] & 0xF ) != 0x1 && state->data_p_head[slot] == 0) - // sprintf (state->dmr_lrrp_gps[slot], "IPC SRC [%d] DST [%d] ", dheader[3], dheader[2]); - - } - - 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]); - - state->dmr_lrrp_source[slot] = dheader[3]; - - //Remus! Uncomment these line - // if ( (state->data_header_format[slot] & 0xF ) != 0x1 && state->data_p_head[slot] == 0) - // sprintf (state->dmr_lrrp_gps[slot], "UDP SRC [%d] DST [%d] ", dheader[3], dheader[2]); - - } - - 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] ); - - //Remus! Uncomment this line - // sprintf (state->dmr_lrrp_gps[slot], "SD-D SRC [%d] DST [%d] ", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7], (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] ); - - //Remus! Uncomment this line - // sprintf (state->dmr_lrrp_gps[slot], "SD-R/P SRC [%d] DST [%d] ", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7], (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] ); - - //Remus! Uncomment these lines - // char rsp[90]; - // sprintf (rsp, " - RSP SRC [%d] DST [%d] ", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7], (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]); - // strcat (state->dmr_lrrp_gps[slot], rsp); - - } - - //Removed Dup UDT Message - - 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] ); - - //Remus! Uncomment these lines - // char rsp[90]; - // sprintf (rsp, "- RSP REQ "); - // strcat (state->dmr_lrrp_gps[slot], rsp); - - } - - //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; //disabling this, we can flag it off after processing pdu instead - 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]; //diable, will only set in link control or csbk for now (random manufacturers getting set, bad decode? or random feature?) - - //assign prop header pdu to 'superframe' - uint8_t blocks = state->data_header_blocks[slot] - 1; - for(i = 0; i < 12; i++) + + //Proprietary Data Header + if (dpf == 15) { - state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i]; + fprintf (stderr, " - P_SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string); + + //look for LRRP potential report 0x1F (may be others as well) + //this could just be a sap == 1, which is 'reserved', unsure (or maybe no actual correlation?) + if (p_sap != 1) state->data_header_blocks[slot]--; //decrement the blocks to follow count in order to pass CRC32 and properly assemble blocks + else //add block to start of the dmr_pdu_sf since it probably contains vital LRRP data (0x1F report) -- won't pass CRC32 either way + { + int blocks = state->data_header_blocks[slot]-1; + if (blocks < 1) blocks = 4; //safety value + if (blocks > 9) blocks = 9; + for(i = 0; i < 12; i++) state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i]; + state->data_block_counter[slot]++; + //no matter how you assemble this, with or without the p_head block(s), there is ALWAYS a CRC32 Failure + //even when it continues to pass on other SAP values, SAP 1 must have a different checksum? + //Users trying to get this will want to enable -F to bypass the CRC32 failure + + //a recent discovery on a few systems and samples show the existence of multiple Prop Head Packets (how does that work) + } + } - } - //only set this flag after everything else is processed - if (state->data_header_sap[slot] == 0x9 && state->data_p_head[slot] == 0) + //block storage sanity + if (state->data_header_blocks[slot] > 9) state->data_header_blocks[slot] = 9; + //assuming we didn't receive the initial data header block on a p_head and then decremented it + //3 or 4 seems to be the average safe value + if (state->data_header_blocks[slot] < 1) state->data_header_blocks[slot] = 4; + //set data header validity unless its a p_head (should be set prior, if received) + if (dpf != 15) state->data_header_valid[slot] = 1; + + //REMUS! Uncomment these lines if desired + if (dpf != 15 && dpf != 1) + { + sprintf (state->dmr_lrrp_gps[slot], "Data Call - %s SRC [%d] DST [%d] ", sap_string, source, target); + if (a == 1) strcat (state->dmr_lrrp_gps[slot], "- RSP REQ "); + } + + //REMUS! Uncomment these lines if desired -- if the data request data header is missing, though, this may keep accumulating + // if (dpf == 1) + // { + // strcat (state->dmr_lrrp_gps[slot], "- RSP "); + // if (r_class == 0) strcat (state->dmr_lrrp_gps[slot], "ACK - RX OK"); + // if (r_class == 1) strcat (state->dmr_lrrp_gps[slot], "NACK - RX ERR"); + // if (r_class == 2) strcat (state->dmr_lrrp_gps[slot], "SACK - RETRY"); + + // } + //End REMUS Data string + + //store SAP value + state->data_header_sap[slot] = sap; + + } //End Irrecoverable Errors + + if (IrrecoverableErrors != 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 + state->data_header_valid[slot] = 0; + sprintf (state->dmr_lrrp_gps[slot], "%s", ""); + state->data_p_head[slot] = 0; + state->data_conf_data[slot] = 0; + state->data_block_counter[slot] = 1; + state->data_header_blocks[slot] = 1; + } - 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); + fprintf (stderr, "%s", KNRM); } +//convert UDT to a CSBK friendly PDU format +void dmr_udt_cspdu_converter (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors) +{ + int i, j; + + //rearrange UDT data to a CSBK message format + uint8_t cs_byte[48]; //12 x 4, 2 bit AB should mean only 3 total appended blocks, so 4 all together (minus rearrangement) + memset (cs_byte, 0, sizeof (cs_byte)); + uint8_t cs_bits[48*8]; + memset (cs_bits, 0, sizeof (cs_bits)); + + cs_byte[0] = (uint8_t)ConvertBitIntoBytes(&block_bits[73], 7); //lb, pf and opcode byte + uint8_t udt_opcode = (uint8_t)ConvertBitIntoBytes(&block_bits[74], 6); //for observation testing + cs_byte[1] = 0; //set mfid to zero for now (may use custom value if needed later) + uint8_t udt_mfid = 0; //setting to zero + + //should be 34 total (maximum) after removing tailing CRC16 (initial and last block) + for (i = 0; i < 34; i++) cs_byte[2+i] = block_bytes[12+i]; + + //bytes to bits + for(i = 0, j = 0; i < 36; i++, j+=8) //4 blocks max? + { + cs_bits[j + 0] = (cs_byte[i] >> 7) & 0x01; + cs_bits[j + 1] = (cs_byte[i] >> 6) & 0x01; + cs_bits[j + 2] = (cs_byte[i] >> 5) & 0x01; + cs_bits[j + 3] = (cs_byte[i] >> 4) & 0x01; + cs_bits[j + 4] = (cs_byte[i] >> 3) & 0x01; + cs_bits[j + 5] = (cs_byte[i] >> 2) & 0x01; + cs_bits[j + 6] = (cs_byte[i] >> 1) & 0x01; + cs_bits[j + 7] = (cs_byte[i] >> 0) & 0x01; + } + + dmr_cspdu (opts, state, cs_bits, cs_byte, CRCCorrect, IrrecoverableErrors); + +} + //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]; uint8_t block_num = state->data_header_blocks[slot]; - //crc specific variables - // uint8_t len = 24; - // 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; @@ -302,20 +393,27 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte if (type == 1) blocks = state->data_header_blocks[slot] - 1; if (type == 2) blocks = state->data_block_counter[slot]; + //UDT Header and Block Check + uint8_t is_udt = 0; + if (type == 3) + { + blocks = state->data_block_counter[slot]; + is_udt = 1; + type = 2; + } + //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 (blocks > 9) blocks = 9; if (block_len == 0) block_len = 18; if (block_len > 24) block_len = 24; - //WIP: CRC32 on Completed Message Working! CRC9 on 3/4 Working! CRC9 or 1/2 and 1 still need testing - type 1 - //may/will still fail on p_head data and blocks if (type == 1) { //type 1 data block, shuffle method - for (j = 0; j < blocks; j++) //6 + for (j = 0; j < blocks; j++) { - for (i = 0; i < block_len; i++) //block_len + for (i = 0; i < block_len; i++) { state->dmr_pdu_sf[slot][i+block_len*j] = state->dmr_pdu_sf[slot][i+block_len*(j+1)]; } @@ -325,8 +423,9 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte { 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]) + if (state->data_block_counter[slot] == state->data_header_blocks[slot] && state->data_header_valid[slot] == 1) { //CRC32 on completed messages for(i = 0, j = 0; i < (block_num * block_len); i++, j+=8) @@ -388,28 +487,77 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte //individual CRC9s are correct on confirmed data blocks (but we can confirm now that they are all good) if (CRCComputed == CRCExtracted) CRCCorrect = 1; - //test only running on good CRC or CRC/RAS bypass (aggressive_framesync) - if (CRCCorrect || opts->aggressive_framesync == 0) dmr_pdu (opts, state, block_len, state->dmr_pdu_sf[slot]); + //only run on good CRC or CRC/RAS bypass (aggressive_framesync == 0) + if (CRCCorrect || opts->aggressive_framesync == 0) + dmr_pdu (opts, state, block_len, state->dmr_pdu_sf[slot]); if (CRCCorrect) ; //print nothing else { fprintf (stderr, "%s", KRED); fprintf (stderr, "\n Slot %d - Multi Block PDU Message CRC32 ERR", slot+1); + + //debug print + // fprintf (stderr, " %X - %X", CRCExtracted, CRCComputed); + fprintf (stderr, "%s", KNRM); - state->data_conf_data[slot] = 0; //flag off conf data flag - state->data_header_format[slot] = 0; //zero out so we don't keep ascii printing - } - } - } + } + + //Full Super Frame Type 1 - Payload Output + if (opts->payload == 1) + { + fprintf (stderr, "%s", KGRN); + fprintf (stderr, "\n Slot %d - Multi Block PDU Message\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 "); + } + } + + //debug print + // fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed); + + if (state->data_header_format[slot] == 13 || state->data_header_format[slot] == 14 || state->data_header_sap[slot] == 10) + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "\n Short Data: ASCII \n" ); + for (i = 0; i < ((blocks+1)*block_len); i++) + { + if (state->dmr_pdu_sf[slot][i] <= 0x7E && state->dmr_pdu_sf[slot][i] >=0x20) + { + fprintf (stderr, "%c", state->dmr_pdu_sf[slot][i]); + } + else fprintf (stderr, " "); + + if (i == 47 || i == 95) fprintf (stderr, "\n "); + } + + } + + fprintf (stderr, "%s ", KNRM); + } + + //reset data header format storage + state->data_header_format[slot] = 7; + //flag off data header validity + state->data_header_valid[slot] = 0; + //flag off conf data flag + state->data_conf_data[slot] = 0; + + } //end completed sf + + } //end type 1 blocks - //type 2 - MBC header and MBC continuation blocks + //type 2 - MBC and UDT header, MBC and UDT 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; + //sanity check (marginal signal, bad decodes, etc) -- may go a little lower (find out max number of MBC blocks supported) + if (state->data_block_counter[slot] > 4) state->data_block_counter[slot] = 4; //Type 2 data block, additive method for (i = 0; i < block_len; i++) @@ -422,9 +570,17 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte 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 + if (is_udt) { - for(i = 0, j = 0; i < 12*4; i++, j+=8) // + blocks = state->data_header_blocks[slot]; + if (blocks == blockcounter) lb = 1; //double check + pf = 0; //flag off is set from bit in error + } + + //last block arrived and we have a valid data header, time to send to cspdu decoder + if (lb == 1 && state->data_header_valid[slot] == 1) + { + for(i = 0, j = 0; i < 12*4; i++, j+=8) //4 blocks max? { 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; @@ -436,10 +592,13 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte dmr_pdu_sf_bits[j + 7] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01; } + //check UDT PF + if (is_udt) pf = dmr_pdu_sf_bits[73]; + //CRC check on Header and full frames as appropriate (header crc already stored) //The 16 bit CRC in the header shall include the data carried by the header. //The 16 bit CRC in the last block shall be performed on - //all MBC blocks (conmbined) except the header block. <-- misleading statement, just like half the dmr manual + //all MBC blocks (conmbined) except the header block. mbc_crc_good[0] = state->data_block_crc_valid[slot][0]; @@ -454,15 +613,13 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte uint8_t mbc_block_bits[12*8*3]; memset (mbc_block_bits, 0, sizeof(mbc_block_bits)); //shift continuation blocks and last block into seperate array for crc check - for (i = 0; i < 12*8*3; i++) + for (i = 0; i < 12*8*3; i++) //only doing 3 blocks (4 minus the header) { mbc_block_bits[i] = dmr_pdu_sf_bits[i+96]; //skip mbc header } CRCComputed = ComputeCrcCCITT16d (mbc_block_bits, ((blocks+0)*96)-16 ); - // fprintf (stderr, " \n CRC EXT %X CRC CMP %X", CRCExtracted, CRCComputed); - if (CRCComputed == CRCExtracted) mbc_crc_good[1] = 1; CRCCorrect = 0; @@ -477,60 +634,51 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte else { fprintf (stderr, "%s", KRED); - fprintf(stderr, " (CRC ERR)"); + fprintf (stderr, "\n Slot %d - Multi Block Control Message CRC16 ERR", slot+1); + + //debug print + fprintf (stderr, " %X - %X", CRCExtracted, CRCComputed); + fprintf (stderr, "%s", KNRM); } //cspdu will only act on any fid/opcodes if good CRC to prevent falsing on control signalling - dmr_cspdu (opts, state, dmr_pdu_sf_bits, state->dmr_pdu_sf[slot], CRCCorrect, IrrecoverableErrors); + if (!is_udt && !pf) dmr_cspdu (opts, state, dmr_pdu_sf_bits, state->dmr_pdu_sf[slot], CRCCorrect, IrrecoverableErrors); - } - } + //will need to reassemble partially before sending to dmr_pdu or dmr_cspdu for handling -- needs testing + if (is_udt && !pf) dmr_udt_cspdu_converter (opts, state, state->dmr_pdu_sf[slot], dmr_pdu_sf_bits, 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 Slot %d - Multi Block PDU Message\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) + //Full Super Frame MBC/UDT - Debug Output + if (opts->payload == 1) { - fprintf (stderr, "\n "); + fprintf (stderr, "%s", KGRN); + fprintf (stderr, "\n Slot %d - Multi Block Control Message\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", KRED); + if (mbc_crc_good[0] == 0) fprintf (stderr, "MBC/UDT Header CRC ERR "); + if (mbc_crc_good[1] == 0) fprintf (stderr, "MBC/UDT Blocks CRC ERR "); + if (pf) fprintf (stderr, "MBC/UDT Header/Blocks Protected "); + fprintf (stderr, "%s ", KNRM); } - } - //debug print - // fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed); + } //end last block flag on MBC - fprintf (stderr, "%s ", KNRM); - } + } //end type 2 (MBC Header and Continuation) - //Full Super Frame MBC - Debug Output - if (opts->payload == 1 && type == 2 && lb == 1) + //leave this seperate so we can reset/zero stuff in case the data header isn't valid, etc + //switched to an if-elseif-else so we could get the block counter increment on the end + //without having it in an akward position + + //if the end of normal data header and blocks + if (type == 1 && state->data_block_counter[slot] == state->data_header_blocks[slot]) { - fprintf (stderr, "%s", KGRN); - fprintf (stderr, "\n Slot %d - Multi Block Control Message\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", KRED); - if (mbc_crc_good[0] == 0) fprintf (stderr, "MBC Header CRC ERR "); - if (mbc_crc_good[1] == 0) fprintf (stderr, "MBC Blocks CRC ERR "); - 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++) @@ -538,23 +686,65 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte state->dmr_pdu_sf[slot][i] = 0; } - state->data_block_crc_valid[slot][0] = 0; //Zero Out MBC Header Block CRC Valid + //Zero Out MBC Header Block CRC Valid + state->data_block_crc_valid[slot][0] = 0; + //reset the block counter (data blocks) + state->data_block_counter[slot] = 1; + //reset data header format storage + state->data_header_format[slot] = 7; + //flag off data header validity + state->data_header_valid[slot] = 0; + //flag off conf data flag + state->data_conf_data[slot] = 0; } + //else if the end of MBC Header and Blocks + else if (type == 2 && lb == 1) + { + + //clear out unified pdu 'superframe' slot + for (short int i = 0; i < 288; i++) + { + state->dmr_pdu_sf[slot][i] = 0; + } + + //Zero Out MBC Header Block CRC Valid + state->data_block_crc_valid[slot][0] = 0; + //reset the block counter (data blocks) + state->data_block_counter[slot] = 1; + //reset data header format storage + state->data_header_format[slot] = 7; + //flag off data header validity + state->data_header_valid[slot] = 0; + //flag off conf data flag + state->data_conf_data[slot] = 0; + + } + + //else increment block counter after sorting/shuffling blocks + else state->data_block_counter[slot]++; + } -//failsafe to clear old data header, block info, cach, in case of tact/emb/slottype failures and we -//can no longer verify accurate data block reporting +//failsafe to clear old data header, block info, cach, in case of tact/emb/slottype failures +//or tuning away and we can no longer verify accurate data block reporting void dmr_reset_blocks (dsd_opts * opts, dsd_state * state) { memset (state->data_p_head, 0, sizeof(state->data_p_head)); memset (state->data_conf_data, 0, sizeof(state->data_conf_data)); memset (state->dmr_pdu_sf, 0, sizeof(state->dmr_pdu_sf)); - memset (state->data_block_counter, 0, sizeof(state->data_block_counter)); - memset (state->data_header_blocks, 0, sizeof(state->data_header_blocks)); + memset (state->data_block_counter, 1, sizeof(state->data_block_counter)); + memset (state->data_header_blocks, 1, sizeof(state->data_header_blocks)); memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid)); memset (state->dmr_lrrp_source, 0, sizeof(state->dmr_lrrp_source)); memset (state->dmr_cach_fragment, 1, sizeof (state->dmr_cach_fragment)); memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits)); + memset (state->data_header_valid, 0, sizeof(state->data_header_valid)); + memset (state->data_header_format, 7, sizeof(state->data_header_format)); + //reset some strings + sprintf (state->call_string[0], "%s", " "); //21 spaces + sprintf (state->call_string[1], "%s", " "); //21 spaces + sprintf (state->dmr_lrrp_gps[0], "%s", ""); + sprintf (state->dmr_lrrp_gps[1], "%s", ""); } \ No newline at end of file diff --git a/src/dmr_dburst.c b/src/dmr_dburst.c index 8cb4aa0..1488dc7 100644 --- a/src/dmr_dburst.c +++ b/src/dmr_dburst.c @@ -9,9 +9,11 @@ * 2022-12 DSD-FME Florida Man Edition *-----------------------------------------------------------------------------*/ -//WIP: CRC9 on confirmed data blocks; CRC32 on completed data sf; -//WIP: Reverse Channel Signalling - RC single burst BPTC/7-bit CRC -//WIP: Single Burst Embedded LC - Non-RC single burst LC - Look for Late Entry Alg/Key +//WIP: Unified Single Block Data - USBD -- TODO: USBD LIP Protocol Handling +//WIP: UDT Header and Blocks (coded - need samples) +//WIP: CRC9/CRC32 on Rate 1 Data (need samples) +//WIP: Reverse Channel Signalling - RC single burst BPTC/7-bit CRC (rc interleave) and when to run RC and not SB +//WIP: Single Burst Embedded LC - Non-RC single burst LC - Look for Late Entry Alg/Key #include "dsd.h" @@ -43,9 +45,9 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 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 + //PDU Bytes and Bits + uint8_t DMR_PDU[25]; + uint8_t DMR_PDU_bits[196]; memset (DMR_PDU, 0, sizeof (DMR_PDU)); memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits)); @@ -61,9 +63,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 uint8_t is_trellis = 0; uint8_t is_emb = 0; uint8_t is_lc = 0; - uint8_t is_full = 0; + uint8_t is_full = 0; + uint8_t is_udt = 0; uint8_t pdu_len = 0; - uint8_t pdu_start = 0; //starting value of pdu (0 normal, 2 for confirmed) + uint8_t pdu_start = 0; //starting value of pdu (0 normal, 2 for confirmed) + + uint8_t usbd_st = 0; //usbd service type switch(databurst){ case 0x00: //PI @@ -127,7 +132,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 pdu_len = 10; pdu_start = 2; //start at plus two when assembling sprintf(state->fsubtype, " R12C "); - } + } + if (state->data_header_format[slot] == 0) //UDT 1/2 Encoded Blocks + { + is_udt = 1; + sprintf(state->fsubtype, " UDTC "); + } break; case 0x08: //3/4 Rate Data is_trellis = 1; @@ -159,12 +169,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 sprintf(state->fsubtype, " R_1C "); } break; - case 0x0B: //Unified Data + case 0x0B: //Unified Single Block Data USBD is_bptc = 1; crclen = 16; crcmask = 0x3333; pdu_len = 12; //12 bytes - sprintf(state->fsubtype, " UDAT "); + sprintf(state->fsubtype, " USBD "); break; //special types (not real data 'sync' bursts) @@ -202,7 +212,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 for (i = 0; i < 6; i++) //3 byte CACH { int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1]; - fprintf (pFile, "%X", cach_byte); + fprintf (pFile, "%X", cach_byte); //nibble, not a byte, next time I look at this and wonder why its not %02X } fprintf (pFile, "\n%d %02X ", slot+1, databurst); //use hex value of current data burst type for (i = 6; i < 72; i++) //33 bytes, no CACH @@ -233,7 +243,6 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 //debug print //fprintf (stderr, " RAS? %X - %d %d %d", BPTCReservedBits, R[0], R[1], R[2]); - /* Convert the 96 bits BPTC data into 12 bytes */ k = 0; for(i = 0; i < 12; i++) @@ -269,10 +278,6 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 CRCCorrect = 1; } - //set CRC to correct on proprietary data header blocks (unsure if p_head data has valid crcs, - //may be ras enabled, manufacturer specific, or none, currently unknown, but possibly RAS on samples I have) - // else if (state->data_p_head[slot] == 1 && databurst == 0x06) CRCCorrect = 1; - //run CRC9 on intermediate and last 1/2 confirmed data blocks else if (state->data_conf_data[slot] == 1 && databurst == 0x7) { @@ -297,7 +302,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 } //run CCITT on other data forms - else //will still run on unconfirmed data (shouldn't matter other than a possible bogus warning message) + else { CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit); if (CRCComputed == CRCExtracted) CRCCorrect = 1; @@ -305,12 +310,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 } //set the 'RAS Flag', if no irrecoverable errors but bad crc, only when enabled by user (to prevent a lot of bad data CSBKs) - if (opts->aggressive_framesync == 0 && CRCCorrect == 0 && IrrecoverableErrors == 0 && BPTCReservedBits == 4) is_ras = 1; //!=0, or == 0x4, or just R[2] == 1 + if (opts->aggressive_framesync == 0 && CRCCorrect == 0 && IrrecoverableErrors == 0 && BPTCReservedBits == 4) is_ras = 1; //make sure the system type isn't Hytera, but could just be bad decodes on bad sample if (BPTCDmrDataByte[1] == 0x68) is_ras = 0; - //if this is a RAS system, set the CRC to okay if irrecoverable errors is okay + //if this is a RAS system, set the CRC to okay if irrecoverable errors are okay //if we don't do this, then we can't view some data (CSBKs on RAS enabled systems) if (is_ras == 1) { @@ -340,7 +345,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 BPTCDmrDataBit[j + 7] = (BPTCDmrDataByte[i+pdu_start] >> 0) & 0x01; } - //convert to unified DMR_PDU and DMR_PDU_bits + //convert to DMR_PDU and DMR_PDU_bits for (i = 0; i < pdu_len; i++) { DMR_PDU[i] = BPTCDmrDataByte[i+pdu_start]; @@ -471,7 +476,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 } else { - IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix + // IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix state->data_block_crc_valid[slot][blockcounter] = 0; } @@ -548,14 +553,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 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 + //dmr data header and multi block types (header, 1/2, 3/4, 1, UDT) - type 1 + if (databurst == 0x06) dmr_dheader (opts, state, DMR_PDU, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors); 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 - - //my best understanding is that unified data carries supplimentary MS data on TIII systems, not control signalling - if (databurst == 0x0B) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Unified Data + if (databurst == 0x07 && is_udt == 0) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //1/2 Rate Data + if (databurst == 0x07 && is_udt == 1) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 3); //UDT with 1/2 Rate Encoding //control signalling types (CSBK, MBC) if (databurst == 0x03) dmr_cspdu (opts, state, DMR_PDU_bits, DMR_PDU, CRCCorrect, IrrecoverableErrors); @@ -564,25 +567,38 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 if (databurst == 0x04) { state->data_block_counter[slot] = 0; //zero block counter before running header + state->data_header_valid[slot] = 1; //set valid header since we received one 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); + //Unified Single Data Block (USBD) -- Not to be confused with Unified Data Transport (UDT) + if (databurst == 0x0B) + { + //TODO: provide more robust handling at a later date -- ETSI TS 102 361-4 V1.11.1 (2021-01) 6.6.11.3 + usbd_st = (uint8_t)ConvertBitIntoBytes(&DMR_PDU_bits[0], 4); + fprintf (stderr, "%s\n", KYEL); + fprintf (stderr, " Unified Single Block Data - "); + if (usbd_st == 0) fprintf (stderr, "Location Information Protocol"); + else if (usbd_st > 8) fprintf (stderr, "Manufacturer Specific Service %d ", usbd_st); + else fprintf (stderr, "Reserved %d ", usbd_st); + } + //set the original CRCCorrect back to its original value if the RAS flag was tripped if (is_ras == 1) CRCCorrect = crc_original_validity; //start printing relevant fec/crc/ras messages, don't print on idle or MBC continuation blocks (handled in dmr_block.c) - if (CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) ; //fprintf(stderr, "(CRC OK)"); + if (IrrecoverableErrors == 0 && CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) ; //fprintf(stderr, "(CRC OK)"); - if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05) - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, " (FEC OK)"); - fprintf (stderr, "%s", KNRM); + // if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05) + // { + // fprintf (stderr, "%s", KYEL); + // fprintf(stderr, " (FEC OK)"); + // fprintf (stderr, "%s", KNRM); - } + // } - if (IrrecoverableErrors != 0 && databurst != 0x09 && databurst != 0x05) + if (IrrecoverableErrors != 0 && databurst != 0x09) //&& databurst != 0x05 { fprintf (stderr, "%s", KRED); fprintf(stderr, " (FEC ERR)"); @@ -599,7 +615,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 fprintf (stderr, "%s", KNRM); } - if (CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05) + if (IrrecoverableErrors == 0 && CRCCorrect == 0 && is_ras == 0 && databurst != 0x09 && databurst != 0x05) { fprintf (stderr, "%s", KRED); fprintf (stderr, " (CRC ERR) "); @@ -622,25 +638,6 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 // fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed); fprintf (stderr, "%s", KNRM); - - //short data - DD_HEAD, SP_HEAD or R_HEAD (Might do on TMS as well) - if ( (state->data_header_format[slot] & 0xF) == 0xD ) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\n Hex to Ascii - "); - for (i = 0; i < pdu_len; 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/dsd_main.c b/src/dsd_main.c index 821756a..5c43c46 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -52,11 +52,10 @@ char * FM_banner[9] = { " ██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ ", " ██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗", " ╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝", - " 'Lite' Edition v2.0.0-30-ga4ecfdc Windows 32-bit RC3a " + " 'Lite' Edition v2.0.0-31-g3167f9d Windows 32-bit RC4 " }; -int -comp (const void *a, const void *b) +int comp (const void *a, const void *b) { if (*((const int *) a) == *((const int *) b)) return 0; @@ -255,12 +254,12 @@ noCarrier (dsd_opts * opts, dsd_state * state) state->data_header_blocks[1] = 1; //when trying to fill the superframe and 0-1 blocks give us an overflow state->data_header_padding[0] = 0; state->data_header_padding[1] = 0; - state->data_header_format[0] = 0; - state->data_header_format[1] = 0; + state->data_header_format[0] = 7; + state->data_header_format[1] = 7; state->data_header_sap[0] = 0; state->data_header_sap[1] = 0; - state->data_block_counter[0] = 0; - state->data_block_counter[1] = 0; + state->data_block_counter[0] = 1; + state->data_block_counter[1] = 1; state->data_p_head[0] = 0; state->data_p_head[1] = 0; @@ -303,7 +302,8 @@ noCarrier (dsd_opts * opts, dsd_state * state) //initialize unified dmr pdu 'superframe' memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf)); - + memset (state->data_header_valid, 0, sizeof(state->data_header_valid)); + //initialize cap+ bits and block num storage memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits)); state->cap_plus_block_num = 0; @@ -739,12 +739,12 @@ initState (dsd_state * state) state->data_header_blocks[1] = 1; //when trying to fill the superframe and 0-1 blocks give us an overflow state->data_header_padding[0] = 0; state->data_header_padding[1] = 0; - state->data_header_format[0] = 0; - state->data_header_format[1] = 0; + state->data_header_format[0] = 7; + state->data_header_format[1] = 7; state->data_header_sap[0] = 0; state->data_header_sap[1] = 0; - state->data_block_counter[0] = 0; - state->data_block_counter[1] = 0; + state->data_block_counter[0] = 1; + state->data_block_counter[1] = 1; state->data_p_head[0] = 0; state->data_p_head[1] = 0; @@ -836,6 +836,7 @@ initState (dsd_state * state) //initialize unified dmr pdu 'superframe' memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf)); + memset (state->data_header_valid, 0, sizeof(state->data_header_valid)); //initialize cap+ bits and block num storage memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits)); @@ -976,7 +977,7 @@ usage () //printf (" (4 Level, not 8 Level LSM) (this is honestly unknown since I can't verify what local systems are using)\n"); printf (" -F Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n"); printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n"); - printf (" -F Relax DMR CACH/Burst FEC or RAS/CRC CSBK Pass/Fail\n"); + printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n"); printf (" Enabling on some systems could lead to bad voice/data decoding if bad or marginal signal\n"); printf ("\n"); printf (" -K Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n"); @@ -1153,22 +1154,6 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) exit (0); } -// void -// sigfun (int sig) //not convinced this is truly required, maybe some environments require it? -// { -// exitflag = 1; -// #ifdef USE_RTLSDR -// // if (opts->audio_in_type == 3) -// //rtlsdr_sighandler(); -// #endif -// signal (SIGINT, SIG_DFL); -// ncursesClose (); - -// // #ifdef USE_RTLSDR -// // if (opts->audio_in_type == 3) rtlsdr_sighandler(); -// // #endif -// } - double atofs(char *s) { char last; @@ -1223,7 +1208,6 @@ main (int argc, char **argv) InitAllFecFunction(); exitflag = 0; - // signal (SIGINT, sigfun); while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:Y:K:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1) { @@ -1241,7 +1225,6 @@ main (int argc, char **argv) //make sure to put a colon : after each if they need an argument //or remove colon if no argument required - //Disabled the Serial Port Dev and Baud Rate, etc, If somebody uses that function, sorry... case 'k': //NXDN multi-key loader strncpy(opts.key_in_file, optarg, 1023); @@ -1354,41 +1337,6 @@ main (int argc, char **argv) if (opts.setmod_bw > 25000) opts.setmod_bw = 25000; //not too high break; - // case 'e': - // opts.errorbars = 1; - // opts.datascope = 0; - // break; - // case 'p': - // if (optarg[0] == 'e') - // { - // opts.p25enc = 1; - // } - // else if (optarg[0] == 'l') - // { - // opts.p25lc = 1; - // } - // else if (optarg[0] == 's') - // { - // opts.p25status = 1; - // } - // else if (optarg[0] == 't') - // { - // opts.p25tg = 1; - // } - // else if (optarg[0] == 'u') - // { - // opts.unmute_encrypted_p25 = 1; - // fprintf(stderr, "P25 Encrypted Audio Unmuted\n"); - // } - // break; - // case 'P': - // sscanf (optarg, "%d", &opts.rtlsdr_ppm_error); - // break; - // case 'q': - // opts.errorbars = 0; - // opts.verbose = 0; - // break; - case 's': sscanf (optarg, "%d", &opts.wav_sample_rate); opts.wav_interpolator = opts.wav_sample_rate / opts.wav_decimator; @@ -1396,12 +1344,6 @@ main (int argc, char **argv) state.symbolCenter = state.symbolCenter * opts.wav_interpolator; break; - // case 't': - // opts.symboltiming = 1; - // opts.errorbars = 1; - // opts.datascope = 0; - // break; - case 'v': sscanf (optarg, "%d", &opts.verbose); break; @@ -1480,30 +1422,6 @@ main (int argc, char **argv) } break; - // case 'G': //Set rtl device gain - // sscanf (optarg, "%d", &opts.rtl_gain_value); //multiple value by ten to make it consitent with the way rtl_fm really works - // break; - - // case 'L': //Set rtl squelch level - // sscanf (optarg, "%d", &opts.rtl_squelch_level); //set squelch by user to prevent false positives on NXDN and others - // break; - - // case 'V': //Set rtl voltage level - // sscanf (optarg, "%d", &opts.rtl_volume_multiplier); //set 'volume' multiplier for rtl-sdr samples - // break; - - // case 'U': //Set rtl udp remote port - // sscanf (optarg, "%d", &opts.rtl_udp_port); //set udp port number for RTL remote - // break; - - // case 'D': //Set rtl device index number - // sscanf (optarg, "%d", &opts.rtl_dev_index); - // break; - - // case 'Y': //Set rtl VFO bandwidth --recommend 6, 12, 24, 36, 48, default 48? or 12? - // sscanf (optarg, "%d", &opts.rtl_bandwidth); - // break; - case 'N': opts.use_ncurses_terminal = 1; fprintf (stderr,"Enabling NCurses Terminal.\n"); @@ -1543,22 +1461,10 @@ main (int argc, char **argv) fprintf (stderr, "%s", KYEL); //fprintf (stderr,"DMR Stereo Aggressive Resync Disabled!\n"); fprintf (stderr, "Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n"); - fprintf (stderr, "Relax DMR CACH/Burst FEC or RAS/CRC CSBK Pass/Fail\n"); + fprintf (stderr, "Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n"); fprintf (stderr, "%s", KNRM); break; - // case 'z': - // sscanf (optarg, "%d", &opts.scoperate); - // opts.errorbars = 0; - // opts.p25enc = 0; - // opts.p25lc = 0; - // opts.p25status = 0; - // opts.p25tg = 0; - // opts.datascope = 1; - // opts.symboltiming = 0; - // fprintf (stderr,"Setting datascope frame rate to %i frame per second.\n", opts.scoperate); - // break; - case 'i': strncpy(opts.audio_in_dev, optarg, 2047); opts.audio_in_dev[2047] = '\0'; @@ -1580,11 +1486,6 @@ main (int argc, char **argv) // fprintf (stderr,"Writing mbe data temporarily disabled!\n"); break; - // case 'c': - // opts.rtlsdr_center_freq = (uint32_t)atofs(optarg); - // fprintf (stderr,"Tuning to frequency: %i Hz\n", opts.rtlsdr_center_freq); - // break; - case 'c': //now is symbol capture bin output like FME Lite strncpy(opts.symbol_out_file, optarg, 1023); opts.symbol_out_file[1023] = '\0'; @@ -1623,15 +1524,6 @@ main (int argc, char **argv) openWavOutFile (&opts, &state); break; - // case 'B': - // sscanf (optarg, "%d", &opts.serial_baud); - // break; - - // case 'C': - // strncpy(opts.serial_dev, optarg, 1023); - // opts.serial_dev[1023] = '\0'; - // break; - case 'f': if (optarg[0] == 'a') { @@ -1930,30 +1822,9 @@ main (int argc, char **argv) state.dmr_stereo = 0; //0 opts.setmod_bw = 7000; sprintf (opts.output_name, "DMR Mono"); - //fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n"); + 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 '-fs' or XDMA '-ft' 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') { diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index fad6069..bb6ac8a 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -2061,7 +2061,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->ncurses_compact == 1) { printw ("------------------------------------------------------------------------------\n"); - printw ("| Digital Speech Decoder: Florida Man Edition - Win32 %s \n", "v2.0.0-30-ga4ecfdc RC3a"); + printw ("| Digital Speech Decoder: Florida Man Edition - Win32 %s \n", "v2.0.0-31-g3167f9d RC4"); } if (opts->ncurses_compact == 0) { @@ -2072,8 +2072,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (i == 1) printw (" ESC to Menu"); if (i == 2) printw (" 'q' to Quit "); if (i == 4) printw (" MBElib %s", versionstr); - if (i == 5) printw (" %s ", "Win32 RC3a"); //printw (" %s \n", GIT_TAG); - if (i == 6) printw (" %s \n", "v2.0.0-30-ga4ecfdc"); //printw (" %s \n", GIT_TAG); + if (i == 5) printw (" %s ", "Win32 RC4"); //printw (" %s \n", GIT_TAG); + if (i == 6) printw (" %s \n", "v2.0.0-31-g3167f9d"); //printw (" %s \n", GIT_TAG); else printw ("\n"); } attroff(COLOR_PAIR(6)); //6 @@ -2178,6 +2178,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { printw ("| Reverse Mute - Muting Unencrypted Voice\n"); } + if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n"); printw ("------------------------------------------------------------------------------\n"); attroff(COLOR_PAIR(4)); @@ -2372,8 +2373,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } else if (lls == 0 || lls == 1) //P1 { - // printw ("P25 P1 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc); - printw ("P25 P1 - [%05llX][%03llX][%03llX] RFSS: [%llX] SITE: [%llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); + printw ("P25 P1 - [%05llX][%03llX][%03llX] RFSS: [%lld] SITE: [%lld] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); if (state->p25_cc_freq != 0) { printw ("Freq: [%.06lf] MHz", (double)state->p25_cc_freq/1000000); @@ -2381,8 +2381,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } else if (lls == 35 || lls == 36) //P2 { - // printw ("P25 P2 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc); - printw ("P25 P2 - [%05llX][%03llX][%03llX] RFSS: [%llX] SITE: [%llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); + printw ("P25 P2 - [%05llX][%03llX][%03llX] RFSS: [%lld] SITE: [%lld] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0) { attron(COLOR_PAIR(2)); @@ -2494,7 +2493,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw("AES-128"); attron(COLOR_PAIR(3)); } - if (state->payload_algid == 0x84 || state->payload_algid == 0x25) + if (state->payload_algid == 0x84 || state->payload_algid == 0x25 || state->payload_algid == 0x05) { attron(COLOR_PAIR(1)); printw("AES-256"); @@ -2535,17 +2534,6 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(4)); - //Frequency Display - if (state->p25_vc_freq[0] != 0) - { - attron(COLOR_PAIR(5)); - printw ("Frequency: [%.06lf] MHz ", (double)state->p25_vc_freq[0]/1000000); - if (state->carrier == 1) - { - attron(COLOR_PAIR(3)); - } - } - if(state->dmrburstL == 16) //only during call { @@ -2571,7 +2559,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } //LRRP - if(state->dmrburstL != 16 && opts->p25_trunk == 0) //only during data and no trunking + if(state->dmrburstL != 16) //only during data and no trunking //&& opts->p25_trunk == 0 { attron(COLOR_PAIR(4)); printw ("%s", state->dmr_lrrp_gps[0]); @@ -2600,198 +2588,205 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw ("\n"); - //Slot 2 [1] - if (lls < 30 || lls == 35 || lls == 36){ //Don't print on MS mode - printw ("| SLOT 2 - "); - if (state->dmrburstR < 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) - { - attron(COLOR_PAIR(2)); - } - printw ("TGT: [%8i] SRC: [%8i] ", state->lasttgR, state->lastsrcR); - if (state->dmrburstR != 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) - { - attroff(COLOR_PAIR(2)); - attron(COLOR_PAIR(3)); - } - - //REMUS! THIS IS THE OLD ONE - // printw ("FID: [%02X] SVC: [%02X] ", state->dmr_fidR, state->dmr_soR); - //THIS IS THE NEW ONE - printw ("%s | ", state->call_string[1]); - printw ("%s ", DMRBusrtTypes[state->dmrburstR]); - if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && state->dmrburstR == 16 && state->dmrburstL == 16) printw ("*M*"); - printw ("\n"); - - printw ("| V XTRA | "); //10 spaces - - if(state->dmrburstR == 16 && state->payload_algidR == 0 && (state->dmr_soR & 0xCF) == 0x40) //4F or CF mask? - { - attron(COLOR_PAIR(5)); - printw (" **Pr** "); - attroff(COLOR_PAIR(5)); - attron(COLOR_PAIR(3)); - } - - if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->K > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x10) - { - attron(COLOR_PAIR(1)); - printw ("Pr Key [%3lld] ", state->K); - attroff(COLOR_PAIR(1)); - attron(COLOR_PAIR(3)); - } - if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->H > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x68) - { - attron(COLOR_PAIR(1)); - printw ("**tera Pr Key [%010llX] ", state->H); - attroff(COLOR_PAIR(1)); - attron(COLOR_PAIR(3)); - } - //ALG, KeyID, MI 2 //was keyidR - if(state->dmrburstR == 16 && state->payload_algidR > 0 && (state->dmr_soR & 0xCF) == 0x40) - { - attron(COLOR_PAIR(1)); - printw ("ALG: [0x%02X] KEY: [0x%02X] MI: [0x%08X] ", state->payload_algidR, state->payload_keyidR, state->payload_miR); - attroff(COLOR_PAIR(1)); - attron(COLOR_PAIR(3)); - } - //P25-P1 and P2 - if(state->dmrburstR > 19 && state->payload_algidR > 0 && state->payload_algidR != 0x80) - { - attron(COLOR_PAIR(1)); - printw ("ALG: [0x%02X] KEY: [0x%04X] MI: [0x%016llX] ", state->payload_algidR, state->payload_keyidR, state->payload_miN); - attroff(COLOR_PAIR(1)); - attron(COLOR_PAIR(3)); - } - if (state->payload_algidR == 0xAA || state->payload_algidR == 0x21) - { - attron(COLOR_PAIR(1)); - printw("ADP-RC4"); - attron(COLOR_PAIR(3)); - } - if (state->payload_algidR == 0x81 || state->payload_algidR == 0x22) - { - attron(COLOR_PAIR(1)); - printw("DES-OFB"); - attron(COLOR_PAIR(3)); - } - if (state->payload_algidR == 0x83 || state->payload_algidR == 0x23) - { - attron(COLOR_PAIR(1)); - printw("Triple DES"); - attron(COLOR_PAIR(3)); - } - if (state->payload_algidR == 0x85 || state->payload_algidR == 0x24) - { - attron(COLOR_PAIR(1)); - printw("AES-128"); - attron(COLOR_PAIR(3)); - } - if (state->payload_algidR == 0x84 || state->payload_algidR == 0x25) - { - attron(COLOR_PAIR(1)); - printw("AES-256"); - attron(COLOR_PAIR(3)); - } - if (state->payload_algidR == 0x02) - { - attron(COLOR_PAIR(1)); - printw("Hytera Full Encrypt"); - attron(COLOR_PAIR(3)); - } - //Call Types, may switch to the more robust version later? - if(state->dmrburstR == 16 && state->dmr_soR == 0x40 && state->R == 0) //0100 0000 - { - attron(COLOR_PAIR(2)); - printw (" **ENC** "); - attroff(COLOR_PAIR(2)); - attron(COLOR_PAIR(3)); - } - if(state->dmrburstR == 16 && state->dmr_soR == 0x80) - { - attron(COLOR_PAIR(2)); - printw (" **Emergency** "); - attroff(COLOR_PAIR(2)); - attron(COLOR_PAIR(3)); - } - if(state->dmrburstR == 16 && state->dmr_soR == 0x30) //0010 0000 - { - attron(COLOR_PAIR(2)); - printw (" **Private Call** "); - attroff(COLOR_PAIR(2)); - attron(COLOR_PAIR(3)); - } - printw ("\n"); - - //printw ("| | "); - printw ("| D XTRA | "); - - attron(COLOR_PAIR(4)); - - //Frequency Display - if (state->p25_vc_freq[1] != 0) - { - attron(COLOR_PAIR(5)); - printw ("Frequency: [%.06lf] MHz ", (double)state->p25_vc_freq[1]/1000000); - if (state->carrier == 1) + //Slot 2 [1] //Don't print on MS mode + if (lls < 30 || lls == 35 || lls == 36) + { + printw ("| SLOT 2 - "); + if (state->dmrburstR < 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) { + attron(COLOR_PAIR(2)); + } + printw ("TGT: [%8i] SRC: [%8i] ", state->lasttgR, state->lastsrcR); + if (state->dmrburstR != 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) + { + attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } - } - if(state->dmrburstR == 16) //only during call - { + //REMUS! THIS IS THE OLD ONE + // printw ("FID: [%02X] SVC: [%02X] ", state->dmr_fidR, state->dmr_soR); + //THIS IS THE NEW ONE + printw ("%s | ", state->call_string[1]); + printw ("%s ", DMRBusrtTypes[state->dmrburstR]); + if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && state->dmrburstR == 16 && state->dmrburstL == 16) printw ("*M*"); + printw ("\n"); - //Embedded GPS (not LRRP) - attron(COLOR_PAIR(4)); - printw ("%s ", state->dmr_embedded_gps[1]); + printw ("| V XTRA | "); //10 spaces - //Embedded Talker Alias Blocks - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 7; j++) - { - printw ("%s", state->dmr_alias_block_segment[1][i][j]); - } - } - - attroff(COLOR_PAIR(5)); - if (state->carrier == 1) + if(state->dmrburstR == 16 && state->payload_algidR == 0 && (state->dmr_soR & 0xCF) == 0x40) //4F or CF mask? { + attron(COLOR_PAIR(5)); + printw (" **Pr** "); + attroff(COLOR_PAIR(5)); attron(COLOR_PAIR(3)); } - } - - //LRRP - if(state->dmrburstR != 16 && opts->p25_trunk == 0) //only during data and no trunking - { - attron(COLOR_PAIR(4)); - printw ("%s", state->dmr_lrrp_gps[1]); - } - - //Group Name Labels from CSV import - if (state->dmrburstR == 16 || state->dmrburstR > 19) - { - for (int k = 0; k < state->group_tally; k++) + if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->K > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x10) { - if (state->group_array[k].groupNumber == state->lasttgR) + attron(COLOR_PAIR(1)); + printw ("Pr Key [%3lld] ", state->K); + attroff(COLOR_PAIR(1)); + attron(COLOR_PAIR(3)); + } + if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->H > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x68) + { + attron(COLOR_PAIR(1)); + printw ("**tera Pr Key [%010llX] ", state->H); + attroff(COLOR_PAIR(1)); + attron(COLOR_PAIR(3)); + } + //ALG, KeyID, MI 2 //was keyidR + if(state->dmrburstR == 16 && state->payload_algidR > 0 && (state->dmr_soR & 0xCF) == 0x40) + { + attron(COLOR_PAIR(1)); + printw ("ALG: [0x%02X] KEY: [0x%02X] MI: [0x%08X] ", state->payload_algidR, state->payload_keyidR, state->payload_miR); + attroff(COLOR_PAIR(1)); + attron(COLOR_PAIR(3)); + } + //P25-P1 and P2 + if(state->dmrburstR > 19 && state->payload_algidR > 0 && state->payload_algidR != 0x80) + { + attron(COLOR_PAIR(1)); + printw ("ALG: [0x%02X] KEY: [0x%04X] MI: [0x%016llX] ", state->payload_algidR, state->payload_keyidR, state->payload_miN); + attroff(COLOR_PAIR(1)); + attron(COLOR_PAIR(3)); + } + if (state->payload_algidR == 0xAA || state->payload_algidR == 0x21) + { + attron(COLOR_PAIR(1)); + printw("ADP-RC4"); + attron(COLOR_PAIR(3)); + } + if (state->payload_algidR == 0x81 || state->payload_algidR == 0x22) + { + attron(COLOR_PAIR(1)); + printw("DES-OFB"); + attron(COLOR_PAIR(3)); + } + if (state->payload_algidR == 0x83 || state->payload_algidR == 0x23) + { + attron(COLOR_PAIR(1)); + printw("Triple DES"); + attron(COLOR_PAIR(3)); + } + if (state->payload_algidR == 0x85 || state->payload_algidR == 0x24) + { + attron(COLOR_PAIR(1)); + printw("AES-128"); + attron(COLOR_PAIR(3)); + } + if (state->payload_algidR == 0x84 || state->payload_algidR == 0x25 || state->payload_algidR == 0x05) + { + attron(COLOR_PAIR(1)); + printw("AES-256"); + attron(COLOR_PAIR(3)); + } + if (state->payload_algidR == 0x02) + { + attron(COLOR_PAIR(1)); + printw("Hytera Full Encrypt"); + attron(COLOR_PAIR(3)); + } + //Call Types, may switch to the more robust version later? + if(state->dmrburstR == 16 && state->dmr_soR == 0x40 && state->R == 0) //0100 0000 + { + attron(COLOR_PAIR(2)); + printw (" **ENC** "); + attroff(COLOR_PAIR(2)); + attron(COLOR_PAIR(3)); + } + if(state->dmrburstR == 16 && state->dmr_soR == 0x80) + { + attron(COLOR_PAIR(2)); + printw (" **Emergency** "); + attroff(COLOR_PAIR(2)); + attron(COLOR_PAIR(3)); + } + if(state->dmrburstR == 16 && state->dmr_soR == 0x30) //0010 0000 + { + attron(COLOR_PAIR(2)); + printw (" **Private Call** "); + attroff(COLOR_PAIR(2)); + attron(COLOR_PAIR(3)); + } + printw ("\n"); + + //printw ("| | "); + printw ("| D XTRA | "); + + attron(COLOR_PAIR(4)); + + if(state->dmrburstR == 16) //only during call + { + + //Embedded GPS (not LRRP) + attron(COLOR_PAIR(4)); + printw ("%s ", state->dmr_embedded_gps[1]); + + //Embedded Talker Alias Blocks + for (int i = 0; i < 4; i++) { - attron(COLOR_PAIR(4)); - printw (" [%s]", state->group_array[k].groupName); - printw ("[%s] ", state->group_array[k].groupMode); + for (int j = 0; j < 7; j++) + { + printw ("%s", state->dmr_alias_block_segment[1][i][j]); + } } + + attroff(COLOR_PAIR(5)); if (state->carrier == 1) { attron(COLOR_PAIR(3)); } + } - } - if (state->carrier == 1) attron(COLOR_PAIR(3)); - else attroff(COLOR_PAIR(4)); + //LRRP + if(state->dmrburstR != 16) //only during data and no trunking //&& opts->p25_trunk == 0 + { + attron(COLOR_PAIR(4)); + printw ("%s", state->dmr_lrrp_gps[1]); + } + + //Group Name Labels from CSV import + if (state->dmrburstR == 16 || state->dmrburstR > 19) + { + for (int k = 0; k < state->group_tally; k++) + { + if (state->group_array[k].groupNumber == state->lasttgR) + { + attron(COLOR_PAIR(4)); + printw (" [%s]", state->group_array[k].groupName); + printw ("[%s] ", state->group_array[k].groupMode); + } + if (state->carrier == 1) + { + attron(COLOR_PAIR(3)); + } + } + } - printw ("\n"); - } // end if not MS + if (state->carrier == 1) attron(COLOR_PAIR(3)); + else attroff(COLOR_PAIR(4)); + + printw ("\n"); + + if (1 == 1) //opts->p25_trunk == 1 + { + printw ("| T INFO | "); + + // Tuned Frequency Display + if (state->p25_vc_freq[0] != 0) + { + attron(COLOR_PAIR(5)); + printw ("Frequency: [%.06lf] MHz ", (double)state->p25_vc_freq[0]/1000000); + } + if (state->carrier == 1) attron(COLOR_PAIR(3)); + else attroff(COLOR_PAIR(4)); + printw ("\n"); + } + + printw ("\n"); + } // end if not MS } //end DMR BS Types //dPMR @@ -2989,140 +2984,140 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) refresh(); - //keyboard shortcuts - codes same as ascii codes + //keyboard shortcuts - codes same as ascii codes if (c == 27) //esc key, open menu - { - ncursesMenu (opts, state); //just a quick test - } - - if (c == 122) //'z' key, toggle payload to console - { - if (opts->payload == 1) opts->payload = 0; - else opts->payload = 1; - } - - if (c == 99) //'c' key, toggle compact mode - { - if (opts->ncurses_compact == 1) opts->ncurses_compact = 0; - else opts->ncurses_compact = 1; - } - - if (c == 116) //'t' key, toggle trunking - { - if (opts->p25_trunk == 1) opts->p25_trunk = 0; - else opts->p25_trunk = 1; - } - - if (c == 97) //'a' key, toggle call alert beep - { - if (opts->call_alert == 1) opts->call_alert = 0; - else opts->call_alert = 1; - } - - if (c == 104) //'h' key, toggle history - { - if (opts->ncurses_history == 1) opts->ncurses_history = 0; - else opts->ncurses_history = 1; - } - - if (c == 113) //'q' key, quit - { - ncursesClose(); - cleanupAndExit (opts, state); - } - - if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr) - { - if (state->M == 1) state->M = 0; - else state->M = 1; - } - - if (c == 105) //'i' key, toggle signal inversion on inverted types - { - //Set all signal for inversion or uninversion - if (opts->inverted_dmr == 0) { - opts->inverted_dmr = 1; - opts->inverted_dpmr = 1; - opts->inverted_x2tdma = 1; - opts->inverted_ysf = 1; + ncursesMenu (opts, state); //just a quick test } - else - { - opts->inverted_dmr = 0; - opts->inverted_dpmr = 0; - opts->inverted_x2tdma = 0; - opts->inverted_ysf = 0; - } - } - if (c == 109) //'m' key, toggle qpsk/c4fm - everything but phase 2 - { - if (state->rf_mod == 0) + if (c == 122) //'z' key, toggle payload to console { - opts->mod_c4fm = 0; - opts->mod_qpsk = 1; - opts->mod_gfsk = 0; - state->rf_mod = 1; - state->samplesPerSymbol = 10; - state->symbolCenter = 4; + if (opts->payload == 1) opts->payload = 0; + else opts->payload = 1; } - else - { - opts->mod_c4fm = 1; - opts->mod_qpsk = 0; - opts->mod_gfsk = 0; - state->rf_mod = 0; - state->samplesPerSymbol = 10; - state->symbolCenter = 4; - } - } - if (c == 77) //'M' key, toggle qpsk - phase 2 6000 sps - { - if (state->rf_mod == 0) + if (c == 99) //'c' key, toggle compact mode { - opts->mod_c4fm = 0; - opts->mod_qpsk = 1; - opts->mod_gfsk = 0; - state->rf_mod = 1; - state->samplesPerSymbol = 8; - state->symbolCenter = 3; + if (opts->ncurses_compact == 1) opts->ncurses_compact = 0; + else opts->ncurses_compact = 1; } - else - { - opts->mod_c4fm = 1; - opts->mod_qpsk = 0; - opts->mod_gfsk = 0; - state->rf_mod = 0; - state->samplesPerSymbol = 10; - state->symbolCenter = 4; - } - } - if (c == 82) //'R', save symbol capture bin with date/time string as name - { - sprintf (opts->symbol_out_file, "%s %s.bin", getDateN(), getTimeN()); - if (opts->symbol_out_file[0] != 0) + if (c == 116) //'t' key, toggle trunking { - opts->symbol_out = 1; //set flag to 1 - openSymbolOutFile (opts, state); + if (opts->p25_trunk == 1) opts->p25_trunk = 0; + else opts->p25_trunk = 1; } - } - if (c == 114) //'r' key, stop capturing symbol capture bin file - { - if (opts->symbol_out == 1) + if (c == 97) //'a' key, toggle call alert beep { + if (opts->call_alert == 1) opts->call_alert = 0; + else opts->call_alert = 1; + } + + if (c == 104) //'h' key, toggle history + { + if (opts->ncurses_history == 1) opts->ncurses_history = 0; + else opts->ncurses_history = 1; + } + + if (c == 113) //'q' key, quit + { + ncursesClose(); + cleanupAndExit (opts, state); + } + + if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr) + { + if (state->M == 1) state->M = 0; + else state->M = 1; + } + + if (c == 105) //'i' key, toggle signal inversion on inverted types + { + //Set all signal for inversion or uninversion + if (opts->inverted_dmr == 0) + { + opts->inverted_dmr = 1; + opts->inverted_dpmr = 1; + opts->inverted_x2tdma = 1; + opts->inverted_ysf = 1; + } + else + { + opts->inverted_dmr = 0; + opts->inverted_dpmr = 0; + opts->inverted_x2tdma = 0; + opts->inverted_ysf = 0; + } + } + + if (c == 109) //'m' key, toggle qpsk/c4fm - everything but phase 2 + { + if (state->rf_mod == 0) + { + opts->mod_c4fm = 0; + opts->mod_qpsk = 1; + opts->mod_gfsk = 0; + state->rf_mod = 1; + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + } + else + { + opts->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + } + } + + if (c == 77) //'M' key, toggle qpsk - phase 2 6000 sps + { + if (state->rf_mod == 0) + { + opts->mod_c4fm = 0; + opts->mod_qpsk = 1; + opts->mod_gfsk = 0; + state->rf_mod = 1; + state->samplesPerSymbol = 8; + state->symbolCenter = 3; + } + else + { + opts->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + } + } + + if (c == 82) //'R', save symbol capture bin with date/time string as name + { + sprintf (opts->symbol_out_file, "%s %s.bin", getDateN(), getTimeN()); if (opts->symbol_out_file[0] != 0) { - fclose(opts->symbol_out_f); - sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file); + opts->symbol_out = 1; //set flag to 1 + openSymbolOutFile (opts, state); + } + } + + if (c == 114) //'r' key, stop capturing symbol capture bin file + { + if (opts->symbol_out == 1) + { + if (opts->symbol_out_file[0] != 0) + { + fclose(opts->symbol_out_f); + sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file); + } + + opts->symbol_out = 0; } - - opts->symbol_out = 0; } - } // // if (c == 32) //'space bar' replay last bin file (rework to do wav files too?) @@ -3162,143 +3157,143 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) openWavOutFileR (opts, state); } -//this one could cause issues, but seems okay -if (c == 112) //'p' key - stop all per call wav files -{ - //hope this one doesn't cause random crashing or garbage writing - closeWavOutFile (opts, state); - closeWavOutFileL (opts, state); - closeWavOutFileR (opts, state); - sprintf (opts->wav_out_file, "%s", ""); - sprintf (opts->wav_out_fileR, "%s", ""); - opts->dmr_stereo_wav = 0; -} + //this one could cause issues, but seems okay + if (c == 112) //'p' key - stop all per call wav files + { + //hope this one doesn't cause random crashing or garbage writing + closeWavOutFile (opts, state); + closeWavOutFileL (opts, state); + closeWavOutFileR (opts, state); + sprintf (opts->wav_out_file, "%s", ""); + sprintf (opts->wav_out_fileR, "%s", ""); + opts->dmr_stereo_wav = 0; + } -// -// if (c == 115) //'s' key, stop playing wav or symbol in files -// { -// if (opts->symbolfile != NULL) -// { -// if (opts->audio_in_type == 4) -// { -// fclose(opts->symbolfile); -// } -// } + // + // if (c == 115) //'s' key, stop playing wav or symbol in files + // { + // if (opts->symbolfile != NULL) + // { + // if (opts->audio_in_type == 4) + // { + // fclose(opts->symbolfile); + // } + // } -// if (opts->audio_in_type == 2) //wav input file -// { -// sf_close(opts->audio_in_file); -// } + // if (opts->audio_in_type == 2) //wav input file + // { + // sf_close(opts->audio_in_file); + // } -// if (opts->audio_out_type == 0) -// { -// opts->audio_in_type = 0; -// openPulseInput(opts); -// } -// else opts->audio_in_type = 5;//cleanupAndExit(opts, state); - -// } -// + // if (opts->audio_out_type == 0) + // { + // opts->audio_in_type = 0; + // openPulseInput(opts); + // } + // else opts->audio_in_type = 5;//cleanupAndExit(opts, state); + + // } + // -// //Lockout bug in EDACS prevents any group from tuning when using this, not sure why yet -// //WARNING! USE THESE WITH CAUTION! IF BREAKING ISSUES OBSERVED, THEN RESTART AND DON'T USE THEM!! -if (opts->frame_provoice != 1 && c == 49) //'1' key, lockout slot 1 or conventional tg from tuning/playback during session -{ - state->group_array[state->group_tally].groupNumber = state->lasttg; - sprintf (state->group_array[state->group_tally].groupMode, "%s", "B"); - sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT"); - state->group_tally++; + // //Lockout bug in EDACS prevents any group from tuning when using this, not sure why yet + // //WARNING! USE THESE WITH CAUTION! IF BREAKING ISSUES OBSERVED, THEN RESTART AND DON'T USE THEM!! + if (opts->frame_provoice != 1 && c == 49) //'1' key, lockout slot 1 or conventional tg from tuning/playback during session + { + state->group_array[state->group_tally].groupNumber = state->lasttg; + sprintf (state->group_array[state->group_tally].groupMode, "%s", "B"); + sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT"); + state->group_tally++; - //test tuning away to break sync, if not working so well, then disable - //RIGCTL - if (opts->frame_provoice != 1 && opts->p25_is_tuned == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, 450000000); + //test tuning away to break sync, if not working so well, then disable + //RIGCTL + if (opts->frame_provoice != 1 && opts->p25_is_tuned == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, 450000000); - //rtl_udp - if (opts->frame_provoice != 1 && opts->p25_is_tuned == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, 450000000); + //rtl_udp + if (opts->frame_provoice != 1 && opts->p25_is_tuned == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, 450000000); -} + } -if (opts->frame_provoice != 1 && c == 50) //'2' key, lockout slot 2 tdma tgR from tuning/playback during session -{ - state->group_array[state->group_tally].groupNumber = state->lasttgR; - sprintf (state->group_array[state->group_tally].groupMode, "%s", "B"); - sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT"); - state->group_tally++; + if (opts->frame_provoice != 1 && c == 50) //'2' key, lockout slot 2 tdma tgR from tuning/playback during session + { + state->group_array[state->group_tally].groupNumber = state->lasttgR; + sprintf (state->group_array[state->group_tally].groupMode, "%s", "B"); + sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT"); + state->group_tally++; - //test tuning away to break sync, if not working so well, then disable - //RIGCTL - if (opts->p25_is_tuned == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, 450000000); + //test tuning away to break sync, if not working so well, then disable + //RIGCTL + if (opts->p25_is_tuned == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, 450000000); - //rtl_udp - if (opts->p25_is_tuned == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, 450000000); + //rtl_udp + if (opts->p25_is_tuned == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, 450000000); -} + } -if (c == 48) //'0' key, toggle upsampled audio smoothing -{ - if (state->audio_smoothing == 1) state->audio_smoothing = 0; - else state->audio_smoothing = 1; -} + if (c == 48) //'0' key, toggle upsampled audio smoothing + { + if (state->audio_smoothing == 1) state->audio_smoothing = 0; + else state->audio_smoothing = 1; + } -if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode -{ - if (opts->trunk_use_allow_list == 1) opts->trunk_use_allow_list = 0; - else opts->trunk_use_allow_list = 1; -} + if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode + { + if (opts->trunk_use_allow_list == 1) opts->trunk_use_allow_list = 0; + else opts->trunk_use_allow_list = 1; + } -if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls -{ - if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0; - else opts->trunk_tune_private_calls = 1; -} + if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls + { + if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0; + else opts->trunk_tune_private_calls = 1; + } -if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls -{ - if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0; - else opts->trunk_tune_data_calls = 1; -} + if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls + { + if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0; + else opts->trunk_tune_data_calls = 1; + } -if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls -{ - if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0; - else opts->trunk_tune_group_calls = 1; -} + if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls + { + if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0; + else opts->trunk_tune_group_calls = 1; + } -if (c == 70) //'F' key - toggle agressive sync/crc failure/ras -{ - if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1; - else opts->aggressive_framesync = 0; -} + if (c == 70) //'F' key - toggle agressive sync/crc failure/ras + { + if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1; + else opts->aggressive_framesync = 0; + } -if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc. -{ - //dmr trunking/ncurses stuff - state->dmr_rest_channel = -1; //init on -1 - state->dmr_mfid = -1; // + if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc. + { + //dmr trunking/ncurses stuff + state->dmr_rest_channel = -1; //init on -1 + state->dmr_mfid = -1; // - //dmr mfid branding and site parms - sprintf(state->dmr_branding_sub, "%s", ""); - sprintf(state->dmr_branding, "%s", ""); - sprintf (state->dmr_site_parms, "%s", ""); + //dmr mfid branding and site parms + sprintf(state->dmr_branding_sub, "%s", ""); + sprintf(state->dmr_branding, "%s", ""); + sprintf (state->dmr_site_parms, "%s", ""); - //DMR Location Area - DMRLA B***S*** - opts->dmr_dmrla_is_set = 0; - opts->dmr_dmrla_n = 0; + //DMR Location Area - DMRLA B***S*** + opts->dmr_dmrla_is_set = 0; + opts->dmr_dmrla_n = 0; -} + } -//Debug/Troubleshooting Option -if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z) -{ - // opts->p25_is_tuned = 0; - state->last_cc_sync_time = 0; - state->last_vc_sync_time = 0; - noCarrier(opts, state); -} + //Debug/Troubleshooting Option + if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z) + { + // opts->p25_is_tuned = 0; + state->last_cc_sync_time = 0; + state->last_vc_sync_time = 0; + noCarrier(opts, state); + } - //anything with an entry box will need the inputs and outputs stopped first - //so probably just write a function to handle c input, and when c = certain values - //needing an entry box, then stop all of those + //anything with an entry box will need the inputs and outputs stopped first + //so probably just write a function to handle c input, and when c = certain values + //needing an entry box, then stop all of those } //end ncursesPrinter