mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-12 16:57:23 -05:00
P25 Moto Alias vPDU Working; Tweaks and Fixes;
This commit is contained in:
123
src/dsd_alias.c
123
src/dsd_alias.c
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
//Motorola P25 OTA Alias Decoding ripped/demistified from Ilya Smirnov's SDRTrunk Voodoo Code
|
||||
//Motorola P25 OTA Alias Decoding ripped/demystified from Ilya Smirnov's SDRTrunk Voodoo Code
|
||||
uint8_t moto_alias_lut[256] = {
|
||||
0xD2, 0xF6, 0xD4, 0x2B, 0x63, 0x49, 0x94, 0x5E, 0xA7, 0x5C, 0x70, 0x69, 0xF7, 0x08, 0xB1, 0x7D,
|
||||
0x38, 0xCF, 0xCC, 0xD8, 0x51, 0x8F, 0xD5, 0x93, 0x6A, 0xF3, 0xEF, 0x7E, 0xFB, 0x64, 0xF4, 0x35,
|
||||
@@ -93,7 +93,9 @@ void apx_embedded_alias_header_phase1 (dsd_opts * opts, dsd_state * state, uint8
|
||||
|
||||
UNUSED(opts);
|
||||
uint8_t ta_len = (uint8_t)ConvertBitIntoBytes(&lc_bits[32], 8); //len in blocks of associated talker alias
|
||||
fprintf (stderr, " Block Len: %d;", ta_len);
|
||||
uint8_t sn = (uint8_t)ConvertBitIntoBytes(&lc_bits[56], 4);
|
||||
fprintf (stderr, " SN: %X;", sn);
|
||||
fprintf (stderr, " BN: 0/%d;", ta_len);
|
||||
|
||||
//use dmr_pdu_sf for storage, store entire header (will be used to verify complete reception of full alias)
|
||||
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot])); //reset storage for header and blocks
|
||||
@@ -138,13 +140,35 @@ void apx_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8
|
||||
if (ta_len == bn) //this is the last block, proceed to decoding
|
||||
{
|
||||
|
||||
int16_t num_bits = bn * 44; //number of relevant data bits total from all blocks (not including header)
|
||||
//WIP: Need a way to calculate variable len bits determined by a bit counter or something
|
||||
// int16_t num_bits = bn * 44; //number of relevant data bits total from all blocks (not including header)
|
||||
int16_t num_bits = 56; //starting value is the static bit count on the fqsuid
|
||||
|
||||
// //evaluate the storage and determine how many octets/bits are present at this point (fall back to this if needed)
|
||||
// for (int16_t i = 0; i < 31; i++) //end point? BEE00 doesn't trip this since it is 0xBE 0xE0 0x0X, but other things might, may want to start after the fqsuid
|
||||
// {
|
||||
// uint8_t byte = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][72+56+(i*8)], 8);
|
||||
// if (byte == 0)
|
||||
// break;
|
||||
// else
|
||||
// num_bits += 8;
|
||||
// }
|
||||
|
||||
//evaluate the storage and determine how many octets/bits are present at this point (expanded to two octets each, CRC with a 00xx pattern failed this)
|
||||
for (int16_t i = 0; i < 31; i++) //end point? BEE00 doesn't trip this since it is 0xBE 0xE0 0x0X, but other things might, may want to start after the fqsuid
|
||||
{
|
||||
uint16_t bytes = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][72+56+(i*16)], 16);
|
||||
if (bytes == 0)
|
||||
break;
|
||||
else
|
||||
num_bits += 16;
|
||||
}
|
||||
|
||||
//pass to alias decoder
|
||||
apx_embedded_alias_decode (opts, state, slot, num_bits, state->dmr_pdu_sf[slot]);
|
||||
|
||||
//clear out now stale storage
|
||||
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot]));
|
||||
memset (state->dmr_pdu_sf[slot], 0, sizeof(state->dmr_pdu_sf[slot]));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -152,37 +176,56 @@ void apx_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8
|
||||
|
||||
void apx_embedded_alias_header_phase2 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits)
|
||||
{
|
||||
//TODO: Adjust values as needed for MAC vPDU Messages
|
||||
|
||||
UNUSED(opts);
|
||||
uint8_t ta_len = (uint8_t)ConvertBitIntoBytes(&lc_bits[32], 8); //adjust when samples arrive with this in them
|
||||
fprintf (stderr, " Block Len: %d;", ta_len);
|
||||
uint8_t ta_len = (uint8_t)ConvertBitIntoBytes(&lc_bits[40], 8);
|
||||
uint8_t sn = (uint8_t)ConvertBitIntoBytes(&lc_bits[64], 4);
|
||||
uint8_t bn = (uint8_t)ConvertBitIntoBytes(&lc_bits[56], 8);
|
||||
fprintf (stderr, " SN: %X;", sn); //NOTE: vPDU header is also a partial block, and has a block num and SN value in it
|
||||
fprintf (stderr, " BN: %d/%d;", bn, ta_len);
|
||||
|
||||
//bit array to rearrange input lc_bits from phase 2 mac to match the phase 1 header and block handling
|
||||
uint8_t bits[136]; memset(bits, 0, sizeof(bits));
|
||||
memcpy (bits, lc_bits, 2*8*sizeof(uint8_t)); //header 0x9190
|
||||
memcpy (bits+16, lc_bits+24, 4*8*sizeof(uint8_t)); //BN, SN, etc
|
||||
memcpy (bits+56, lc_bits+56, 10*8*sizeof(uint8_t)); //adding 8 bits of extra padding here
|
||||
|
||||
int16_t alias_st = 136; //start of the encoded alias (the copied size of this header, basically)
|
||||
|
||||
//debug, dump header arranged at this end
|
||||
// fprintf (stderr, " Header: ");
|
||||
// for (int16_t i = 0; i < alias_st/8; i++) //double check and adjust
|
||||
// fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&bits[0+(i*8)], 8));
|
||||
|
||||
//use dmr_pdu_sf for storage, store entire header (will be used to verify complete reception of full alias)
|
||||
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot])); //reset storage for header and blocks
|
||||
memcpy (state->dmr_pdu_sf[slot], lc_bits, 72*sizeof(uint8_t));
|
||||
memcpy (state->dmr_pdu_sf[slot], bits, alias_st*sizeof(uint8_t)); //this header block has 128 bits of relevant data (through the fqsuid)
|
||||
|
||||
}
|
||||
|
||||
void apx_embedded_alias_blocks_phase2 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits)
|
||||
{
|
||||
//TODO: Adjust values as needed for MAC vPDU Messages
|
||||
//WIP: Adjust values as needed for MAC vPDU Messages
|
||||
UNUSED(opts);
|
||||
uint8_t bn = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //current block number
|
||||
uint8_t sn = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 4); //is a static value on all block sequences
|
||||
int16_t rel_bits = 100; //number of relevant bits in each block
|
||||
int16_t rel_st = 36; //start of relevant bits in this block
|
||||
int16_t alias_st = 136; //start of the encoded alias
|
||||
uint8_t bn = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 8); //current block number
|
||||
uint8_t sn = (uint8_t)ConvertBitIntoBytes(&lc_bits[32], 4); //is a static value on all block sequences
|
||||
uint8_t ta_len = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][32], 8); //len in blocks pulled from stored header
|
||||
uint16_t header = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][0], 16); //header check, should be 0x1590
|
||||
uint16_t header = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][0], 16); //header check, should be 0x9190
|
||||
|
||||
if (ta_len == 0 || header != 0x1590) //checkdown, make sure we have an up to date header for this with a good len value
|
||||
if (ta_len == 0 || header != 0x9190)
|
||||
{
|
||||
fprintf (stderr, " Missing Header");
|
||||
fprintf (stderr, " BN: %d/??;", bn);
|
||||
fprintf (stderr, " SN: %X;", sn);
|
||||
fprintf (stderr, " Partial: ");
|
||||
for (uint8_t i = 7; i < 18; i++) //Fix this value when samples arrive
|
||||
for (uint8_t i = 9; i < 32; i++) //double check and adjust
|
||||
fprintf (stderr, "%0X", (uint8_t)ConvertBitIntoBytes(&lc_bits[0+(i*4)], 4));
|
||||
|
||||
//clear out now stale storage
|
||||
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot]));
|
||||
memset (state->dmr_pdu_sf[slot], 0, sizeof(state->dmr_pdu_sf[slot]));
|
||||
}
|
||||
|
||||
else //good len and header stored
|
||||
@@ -194,14 +237,40 @@ void apx_embedded_alias_blocks_phase2 (dsd_opts * opts, dsd_state * state, uint8
|
||||
fprintf (stderr, " SN: %X;", sn);
|
||||
fprintf (stderr, " BN: %d/%d;", bn, ta_len);
|
||||
|
||||
//use dmr_pdu_sf for storage, store data relevant portion at ptr of (bn-1) * 44 + 72 offset for header
|
||||
memcpy(state->dmr_pdu_sf[slot]+(((bn-1)*44)+72), lc_bits+28, 44*sizeof(uint8_t)); //Fix this value when samples arrive
|
||||
//use dmr_pdu_sf for storage, store data relevant portion at ptr calculated below
|
||||
memcpy(state->dmr_pdu_sf[slot]+(alias_st+((bn-1)*rel_bits)), lc_bits+rel_st, rel_bits*sizeof(uint8_t)); //Fix this value when samples arrive
|
||||
|
||||
//debug, dump accumulated data at this end
|
||||
// fprintf (stderr, " Accumulated: ");
|
||||
// for (int16_t i = 0; i < (alias_st+(rel_bits*bn))/8; i++) //double check and adjust
|
||||
// fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][0+(i*8)], 8));
|
||||
|
||||
if (ta_len == bn) //this is the last block, proceed to decoding
|
||||
{
|
||||
|
||||
//Fix this value when samples arrive
|
||||
int16_t num_bits = bn * 48; //number of relevant data bits total from all blocks (not including header)
|
||||
//WIP: Need a way to calculate variable len bits determined by a bit counter or something
|
||||
// int16_t num_bits = (bn * rel_bits) + 56; //number of relevant data bits total from all blocks (including header fqsuid stub)
|
||||
int16_t num_bits = 56; //starting value is the static bit count on the fqsuid
|
||||
|
||||
// //evaluate the storage and determine how many octets/bits are present at this point (fall back to this if needed)
|
||||
// for (int16_t i = 0; i < 31; i++) //end point? BEE00 doesn't trip this since it is 0xBE 0xE0 0x0X, but other things might, may want to start after the fqsuid
|
||||
// {
|
||||
// uint8_t byte = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][72+56+(i*8)], 8);
|
||||
// if (byte == 0)
|
||||
// break;
|
||||
// else
|
||||
// num_bits += 8;
|
||||
// }
|
||||
|
||||
//evaluate the storage and determine how many octets/bits are present at this point (expanded to two octets each, CRC with a 00xx pattern failed this)
|
||||
for (int16_t i = 0; i < 31; i++) //end point? BEE00 doesn't trip this since it is 0xBE 0xE0 0x0X, but other things might, may want to start after the fqsuid
|
||||
{
|
||||
uint16_t bytes = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][72+56+(i*16)], 16);
|
||||
if (bytes == 0)
|
||||
break;
|
||||
else
|
||||
num_bits += 16;
|
||||
}
|
||||
|
||||
//pass to alias decoder
|
||||
apx_embedded_alias_decode (opts, state, slot, num_bits, state->dmr_pdu_sf[slot]);
|
||||
@@ -220,9 +289,6 @@ void apx_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot
|
||||
UNUSED(state);
|
||||
UNUSED(slot);
|
||||
|
||||
//debug, let's look at byte, bit counts and see if we can find this in the completed dump
|
||||
// fprintf (stderr, " Bits: %X; Bytes: %X; Mod: %d; ", num_bits, num_bits/8, num_bits%8);
|
||||
|
||||
//debug, dump completed data set
|
||||
// fprintf (stderr, "\n Full: ");
|
||||
// for (int16_t i = 0; i < (72+num_bits)/4; i++)
|
||||
@@ -250,7 +316,7 @@ void apx_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot
|
||||
uint32_t rid = (uint32_t)ConvertBitIntoBytes(&input[104], 24);
|
||||
|
||||
//print fully qualified SUID
|
||||
fprintf (stderr, "\n FQ-SUID: %05X.%03X.%X (%d);", wacn, sys, rid, rid);
|
||||
fprintf (stderr, "\n FQ-SUID: %05X.%03X.%06X (%d);", wacn, sys, rid, rid);
|
||||
|
||||
//WIP: Working, needs more samples to verify various num_bits values
|
||||
uint16_t ptr = 128; //starting point of encoded data from test vectors
|
||||
@@ -314,10 +380,17 @@ void apx_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot
|
||||
for (int16_t i = 0; i < num_bytes/2; i++)
|
||||
fprintf (stderr, "%lc", ((decoded[(i*2)+0])<<8) | ((decoded[(i*2)+1])<<0) );
|
||||
|
||||
//For Ncurses Display (needs to be testing on real samples first to make sure this is setup right)
|
||||
// memcpy (state->dmr_embedded_gps[slot], decoded, bytes*sizeof(uint8_t));
|
||||
//For Ncurses Display (needs to be testing on real samples first to make sure this is setup right, %s doesn't seem to work well with utf16)
|
||||
// memcpy (state->dmr_embedded_gps[slot], decoded, num_bytes*sizeof(uint8_t));
|
||||
// state->dmr_embedded_gps[slot][199] = '\0'; //terminate string
|
||||
|
||||
//For Ncurses Display (kind of a hack, but will only work if the UTF16 chars are just roman alphanumerical UTF8 compatible)
|
||||
for (int16_t i = 0; i < num_bytes/2; i++)
|
||||
state->dmr_embedded_gps[slot][i] = decoded[(i*2)+1];
|
||||
|
||||
//TODO: Do this like the Harris Talker Alias so it
|
||||
//can read/write to the files and not randomly reset
|
||||
//and flicker each time its decoded
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
|
||||
else if (lc_mfid == 0x90 && lc_opcode == 0x17)
|
||||
{
|
||||
fprintf (stderr, " MFID90 (Moto) Talker Alias Block");
|
||||
fprintf (stderr, " MFID90 (Moto) Talker Alias Blocks");
|
||||
apx_embedded_alias_blocks_phase1 (opts, state, 0, LCW_bits);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ static const uint8_t mac_msg_len[256] = {
|
||||
0, 14, 15, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //2F
|
||||
5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //3F
|
||||
9, 7, 9, 0, 9, 8, 9, 0, 10, 10, 9, 0, 10, 0, 0, 0, //4F
|
||||
0, 0, 0, 0, 9, 7, 0, 0, 10, 0, 7, 9, 10, 8, 14, 9, //5F (5B was 0, 5F was 7, changed both to 9 to match LCW, but that may not be completely accurate)
|
||||
0, 0, 0, 0, 9, 7, 0, 0, 10, 0, 7, 0, 10, 8, 14, 7, //5F //reverted previous changes here
|
||||
9, 9, 0, 0, 9, 0, 0, 9, 10, 0, 7, 10, 10, 7, 0, 9, //6F
|
||||
9, 29, 9, 9, 9, 9, 10, 13, 9, 9, 9, 11, 9, 9, 0, 0, //7F
|
||||
8, 18, 0, 7, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, //8F (needed to add 81 and 8f for Harris)
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //9F
|
||||
0, 17, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //9F // 0x91 and 0x95 manualy set to 17 (moto)
|
||||
16, 0, 0, 11, 13, 11, 11, 11, 10, 0, 0, 0, 0, 0, 0, 0, //AF
|
||||
17, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //BF, B0 was 0, set to 17 (Harris again), B5 Tait 0, set to 5
|
||||
11, 0, 0, 8, 15, 12, 15, 32, 12, 12, 0, 27, 14, 29, 29, 32, //CF
|
||||
@@ -1634,23 +1634,27 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n MFID90 Group Regroup Add Command ");
|
||||
}
|
||||
|
||||
//look for these in logs (these may need a corrected value set for 5B and 5F in len table)
|
||||
if (MAC[1+len_a] == 0x5B && MAC[2+len_a] == 0x90)
|
||||
//the len on these indicate they are always a single messages, foregoing the +len_a index pointer
|
||||
if (MAC[1] == 0x91 && MAC[2] == 0x90)
|
||||
{
|
||||
uint8_t len = MAC[3+len_a];
|
||||
uint8_t len = MAC[3]; //this indication is correct, 0x11, or 17 octets including opcode and mfid
|
||||
uint8_t mac_bits[24*8]; memset (mac_bits, 0, sizeof(mac_bits));
|
||||
unpack_byte_array_into_bit_array((uint8_t *)MAC+len_a, mac_bits, len);
|
||||
fprintf (stderr, " MFID90 (Moto) Talker Alias Header");
|
||||
// apx_embedded_alias_header_phase2 (opts, state, state->currentslot, mac_bits);
|
||||
uint8_t bytes[24]; memset (bytes, 0, sizeof(bytes));
|
||||
for (int i = 0; i < 24; i++) bytes[i] = (uint8_t)MAC[i];
|
||||
unpack_byte_array_into_bit_array(bytes+1, mac_bits, len);
|
||||
fprintf (stderr, "\n MFID90 (Moto) Talker Alias Header");
|
||||
apx_embedded_alias_header_phase2 (opts, state, state->currentslot, mac_bits);
|
||||
}
|
||||
|
||||
if (MAC[1+len_a] == 0x5F && MAC[2+len_a] == 0x90)
|
||||
if (MAC[1] == 0x95 && MAC[2] == 0x90)
|
||||
{
|
||||
uint8_t len = MAC[3+len_a];
|
||||
uint8_t len = MAC[3]; //this indication is correct, 0x11, or 17 octets including opcode and mfid
|
||||
uint8_t mac_bits[24*8]; memset (mac_bits, 0, sizeof(mac_bits));
|
||||
unpack_byte_array_into_bit_array((uint8_t *)MAC+len_a, mac_bits, len);
|
||||
fprintf (stderr, " MFID90 (Moto) Talker Alias Block");
|
||||
// apx_embedded_alias_blocks_phase2 (opts, state, state->currentslot, mac_bits);
|
||||
uint8_t bytes[24]; memset (bytes, 0, sizeof(bytes));
|
||||
for (int i = 0; i < 24; i++) bytes[i] = (uint8_t)MAC[i];
|
||||
unpack_byte_array_into_bit_array(bytes+1, mac_bits, len);
|
||||
fprintf (stderr, "\n MFID90 (Moto) Talker Alias Blocks");
|
||||
apx_embedded_alias_blocks_phase2 (opts, state, state->currentslot, mac_bits);
|
||||
}
|
||||
|
||||
//System Service Broadcast
|
||||
|
||||
Reference in New Issue
Block a user