mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-09 15:27:22 -05:00
NXDN: Add DCR TCH / PICH Lich 0x48 Payload Only; #299
Misc Tweaks to Payload Format;
This commit is contained in:
@@ -1258,13 +1258,15 @@ 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
|
||||
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction);
|
||||
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type);
|
||||
//end
|
||||
//DCR Mode
|
||||
void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60]);
|
||||
void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144]);
|
||||
//MT and Voice
|
||||
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
|
||||
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
|
||||
//Osmocom OP25 12 Rate Trellis Decoder (for NXDN, M17, YSF, etc)
|
||||
|
||||
@@ -516,7 +516,7 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
}
|
||||
|
||||
//Configuration of Single Message or Multi Part Message
|
||||
uint8_t sf_fb = trellis_buf[0];
|
||||
uint8_t sf_fb = trellis_buf[0];
|
||||
uint8_t sf_num = (uint8_t) convert_bits_into_output(trellis_buf+1, 2);
|
||||
uint8_t sf_mes = (uint8_t) convert_bits_into_output(trellis_buf+3, 5);
|
||||
uint8_t sf_pof = 3-sf_num;
|
||||
@@ -530,6 +530,8 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
|
||||
if (sf_mes == 0x01)
|
||||
fprintf (stderr, "Call; ");
|
||||
else if (sf_mes == 0x02)
|
||||
fprintf (stderr, "PDU; ");
|
||||
else if (sf_mes == 0x1E)
|
||||
fprintf (stderr, "End; ");
|
||||
else if (sf_mes == 0x00)
|
||||
@@ -559,9 +561,6 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
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++;
|
||||
|
||||
if (sf_fb && sf_pof) //single unit message
|
||||
memcpy(state->dmr_pdu_sf[0]+0, trellis_buf+bf_idx, sf_size*sizeof(uint8_t));
|
||||
@@ -621,10 +620,12 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
//multi-part message, continue decoding
|
||||
if (sf_fb == 0 && sf_num == 0)
|
||||
{
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
//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));
|
||||
unsigned long long int mes_hex = (unsigned long long int ) convert_bits_into_output(state->dmr_pdu_sf[0]+18, 54);
|
||||
fprintf (stderr, " Message: %014llX; ", mes_hex << 0);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -638,7 +639,7 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
if (sf_num == sf_end)
|
||||
{
|
||||
fprintf (stderr, "\n DCR SFULL ");
|
||||
for (int i = 0; i < sf_bytes; i++)
|
||||
for (int i = 0; i < 9; i++)
|
||||
fprintf (stderr, "[%02X]", convert_bits_into_output(state->dmr_pdu_sf[0]+(i*8), 8));
|
||||
}
|
||||
|
||||
@@ -651,12 +652,144 @@ 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)
|
||||
|
||||
}
|
||||
|
||||
//PICH or TCH 144 bit (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_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
{
|
||||
uint8_t deperm[144]; //144
|
||||
uint8_t depunc[192]; //192
|
||||
uint8_t trellis_buf[96]; //96
|
||||
uint16_t crc = 1; //crc calculated by function
|
||||
uint16_t check = 0; //crc from payload for comparison
|
||||
int out;
|
||||
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
|
||||
for (int i=0; i<144; i++)
|
||||
deperm[PERM_16_9[i]] = bits[i];
|
||||
out = 0;
|
||||
for (int i=0; i<144; i+=3) {
|
||||
depunc[out++] = deperm[i+0];
|
||||
depunc[out++] = 0;
|
||||
depunc[out++] = deperm[i+1];
|
||||
depunc[out++] = deperm[i+2];
|
||||
}
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[200];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[20]; //13
|
||||
memset (temp, 0, sizeof(temp));
|
||||
memset (m_data, 0, sizeof(m_data));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
|
||||
for (int i = 0; i < 192; i++)
|
||||
temp[i] = depunc[i] << 1;
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0; i < 96; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 92);
|
||||
|
||||
for(int i = 0; i < 12; 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 = crc12f (trellis_buf, 84); //80
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[84+i]; //80
|
||||
}
|
||||
|
||||
//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, 92);
|
||||
//fill m_data bytes with trellis_buf
|
||||
for(int i = 0; i < 12; i++)
|
||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
||||
crc = crc12f (trellis_buf, 84);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[i+84];
|
||||
}
|
||||
}
|
||||
|
||||
//need more data points, but thinking this is probably similar to facch3
|
||||
//or udch2 where we need to put two tch (facch1) messages together
|
||||
// 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));
|
||||
// uint8_t opcode = (uint8_t)ConvertBitIntoBytes(&trellis_buf[0], 8);
|
||||
// uint8_t gi = trellis_buf[16];
|
||||
// uint16_t source = (uint16_t)ConvertBitIntoBytes(&trellis_buf[24], 16);
|
||||
// uint16_t target = (uint16_t)ConvertBitIntoBytes(&trellis_buf[40], 16);
|
||||
|
||||
// if (opcode != 0)
|
||||
// {
|
||||
// fprintf (stderr, "\n ");
|
||||
// fprintf (stderr, "OP: %02X; ", opcode);
|
||||
// fprintf (stderr, "Source: %d; Target: %d; ", source, target);
|
||||
// if (gi)
|
||||
// fprintf (stderr, "Private; ");
|
||||
// else fprintf (stderr, "Group; ");
|
||||
// }
|
||||
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// fprintf (stderr, "\n ");
|
||||
// fprintf (stderr, "%s", KRED);
|
||||
// fprintf (stderr, " (CRC ERR)");
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// }
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " TCH Payload ");
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
if (crc != check && opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
UNUSED(state);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//DCR Mode Specific Things
|
||||
int sacch2 = 0;
|
||||
int pich_tch = 0;
|
||||
|
||||
//new breakdown of lich codes
|
||||
uint8_t lich_rf = 0; //RF Channel Type
|
||||
@@ -125,7 +126,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
break;
|
||||
case 0x28: //facch2 types
|
||||
case 0x29:
|
||||
case 0x48:
|
||||
// case 0x48: //removing from here, moving to DCR as pich_tch
|
||||
case 0x49:
|
||||
facch2 = 1;
|
||||
break;
|
||||
@@ -176,13 +177,15 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
sacch = 1;
|
||||
break;
|
||||
|
||||
//DCR Mode
|
||||
//DCR Voice
|
||||
case 0x46:
|
||||
voice = 3;
|
||||
sacch2 = 1;
|
||||
break;
|
||||
|
||||
//DCR Data or End Frame (bad parity)
|
||||
//DCR Data or End Frame
|
||||
case 0x48:
|
||||
pich_tch = 3;
|
||||
case 0x4A:
|
||||
sacch2 = 1;
|
||||
break;
|
||||
@@ -194,8 +197,8 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
scch = 1;
|
||||
voice = 3;
|
||||
break;
|
||||
case 0x74: //vch in 1, facch1 in 2 (facch 2 steal)
|
||||
case 0x75:
|
||||
// case 0x74: //False Positive on DCR, keep disabled, or revert this line
|
||||
case 0x75: //vch in 1, facch1 in 2 (facch 2 steal)
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
voice = 1;
|
||||
@@ -342,7 +345,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
else direction = 1;
|
||||
|
||||
// RF Channel Type
|
||||
if (lich != 0x46 && lich != 0x4A)
|
||||
if (sacch2 == 0)
|
||||
{
|
||||
|
||||
if (lich_rf == 0) fprintf (stderr, "RCCH ");
|
||||
@@ -501,16 +504,16 @@ 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
|
||||
if (udch) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 0);
|
||||
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 1);
|
||||
|
||||
//SHOULD be okay to run facch1's again on steal frames, will need testing
|
||||
// if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
|
||||
// if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
//DCR
|
||||
if (sacch2) nxdn_deperm_sacch2(opts, state, sacch_bits);
|
||||
if (pich_tch & 1) nxdn_deperm_pich_tch(opts, state, facch_bits_a);
|
||||
if (pich_tch & 2) nxdn_deperm_pich_tch(opts, state, facch_bits_b);
|
||||
|
||||
//only run facch in second slot if its not equal to the first one
|
||||
//ideally, this would work better AFTER decoding/FEC
|
||||
|
||||
Reference in New Issue
Block a user