diff --git a/include/dsd.h b/include/dsd.h index 6323493..fb4d6f8 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -1258,6 +1258,7 @@ void nxdn_descramble (uint8_t dibits[], int len); //nxdn deinterleaving/depuncturing functions void nxdn_deperm_facch (dsd_opts * opts, dsd_state * state, uint8_t bits[144]); void nxdn_deperm_sacch (dsd_opts * opts, dsd_state * state, uint8_t bits[60]); +void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60]); void nxdn_deperm_cac (dsd_opts * opts, dsd_state * state, uint8_t bits[300]); void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type); //type-d 'idas' deinterleaving/depuncturing functions diff --git a/src/nxdn_deperm.c b/src/nxdn_deperm.c index 31b2cfa..af3a89e 100644 --- a/src/nxdn_deperm.c +++ b/src/nxdn_deperm.c @@ -421,6 +421,176 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60]) } +//sacch2 (Icom DCR) +void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60]) +{ + //see about initializing these variables + uint8_t deperm[60]; //60 + uint8_t depunc[72]; //72 + uint8_t trellis_buf[32]; //32 + + memset (deperm, 0, sizeof(deperm)); + memset (depunc, 0, sizeof(depunc)); + memset (trellis_buf, 0, sizeof(trellis_buf)); + + int o = 0; + uint8_t crc = 1; //value computed by crc6 on payload + uint8_t check = 0; //value pulled from last 6 bits + + for (int i=0; i<60; i++) + deperm[PERM_12_5[i]] = bits[i]; + for (int p=0; p<60; p+= 10) { + depunc[o++] = deperm[p+0]; + depunc[o++] = deperm[p+1]; + depunc[o++] = deperm[p+2]; + depunc[o++] = deperm[p+3]; + depunc[o++] = deperm[p+4]; + depunc[o++] = 0; + depunc[o++] = deperm[p+5]; + depunc[o++] = deperm[p+6]; + depunc[o++] = deperm[p+7]; + depunc[o++] = deperm[p+8]; + depunc[o++] = deperm[p+9]; + depunc[o++] = 0; + } + + //switch to the convolutional decoder + uint8_t temp[80]; + uint8_t s0; + uint8_t s1; + uint8_t m_data[5]; //5 + + memset (temp, 0, sizeof (temp)); + memset (m_data, 0, sizeof (m_data)); + memset (trellis_buf, 0, sizeof(trellis_buf)); + + for (int i = 0; i < 72; i++) + temp[i] = depunc[i] << 1; + + CNXDNConvolution_start(); + for (int i = 0; i < 36; i++) + { + s0 = temp[(2*i)]; + s1 = temp[(2*i)+1]; + + CNXDNConvolution_decode(s0, s1); + } + + //stored as 4 bytes, will need to convert to trellis_buf after running + CNXDNConvolution_chainback(m_data, 32); + + for(int i = 0; i < 4; i++) + { + trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1; + trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1; + trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1; + trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1; + trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1; + trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1; + trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1; + trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1; + } + + crc = crc6(trellis_buf, 26); + for (int i = 0; i < 6; i++) + { + check = check << 1; + check = check | trellis_buf[i+26]; + } + + //debug + // if (crc == check) + // fprintf (stderr, " Pass 1 "); + + //if the crc fails, attempt again with the other trellis decoder + if (crc != check) + { + //debug + // fprintf (stderr, " Pass 2 "); + crc = 1; check = 0; + memset (trellis_buf, 0, sizeof(trellis_buf)); + memset (m_data, 0, sizeof(m_data)); + trellis_decode(trellis_buf, depunc, 32); + //fill m_data bytes with trellis_buf + for(int i = 0; i < 4; i++) + m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8); + crc = crc6(trellis_buf, 26); //32 + for (int i = 0; i < 6; i++) + { + check = check << 1; + check = check | trellis_buf[i+26]; + } + } + + uint8_t nsf_sacch[26]; + memset (nsf_sacch, 0, sizeof(nsf_sacch)); + for (int i = 0; i < 26; i++) + nsf_sacch[i] = trellis_buf[i+6]; + + //SF configuration is a bit different for this + uint8_t sf_fb = trellis_buf[0]; UNUSED(sf_fb); + uint8_t sf_num = (uint8_t) convert_bits_into_output(trellis_buf+1, 2); + uint8_t ran = (uint8_t) convert_bits_into_output(trellis_buf+3, 3); UNUSED(ran); //unclear if this is a RAN like value or not, but its consistent + + //debug + // if (crc == check) + // fprintf (stderr, " SF: %X; LB: %d;", sf_num, sf_fb); + + sf_num = 3-sf_num; + + if (crc == check) + fprintf (stderr, " PF: %d/4; RAN: %d;", sf_num+1, ran); + + memcpy(state->nxdn_sacch_frame_segment[sf_num], nsf_sacch, 18*sizeof(uint8_t)); + if (crc == check) + state->nxdn_sacch_frame_segcrc[sf_num] = 0; + else state->nxdn_sacch_frame_segcrc[sf_num] = 1; + + if (sf_num == 3) //just showing as MT: 0 (was CALL_RESP) + NXDN_SACCH_Full_decode(opts, state); + + //instead, just use static values so event log will log something, and do wav files, etc + //disable this is random false positive for this lich code triggers this often enough + if (crc == check) + { + state->gi[0] = 0; + state->nxdn_last_ran = 7; + state->nxdn_last_tg = 777; + state->nxdn_last_rid = 777; + sprintf (state->generic_talker_alias[0], "%s", "ICOM DCR"); + sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s; ", "ICOM DCR"); + } + + if (opts->payload == 1) + { + fprintf (stderr, "\n ICOM DCR SACCH "); + for (int i = 0; i < 4; i++) + fprintf (stderr, "[%02X]", m_data[i]); + + if (crc != check) + { + + fprintf (stderr, "%s", KRED); + fprintf (stderr, " (CRC ERR)"); + fprintf (stderr, "%s", KNRM); + } + + } + + //clear out if run, or crc error + if (sf_num == 3) + { + memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); + memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); + } + else if (crc != check) + { + memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); + memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); + } + +} + void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type) { uint8_t deperm[348]; //348 @@ -1154,7 +1324,7 @@ void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType) //RTCH Outbound will take precedent when differences may occur (except CALL_ASSGN) fprintf (stderr, "%s", KYEL); if (MessageType == 0x10) fprintf(stderr, " IDLE"); - else if (MessageType == 0x00) fprintf(stderr, " CALL_RESP"); + // else if (MessageType == 0x00) fprintf(stderr, " CALL_RESP"); else if (MessageType == 0x01) fprintf(stderr, " VCALL"); else if (MessageType == 0x02) fprintf(stderr, " VCALL_REC_REQ"); else if (MessageType == 0x03) fprintf(stderr, " VCALL_IV"); @@ -1185,7 +1355,7 @@ void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType) else if (MessageType == 0x39) fprintf(stderr, " SDCALL_REQ_USERDATA"); else if (MessageType == 0x3B) fprintf(stderr, " SDCALL_RESP"); else if (MessageType == 0x3F) fprintf(stderr, " ALIAS"); - else fprintf(stderr, " Unknown M-%02X", MessageType); + else fprintf(stderr, " Unknown Message Type: %02X;", MessageType); fprintf (stderr, "%s", KNRM); //Zero out stale values on DISC or TX_REL only (IDLE messaages occur often on NXDN96 VCH, and randomly on Type-C FACCH1 steals for some reason) diff --git a/src/nxdn_frame.c b/src/nxdn_frame.c index 735a7c3..ef2deac 100644 --- a/src/nxdn_frame.c +++ b/src/nxdn_frame.c @@ -49,6 +49,9 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) int facch3 = 0; int udch2 = 0; + //Icom DCR Mode Specific Things + int sacch2 = 0; //sacch, but without SF or RAN value (for data dump currently) + //new breakdown of lich codes uint8_t lich_rf = 0; //RF Channel Type uint8_t lich_fc = 0; //Functional Channel Type @@ -173,6 +176,12 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) sacch = 1; break; + //Icom DCR Mode + case 0x46: + voice = 3; + sacch2 = 1; + break; + //NXDN "Type-D" or "IDAS" Specific Lich Codes case 0x76: //normal vch voice (in one and two) case 0x77: @@ -250,6 +259,15 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) if (opts->payload == 1) fprintf (stderr, "L%02X - ", lich); } + else if (sacch2) + { + if (opts->frame_nxdn48 == 1) + { + printFrameSync (opts, state, "ICOM DCR ", 0, "-"); + } + if (opts->payload == 1) + fprintf (stderr, "L%02X - ", lich); + } else if (voice || facch || sacch || facch2 || udch || cac) { if (opts->frame_nxdn48 == 1) @@ -473,6 +491,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) if (facch3) nxdn_deperm_facch3_udch2(opts, state, facch3_bits, 1); if (sacch) nxdn_deperm_sacch(opts, state, sacch_bits); + if (sacch2) nxdn_deperm_sacch2(opts, state, sacch_bits); if (cac) nxdn_deperm_cac(opts, state, cac_bits); //Seperated UDCH user data from facch2 data