mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-12 08:47:24 -05:00
DMR: Rework PDUs;
This commit is contained in:
@@ -661,6 +661,7 @@ typedef struct
|
||||
|
||||
//new stuff below here
|
||||
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
|
||||
uint8_t data_block_poc[2]; //padding octets in the header (needed for Data PDU Decryption)
|
||||
uint8_t dmr_pdu_sf[2][24*128]; //unified pdu 'superframe' //[slot][byte] -- increased capacity to 127(+1) full rate blocks
|
||||
uint8_t cap_plus_csbk_bits[2][12*8*8]; //CSBK Cap+ FL initial and appended block bit storage, by slot
|
||||
uint8_t cap_plus_block_num[2]; //received block number storage -- per timeslot
|
||||
@@ -1285,7 +1286,12 @@ 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[], 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);
|
||||
|
||||
//dmr pdu handling
|
||||
void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
||||
void dmr_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU);
|
||||
void dmr_sd_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU);
|
||||
void dmr_udp_comp_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU);
|
||||
void dmr_reset_blocks (dsd_opts * opts, dsd_state * state);
|
||||
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[]);
|
||||
|
||||
172
src/dmr_block.c
172
src/dmr_block.c
@@ -11,8 +11,7 @@
|
||||
//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)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
uint8_t slot = state->currentslot;
|
||||
|
||||
//clear out unified pdu 'superframe' slot
|
||||
@@ -68,6 +67,9 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
//store source for dmr pdu packet handling (lrrp) when not available in completed message
|
||||
if (dpf != 15) state->dmr_lrrp_source[slot] = source;
|
||||
|
||||
//store number of padding octets in a header to be used
|
||||
if (dpf != 15) state->data_block_poc[slot] = poc;
|
||||
|
||||
//set dpf to storage for later use (UDT, SD, etc)
|
||||
state->data_header_format[slot] = dpf;
|
||||
|
||||
@@ -132,8 +134,6 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
//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
|
||||
UNUSED(p_pot);
|
||||
|
||||
fprintf (stderr, "%s ", KGRN);
|
||||
fprintf (stderr, "\n");
|
||||
@@ -148,7 +148,8 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
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 if (dpf == 15) fprintf (stderr, "Proprietary Packet Data");
|
||||
else if (dpf == 15) fprintf (stderr, "Extended"); //
|
||||
else fprintf (stderr, "Reserved/Unknown DPF %X ", dpf);
|
||||
|
||||
if (a == 1 && dpf != 15) fprintf(stderr, "- Response Requested ");
|
||||
@@ -165,14 +166,14 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
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 == 9) sprintf (sap_string, "%s", "EXTD HDR"); //Extended Header (Proprietary)
|
||||
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)
|
||||
{
|
||||
if (p_mfid == 0x10) sprintf (mfid_string, "%s", "Motorola");
|
||||
if (p_mfid == 0x10) sprintf (mfid_string, "%s", "Moto"); //could just also be a generic catch all for DMRA
|
||||
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");
|
||||
@@ -313,44 +314,85 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
//Proprietary Data Header
|
||||
if (dpf == 15)
|
||||
{
|
||||
fprintf (stderr, " - P_SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string);
|
||||
//The SAP found here is the actual SAP of the message (like a P25 ndary SAP, and can chain together according to ETSI)
|
||||
fprintf (stderr, " - SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string);
|
||||
|
||||
//p_sap 1 on mfid 10 (moto) is a pain, and doesn't assemble correctly for some reason
|
||||
//two extra duplicate blocks are transmitted at the end for some reason -- system unique error?
|
||||
if (p_sap != 1)
|
||||
//p_sap 1 on mfid 10 (moto) is unknown, and the messages don't pass the CRC32
|
||||
//two extra duplicate blocks observed only happens on one sample, could have been radio or repeater errors?
|
||||
// if (p_sap != 1)
|
||||
{
|
||||
//sanity check to prevent segfault (this happened when the regular header was not received beforehand)
|
||||
if (state->data_header_blocks[slot] > 1)
|
||||
state->data_header_blocks[slot]--;
|
||||
}
|
||||
else
|
||||
// else
|
||||
// {
|
||||
// //this method will just include the prop_pdu header as a data block and assemble the data blocks as a message, excluding duplicates
|
||||
// int blocks = state->data_header_blocks[slot]-1;
|
||||
// if (blocks > 127) blocks = 127;
|
||||
// if (blocks < 1) blocks = 4;
|
||||
// for(i = 0; i < 12; i++)
|
||||
// state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i];
|
||||
// state->data_block_counter[slot]++;
|
||||
// }
|
||||
|
||||
//Start Setting DMR Data Packet Encryption Variables
|
||||
if (p_sap != 1 && p_mfid == 0x10) //p_sap 1 is reserved and doesn't seem to contain ENC header (may be extended address, or other signalling)
|
||||
{
|
||||
//this method will assemble with the duplicate blocks and include the header as well
|
||||
// state->data_header_blocks[slot]++;
|
||||
// state->data_header_blocks[slot]++;
|
||||
// int blocks = state->data_header_blocks[slot]-1;
|
||||
// if (blocks > 127) blocks = 127;
|
||||
// if (blocks < 1) blocks = 4; //safety value
|
||||
// for(i = 0; i < 12; i++)
|
||||
// state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i];
|
||||
// state->data_block_counter[slot]++;
|
||||
//check ENC bit, assuming this is an ENC bit, or SVC OPT like thing
|
||||
if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[20], 4) == 1)
|
||||
{
|
||||
//set to 0x100 so it won't trigger any weird flags, but still has a non-zero value to be checked later
|
||||
if (state->currentslot == 0) state->dmr_so = 0x100;
|
||||
else state->dmr_soR = 0x100;
|
||||
}
|
||||
|
||||
//this method will just include the prop_pdu header as a data block and assemble the data blocks as a message, excluding duplicates
|
||||
int blocks = state->data_header_blocks[slot]-1;
|
||||
if (blocks > 127) blocks = 127;
|
||||
if (blocks < 1) blocks = 4;
|
||||
for(i = 0; i < 12; i++)
|
||||
state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i];
|
||||
state->data_block_counter[slot]++;
|
||||
fprintf (stderr, "\n PDU ENC Header:");
|
||||
fprintf (stderr, " MFID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8));
|
||||
fprintf (stderr, " ENC: %X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[20], 4));
|
||||
|
||||
//this method will NOT include the prop_pdu header as a data block and assemble the data blocks as a message, excluding duplicates
|
||||
// state->data_header_blocks[slot]--; UNUSED(i);
|
||||
if (state->currentslot == 0)
|
||||
state->payload_keyid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[24], 8);
|
||||
else state->payload_keyidR = (uint8_t)ConvertBitIntoBytes(&dheader_bits[24], 8);
|
||||
fprintf (stderr, " Key ID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[24], 8));
|
||||
|
||||
//this uses the same 3 bit method found in the 'late entry' alg
|
||||
if (state->currentslot == 0) //could be 17,3
|
||||
state->payload_algid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3);
|
||||
else state->payload_algidR = (uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3);
|
||||
fprintf (stderr, " ALG: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3));
|
||||
if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 0) fprintf (stderr, " BP;");
|
||||
if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 1) fprintf (stderr, " RC4;");
|
||||
if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 2) fprintf (stderr, " DES56;");
|
||||
if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 3) fprintf (stderr, " AES128;");
|
||||
if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 4) fprintf (stderr, " AES256;");
|
||||
|
||||
if (state->currentslot == 0)
|
||||
state->payload_mi = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 32);
|
||||
else state->payload_miR = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 32);
|
||||
|
||||
//print MI only if this is not Moto BP (no MI on those)
|
||||
if ((uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 32) != 0)
|
||||
fprintf (stderr, " MI(32): %08X", (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 32));
|
||||
|
||||
//no matter how you assemble this, with or without the p_head block(s) or extra blocks, 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
|
||||
}
|
||||
|
||||
else //if (p_mfid == 0x10)
|
||||
{
|
||||
//I wonder if this is like the extended addressing header used on P25p1
|
||||
//(either way, the CRC32 will still fail, maybe its RAS or a MAC?)
|
||||
/*Unknown Extended Header: 1F1002011127E70D20232018
|
||||
Slot 2 - Multi Block PDU Message CRC32 ERR
|
||||
Slot 2 - Multi Block PDU Message
|
||||
1F1002011127E70D20232018 <--fails CRC32 with or without this attached
|
||||
41341F9AAECDE6554616A43C
|
||||
0E2A6335040C872A0009006C
|
||||
007356B370000000458AB84D <--very clearly 32 bits (4 bytes) after padding
|
||||
*/ //End Example
|
||||
fprintf (stderr, "\n Unknown Extended Header: ");
|
||||
for (uint8_t i = 2; i < 10; i++)
|
||||
fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&dheader_bits[0+(i*8)], 8));
|
||||
}
|
||||
//End Setting DMR Data Packet Encryption Variables
|
||||
}
|
||||
|
||||
//block storage sanity
|
||||
@@ -361,24 +403,12 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
//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)
|
||||
// if (dpf != 15 && dpf != 1)
|
||||
{
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Data Call - %s TGT: %d SRC: %d ", sap_string, target, source);
|
||||
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;
|
||||
|
||||
@@ -767,9 +797,46 @@ 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;
|
||||
|
||||
//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]);
|
||||
//check for encryption on PDU
|
||||
uint8_t enc_check = 0;
|
||||
uint8_t decrypted_pdu = 1;
|
||||
if (slot == 0 && state->dmr_so == 0x100)
|
||||
{
|
||||
enc_check = 1;
|
||||
decrypted_pdu = 0;
|
||||
}
|
||||
else if (slot == 1 && state->dmr_soR == 0x100)
|
||||
{
|
||||
enc_check = 1;
|
||||
decrypted_pdu = 0;
|
||||
}
|
||||
|
||||
//decode PDU
|
||||
if (enc_check == 1 && decrypted_pdu == 0) //check for encryption and if it was decrypted first or not
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "\n Slot %d - Encrypted Data Packet;", slot+1);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
else if (CRCCorrect || opts->aggressive_framesync == 0)
|
||||
{
|
||||
//may need to make adjustments for various compressed headers for starting point, etc?
|
||||
if (state->data_header_sap[slot] == 4) //IP based
|
||||
{
|
||||
uint16_t len = ((blocks+1)*block_len)-4; //total number of bytes in PDU minus 4 CRC32 bytes
|
||||
dmr_ip_pdu (opts, state, len, state->dmr_pdu_sf[slot]);
|
||||
}
|
||||
else if (state->data_header_sap[slot] == 10) //short data, may also need to check for SD:D [DD_HEAD]
|
||||
{
|
||||
uint16_t len = ((blocks+1)*block_len)-4; //total number of bytes in PDU minus 4 CRC32 bytes
|
||||
dmr_sd_pdu (opts, state, len, state->dmr_pdu_sf[slot]);
|
||||
}
|
||||
else if (state->data_header_sap[slot] == 2 || state->data_header_sap[slot] == 3) //TCP and UDP Compression (may only be 3 UDP compression, unknown)
|
||||
{
|
||||
uint16_t len = ((blocks+1)*block_len)-4; //total number of bytes in PDU minus 4 CRC32 bytes
|
||||
dmr_udp_comp_pdu (opts, state, len, state->dmr_pdu_sf[slot]);
|
||||
}
|
||||
}
|
||||
|
||||
if (CRCCorrect) ; //print nothing
|
||||
else
|
||||
@@ -792,7 +859,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
for (i = 0; i < ((blocks+1)*block_len); i++)
|
||||
{
|
||||
if ( (i != 0) && (i % 12 == 0) ) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
|
||||
fprintf (stderr, "%02X", state->dmr_pdu_sf[slot][i]);
|
||||
}
|
||||
|
||||
//debug print
|
||||
@@ -973,7 +1040,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
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]);
|
||||
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 ");
|
||||
@@ -1054,6 +1121,7 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
||||
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, 1, sizeof(state->data_block_counter));
|
||||
memset (state->data_block_poc, 0, sizeof(state->data_block_poc));
|
||||
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));
|
||||
|
||||
249
src/dmr_pdu.c
249
src/dmr_pdu.c
@@ -23,6 +23,255 @@ void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR
|
||||
|
||||
}
|
||||
|
||||
void utf16_to_text (uint16_t len, uint8_t * input)
|
||||
{
|
||||
len -= 36; //offset for starting point + 1
|
||||
fprintf (stderr, "\n UTF16 Text: ");
|
||||
uint16_t ch16 = 0;
|
||||
for (uint16_t i = 0; i < len; i += 2)
|
||||
{
|
||||
ch16 = (uint16_t)input[i+0];
|
||||
ch16 <<= 8;
|
||||
ch16 |= (uint16_t)input[i+1];
|
||||
// fprintf (stderr, " %04X; ", ch16); //debug for raw values to check grouping for offset
|
||||
|
||||
if (ch16 >= 0x20) //if not a linebreak or terminal commmands
|
||||
fprintf (stderr, "%lc", ch16);
|
||||
else if (ch16 == 0) //if padding (0 could also indicate end of text terminator?)
|
||||
fprintf (stderr, "_");
|
||||
else fprintf (stderr, "-");
|
||||
}
|
||||
}
|
||||
|
||||
void utf8_to_text (uint16_t len, uint8_t * input)
|
||||
{
|
||||
len -= 24;
|
||||
fprintf (stderr, "\n UTF8 Text: ");
|
||||
for (uint16_t i = 0; i < len; i++)
|
||||
{
|
||||
if (input[i] >= 0x20 && input[i] < 0x80) //if not a linebreak or terminal commmands
|
||||
fprintf (stderr, "%c", input[i]);
|
||||
else if (input[i] == 0) //if padding (0 could also indicate end of text terminator?)
|
||||
fprintf (stderr, "_");
|
||||
else if (input[i] == 0x03) //ASCII end of text (observed on the NMEA LOCN ones anyways)
|
||||
break;
|
||||
else fprintf (stderr, "-");
|
||||
}
|
||||
}
|
||||
|
||||
void dmr_sd_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU)
|
||||
{
|
||||
|
||||
// if (DMR_PDU[0] == 0x01) //may not be needed now, unknown
|
||||
{
|
||||
utf8_to_text(len, DMR_PDU+23);
|
||||
dmr_locn(opts, state, len, DMR_PDU); //may need to figure out the actual len of each block?
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//reading ETSI, seems like these aren't compressed, just that they are preset indexed values on the radio
|
||||
void dmr_udp_comp_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU)
|
||||
{
|
||||
UNUSED(opts); UNUSED(state);
|
||||
uint16_t ipid = (DMR_PDU[0] << 8) | DMR_PDU[1];
|
||||
uint16_t said = (DMR_PDU[2] >> 4) & 0xF;
|
||||
uint16_t daid = (DMR_PDU[2] >> 0) & 0xF;
|
||||
|
||||
//the manual shows this is the lsb and msb of the header compression 'opcode', but only zero is defined
|
||||
uint8_t op1 = (DMR_PDU[3] >> 7) & 1;
|
||||
uint8_t op2 = (DMR_PDU[4] >> 7) & 1;
|
||||
uint8_t opcode = (op1 << 1) | op2;
|
||||
|
||||
uint8_t spid = (DMR_PDU[3] >> 0) & 0x7F;
|
||||
uint8_t dpid = (DMR_PDU[4] >> 0) & 0x7F;
|
||||
|
||||
//configure SAID / DAID string
|
||||
char addrstring[2][35]; memset(addrstring, 0, sizeof(addrstring));
|
||||
|
||||
//said
|
||||
if (said == 0)
|
||||
sprintf (addrstring[0], "%s", "Radio Network");
|
||||
else if (said == 1)
|
||||
sprintf (addrstring[0], "%s", "Ethernet");
|
||||
else if (said > 1 && said < 11)
|
||||
sprintf (addrstring[0], "%s", "Reserved");
|
||||
else
|
||||
sprintf (addrstring[0], "%s", "Manufacturer Specific");
|
||||
|
||||
//daid
|
||||
if (daid == 0)
|
||||
sprintf (addrstring[1], "%s", "Radio Network");
|
||||
else if (daid == 1)
|
||||
sprintf (addrstring[1], "%s", "Ethernet");
|
||||
else if (daid == 1)
|
||||
sprintf (addrstring[1], "%s", "Group Network");
|
||||
else if (daid > 2 && daid < 11)
|
||||
sprintf (addrstring[1], "%s", "Reserved");
|
||||
else
|
||||
sprintf (addrstring[1], "%s", "Manufacturer Specific");
|
||||
|
||||
//according to ETSI, if spid and/or dpid is zero, their respective port is defined in this header, otherwise, they are preset indexed values
|
||||
|
||||
//look for and set optional port values and the ptr value to start of data
|
||||
uint16_t ptr = 5;
|
||||
|
||||
if (spid == 0 && dpid == 0)
|
||||
{
|
||||
spid = (DMR_PDU[5] << 8) | DMR_PDU[6];
|
||||
dpid = (DMR_PDU[7] << 8) | DMR_PDU[8];
|
||||
ptr = 9;
|
||||
}
|
||||
else if (spid == 0)
|
||||
{
|
||||
spid = (DMR_PDU[5] << 8) | DMR_PDU[6];
|
||||
ptr = 7;
|
||||
}
|
||||
else if (dpid == 0)
|
||||
{
|
||||
dpid = (DMR_PDU[5] << 8) | DMR_PDU[6];
|
||||
ptr = 7;
|
||||
}
|
||||
else ptr = 5;
|
||||
|
||||
char portstring[2][35]; memset(portstring, 0, sizeof(portstring));
|
||||
|
||||
//spid
|
||||
if (spid == 1)
|
||||
{
|
||||
// spid = 5016;
|
||||
sprintf (portstring[0], "%s", "UTF-16BE Text Message");
|
||||
}
|
||||
else if (spid == 2)
|
||||
{
|
||||
// spid = 5017;
|
||||
sprintf (portstring[0], "%s", "Location Interface Protocol");
|
||||
}
|
||||
else if (spid > 2 && spid < 191)
|
||||
{
|
||||
// spid = spid;
|
||||
sprintf (portstring[0], "%s", "Reserved");
|
||||
}
|
||||
else
|
||||
{
|
||||
// spid = spid;
|
||||
sprintf (portstring[0], "%s", "Manufacturer Specific");
|
||||
}
|
||||
|
||||
//dpid
|
||||
if (dpid == 1)
|
||||
{
|
||||
// dpid = 5016;
|
||||
sprintf (portstring[1], "%s", "UTF-16BE Text Message");
|
||||
}
|
||||
else if (dpid == 2)
|
||||
{
|
||||
// dpid = 5017;
|
||||
sprintf (portstring[1], "%s", "Location Interface Protocol");
|
||||
}
|
||||
else if (dpid > 2 && dpid < 191)
|
||||
{
|
||||
// dpid = dpid;
|
||||
sprintf (portstring[1], "%s", "Reserved");
|
||||
}
|
||||
else
|
||||
{
|
||||
// dpid = dpid;
|
||||
sprintf (portstring[1], "%s", "Manufacturer Specific");
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n Compressed IP Idx: %d; Opcode: %d; Src Idx: %d (%s); Dst Idx: %d (%s); ", ipid, opcode, said, addrstring[0], daid, addrstring[1]);
|
||||
fprintf (stderr, "\n Src Port Idx: %d (%s); Dst Port Idx: %d (%s); ", spid, portstring[0], dpid, portstring[1]);
|
||||
|
||||
//decode known types
|
||||
if (spid == 1 || dpid == 1)
|
||||
utf16_to_text(len, DMR_PDU+ptr); //assumming text starts right at the ptr value
|
||||
else if (spid == 2 || dpid == 2)
|
||||
{
|
||||
//untested
|
||||
uint8_t DMR_PDU_bits[127*8]; memset(DMR_PDU_bits, 0, sizeof(DMR_PDU_bits));
|
||||
unpack_byte_array_into_bit_array(DMR_PDU+ptr, DMR_PDU_bits, (len-4-ptr)*sizeof(uint8_t));
|
||||
lip_protocol_decoder(opts, state, DMR_PDU_bits);
|
||||
}
|
||||
else fprintf (stderr, "Unknown Decode Format;");
|
||||
|
||||
}
|
||||
|
||||
void dmr_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU)
|
||||
{
|
||||
|
||||
UNUSED(opts); UNUSED(state);
|
||||
// uint8_t slot = state->currentslot;
|
||||
|
||||
//may need to look at sap value and determine the len of these addressing headers, etc
|
||||
//and make a ptr to the start of actual PDU content data
|
||||
// if (state->data_header_sap[slot] == 4)
|
||||
// {
|
||||
//adjust ptr, addressing type, etc
|
||||
// }
|
||||
|
||||
//take a look at the src, dst, and port indicated (assuming both ports will match)
|
||||
uint32_t add1 = (DMR_PDU[13] << 16) | (DMR_PDU[14] << 8) | DMR_PDU[15]; //The 0C or 0D indicator will usually tell if this is src or dst
|
||||
uint32_t add2 = (DMR_PDU[17] << 16) | (DMR_PDU[18] << 8) | DMR_PDU[19];
|
||||
uint16_t port1 = (DMR_PDU[20] << 8) | DMR_PDU[21];
|
||||
uint16_t port2 = (DMR_PDU[22] << 8) | DMR_PDU[23];
|
||||
fprintf (stderr, "\n %02X ADD1: %d; Port: %d; %02X ADD2: %d; Port: %d; Len: %d; ", DMR_PDU[12], add1, port1, DMR_PDU[16], add2, port2, len);
|
||||
|
||||
//Are DMR PDU types only dictated by Port Number? Or is this just the defaults when programmed?
|
||||
if (port1 == 231 && port2 == 231)
|
||||
{
|
||||
fprintf (stderr, "Cellocator;");
|
||||
}
|
||||
else if (port1 == 4001 && port2 == 4001)
|
||||
{
|
||||
fprintf (stderr, "LRRP;");
|
||||
dmr_lrrp (opts, state, len, DMR_PDU); //will len just work here? (make adjustments if needed)
|
||||
}
|
||||
else if (port1 == 4004 && port2 == 4004)
|
||||
{
|
||||
fprintf (stderr, "XCMP;"); //may choose to use || instead of &&, saw a mismatch port but one was for XCMP
|
||||
}
|
||||
else if (port1 == 4005 && port2 == 4005)
|
||||
{
|
||||
fprintf (stderr, "ARS;");
|
||||
}
|
||||
else if (port1 == 4007 && port2 == 4007)
|
||||
{
|
||||
fprintf (stderr, "TMS;");
|
||||
utf16_to_text(len, DMR_PDU+35);
|
||||
}
|
||||
else if (port1 == 4008 && port2 == 4008)
|
||||
{
|
||||
fprintf (stderr, "Telemetry;");
|
||||
}
|
||||
else if (port1 == 4009 && port2 == 4009)
|
||||
{
|
||||
fprintf (stderr, "OTAP;");
|
||||
}
|
||||
else if (port1 == 4012 && port2 == 4012)
|
||||
{
|
||||
fprintf (stderr, "Battery Management;");
|
||||
}
|
||||
else if (port1 == 4013 && port2 == 4013)
|
||||
{
|
||||
fprintf (stderr, "Job Ticket Server;");
|
||||
}
|
||||
//ETSI specific
|
||||
else if (port1 == 5016 && port2 == 5016)
|
||||
{
|
||||
fprintf (stderr, "TMS;");
|
||||
utf16_to_text(len, DMR_PDU+35);
|
||||
}
|
||||
else if (port1 == 5017 && port2 == 5017)
|
||||
{
|
||||
uint8_t DMR_PDU_bits[127*8]; memset(DMR_PDU_bits, 0, sizeof(DMR_PDU_bits));
|
||||
unpack_byte_array_into_bit_array(DMR_PDU+35, DMR_PDU_bits, (len-4-35)*sizeof(uint8_t));
|
||||
lip_protocol_decoder(opts, state, DMR_PDU_bits);
|
||||
}
|
||||
else fprintf (stderr, "Unknown PDU Contents;");
|
||||
|
||||
}
|
||||
|
||||
//The contents of this function are mostly my reversed engineered efforts by observing DSDPlus output and matching data bytes
|
||||
//combined with a few external sources such as OK-DMR for some token values and extra data values (rad and alt)
|
||||
//this is by no means an extensive LRRP list and is prone to error (unless somebody has the manual or something)
|
||||
|
||||
@@ -365,6 +365,8 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->data_block_counter[1] = 1;
|
||||
state->data_p_head[0] = 0;
|
||||
state->data_p_head[1] = 0;
|
||||
state->data_block_poc[0] = 0;
|
||||
state->data_block_poc[1] = 0;
|
||||
|
||||
state->dmr_encL = 0;
|
||||
state->dmr_encR = 0;
|
||||
@@ -1034,6 +1036,8 @@ initState (dsd_state * state)
|
||||
state->data_block_counter[1] = 1;
|
||||
state->data_p_head[0] = 0;
|
||||
state->data_p_head[1] = 0;
|
||||
state->data_block_poc[0] = 0;
|
||||
state->data_block_poc[1] = 0;
|
||||
|
||||
state->menuopen = 0; //is the ncurses menu open, if so, don't process frame sync
|
||||
|
||||
|
||||
Reference in New Issue
Block a user