mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 17:27:21 -05:00
NXDN: Fix and Decode Some DCR Elements; #299
Elements include scrambler bits, UC bits, and other misc items; Tweaks to payload output;
This commit is contained in:
@@ -421,7 +421,8 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
|
||||
}
|
||||
|
||||
//sacch2 (Icom DCR)
|
||||
//sacch2 (JPN DCR)
|
||||
//SEE: https://web.archive.org/web/20150417175725/http://arib.or.jp/english/html/overview/doc/1-STD-T98v1_4.pdf
|
||||
void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
{
|
||||
//see about initializing these variables
|
||||
@@ -514,14 +515,28 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
check = (uint8_t) convert_bits_into_output(trellis_buf+26, 6);
|
||||
}
|
||||
|
||||
//SF configuration is a bit different for this
|
||||
uint8_t sf_fb = trellis_buf[0]; UNUSED(sf_fb);
|
||||
//Configuration of Single Message or Multi Part Message
|
||||
uint8_t sf_fb = trellis_buf[0];
|
||||
uint8_t sf_num = (uint8_t) convert_bits_into_output(trellis_buf+1, 2);
|
||||
|
||||
sf_num = 3 - sf_num;
|
||||
uint8_t sf_mes = (uint8_t) convert_bits_into_output(trellis_buf+3, 5);
|
||||
uint8_t sf_pof = 3-sf_num;
|
||||
|
||||
if (crc == check)
|
||||
fprintf (stderr, "PF: %d/4;", sf_num+1);
|
||||
{
|
||||
if (sf_fb && sf_pof) //single message, single unit
|
||||
fprintf (stderr, "PF: %d/1; ", sf_num+1);
|
||||
else //multiple unit message
|
||||
fprintf (stderr, "PF: %d/4; ", sf_pof+1);
|
||||
|
||||
if (sf_mes == 0x01)
|
||||
fprintf (stderr, "Call; ");
|
||||
else if (sf_mes == 0x1E)
|
||||
fprintf (stderr, "End; ");
|
||||
else if (sf_mes == 0x00)
|
||||
fprintf (stderr, "Idle; ");
|
||||
else fprintf (stderr, "Res: %02X; ", sf_mes);
|
||||
|
||||
}
|
||||
else if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
@@ -533,21 +548,29 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
state->nxdn_sacch_frame_segcrc[sf_num] = 0;
|
||||
else state->nxdn_sacch_frame_segcrc[sf_num] = 1;
|
||||
|
||||
//test values for storage and which parts to store
|
||||
//entire superframe has good crc
|
||||
uint8_t crc_sf_check = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
crc_sf_check += state->nxdn_sacch_frame_segcrc[i];
|
||||
|
||||
//values for storage and which parts to store
|
||||
int sf_full = 26; //full size of a sacch frame, minus CRC6
|
||||
int sf_size = 23; //size of superframe portion
|
||||
int sf_end = 3; //end of sf
|
||||
int sf_idx = sf_size*sf_num; //index position for this frame compared to super frame
|
||||
int sf_size = 18; //size of superframe portion (18 bits)
|
||||
int sf_end = 0; //end of sf
|
||||
int sf_idx = sf_size*sf_pof; //index position for this frame compared to super frame
|
||||
int bf_idx = sf_full-sf_size; //index position for buffer to superframe
|
||||
int sf_bytes = ((sf_size*4)/8);
|
||||
if ( ((sf_size*4)%8) != 0)
|
||||
sf_bytes++;
|
||||
memcpy(state->dmr_pdu_sf[0]+sf_idx, trellis_buf+bf_idx, sf_size*sizeof(uint8_t));
|
||||
|
||||
//all segments okay
|
||||
// if (sf_num == sf_end && state->nxdn_sacch_frame_segcrc[0] == 0 && state->nxdn_sacch_frame_segcrc[1] == 0 &&
|
||||
// state->nxdn_sacch_frame_segcrc[2] == 0 && state->nxdn_sacch_frame_segcrc[3] == 0 )
|
||||
// NXDN_Elements_Content_decode(opts, state, 1, state->dmr_pdu_sf[0]);
|
||||
if (sf_fb && sf_pof) //single unit message
|
||||
memcpy(state->dmr_pdu_sf[0]+0, trellis_buf+bf_idx, sf_size*sizeof(uint8_t));
|
||||
else //multiple unit message
|
||||
memcpy(state->dmr_pdu_sf[0]+sf_idx, trellis_buf+bf_idx, sf_size*sizeof(uint8_t));
|
||||
|
||||
//if force application of scrambler key, then let's reset, regardless of CRC check
|
||||
if (sf_fb && state->M == 1)
|
||||
state->payload_miN = 0;
|
||||
|
||||
//currently using 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
|
||||
@@ -557,19 +580,64 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
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");
|
||||
sprintf (state->generic_talker_alias[0], "%s", "JPN DCR");
|
||||
sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s; ", "JPN DCR");
|
||||
|
||||
//sf_fb is the head message in a multi part, or the only message in a single part message
|
||||
if (sf_fb)
|
||||
state->payload_miN = 0;
|
||||
}
|
||||
|
||||
//check for valid crc on single, or on all received
|
||||
if ( (sf_fb && sf_pof && crc == check) || //single frame
|
||||
(sf_num == sf_end && crc_sf_check == 0) ) //multi part frame
|
||||
{
|
||||
uint8_t cipher = (uint16_t) convert_bits_into_output(state->dmr_pdu_sf[0]+0, 2);
|
||||
uint16_t user_code = (uint16_t) convert_bits_into_output(state->dmr_pdu_sf[0]+2, 9);
|
||||
fprintf (stderr, "UC: %03d; ", user_code);
|
||||
if (cipher == 0x01)
|
||||
{
|
||||
fprintf (stderr, "Scrambler; ");
|
||||
state->nxdn_cipher_type = 1;
|
||||
if (state->R != 0)
|
||||
fprintf (stderr, "Key: %d; ", state->R);
|
||||
}
|
||||
else if (cipher != 0x00)
|
||||
{
|
||||
fprintf (stderr, "Reserved Comms: %d; ", cipher);
|
||||
}
|
||||
|
||||
//set enc bit here so we can tell playSynthesizedVoice whether or not to play enc traffic
|
||||
if (state->nxdn_cipher_type != 0)
|
||||
state->dmr_encL = 1;
|
||||
if (state->nxdn_cipher_type == 0 || state->R != 0)
|
||||
state->dmr_encL = 0;
|
||||
|
||||
//this always appears to be 0, but could be other values
|
||||
uint8_t mfid = (uint16_t) convert_bits_into_output(state->dmr_pdu_sf[0]+11, 7);
|
||||
if (mfid != 0)
|
||||
fprintf (stderr, "MFID: %02X; ", mfid);
|
||||
|
||||
//multi-part message, continue decoding
|
||||
if (sf_fb == 0 && sf_num == 0)
|
||||
{
|
||||
//can't find definitions for these elements, even when MT == 1 and MFID == 0
|
||||
fprintf (stderr, "Cont(54): ");
|
||||
for (int i = 0; i < 7; i++)
|
||||
fprintf (stderr, "%02X", convert_bits_into_output(state->dmr_pdu_sf[0]+(i*8)+18, 8));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n ICOM DCR SACCH ");
|
||||
fprintf (stderr, "\n DCR SACCH ");
|
||||
for (int i = 0; i < 4; i++)
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
|
||||
if (sf_num == sf_end)
|
||||
{
|
||||
fprintf (stderr, "\n ICOM DCR SFULL ");
|
||||
fprintf (stderr, "\n DCR SFULL ");
|
||||
for (int i = 0; i < sf_bytes; i++)
|
||||
fprintf (stderr, "[%02X]", convert_bits_into_output(state->dmr_pdu_sf[0]+(i*8), 8));
|
||||
}
|
||||
@@ -583,12 +651,12 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
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->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
||||
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->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
||||
// 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));
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ 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)
|
||||
//DCR Mode Specific Things
|
||||
int sacch2 = 0;
|
||||
|
||||
//new breakdown of lich codes
|
||||
uint8_t lich_rf = 0; //RF Channel Type
|
||||
@@ -96,7 +96,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
lich_parity_received = lich & 1;
|
||||
lich_parity_computed = ((lich >> 7) + (lich >> 6) + (lich >> 5) + (lich >> 4)) & 1;
|
||||
lich = lich >> 1;
|
||||
if (lich_parity_received != lich_parity_computed)
|
||||
if (lich_parity_received != lich_parity_computed && lich != 0x4A) //may disable this if it causes issues
|
||||
{
|
||||
if (opts->payload == 1) fprintf(stderr, " Lich Parity Error %02X\n", lich);
|
||||
state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
|
||||
@@ -176,12 +176,17 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
sacch = 1;
|
||||
break;
|
||||
|
||||
//Icom DCR Mode
|
||||
//DCR Mode
|
||||
case 0x46:
|
||||
voice = 3;
|
||||
sacch2 = 1;
|
||||
break;
|
||||
|
||||
//DCR Data or End Frame (bad parity)
|
||||
case 0x4A:
|
||||
sacch2 = 1;
|
||||
break;
|
||||
|
||||
//NXDN "Type-D" or "IDAS" Specific Lich Codes
|
||||
case 0x76: //normal vch voice (in one and two)
|
||||
case 0x77:
|
||||
@@ -257,16 +262,16 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
printFrameSync (opts, state, "IDAS D ", 0, "-");
|
||||
}
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "L%02X - ", lich);
|
||||
fprintf (stderr, "L: %02X; ", lich);
|
||||
}
|
||||
else if (sacch2)
|
||||
{
|
||||
if (opts->frame_nxdn48 == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "ICOM DCR ", 0, "-");
|
||||
printFrameSync (opts, state, "JPN DCR", 0, "-");
|
||||
}
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "L%02X - ", lich);
|
||||
fprintf (stderr, "L: %02X; ", lich);
|
||||
}
|
||||
else if (voice || facch || sacch || facch2 || udch || cac)
|
||||
{
|
||||
@@ -276,7 +281,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else printFrameSync (opts, state, "NXDN96 ", 0, "-");
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "L%02X - ", lich);
|
||||
fprintf (stderr, "L: %02X; ", lich);;
|
||||
}
|
||||
|
||||
//now that we have a good LICH, we can collect all of our dibits
|
||||
@@ -337,13 +342,18 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
else direction = 1;
|
||||
|
||||
// RF Channel Type
|
||||
if (lich_rf == 0) fprintf (stderr, "RCCH ");
|
||||
else if (lich_rf == 1) fprintf (stderr, "RTCH ");
|
||||
else if (lich_rf == 2) fprintf (stderr, "RDCH ");
|
||||
else
|
||||
if (lich != 0x46 && lich != 0x4A)
|
||||
{
|
||||
if (lich < 0x60) fprintf (stderr, "RTCH_C ");
|
||||
else fprintf (stderr, "RTCH2 ");
|
||||
|
||||
if (lich_rf == 0) fprintf (stderr, "RCCH ");
|
||||
else if (lich_rf == 1) fprintf (stderr, "RTCH ");
|
||||
else if (lich_rf == 2) fprintf (stderr, "RDCH ");
|
||||
else
|
||||
{
|
||||
if (lich < 0x60) fprintf (stderr, "RTCH_C ");
|
||||
else fprintf (stderr, "RTCH2 ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Functional Channel Type -- things start to get really convoluted here
|
||||
@@ -419,19 +429,19 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
if (voice && !facch) //voice only, no facch steal
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " Voice ");
|
||||
fprintf (stderr, "Voice ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
else if (voice && facch) //voice with facch1 steal
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " V%d+F%d ", 3 - facch, facch); //print which position on each
|
||||
fprintf (stderr, "V%d+F%d ", 3 - facch, facch); //print which position on each
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
else //Covers FACCH1 in both, FACCH2, UDCH, UDCH2, CAC
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Data ");
|
||||
fprintf (stderr, "Data ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//roll the voice scrambler LFSR here if key available to advance seed (usually just needed on NXDN96)
|
||||
|
||||
Reference in New Issue
Block a user