NXDN: Add Event History entries for the GPS report, undecoded, and still encrypted Data Calls;

P25p1: Add / Fix Several TSBKs including Station ID and Extended Function Command; Add UDP Port Decode for EFJ Atlas Data Registration Server;
This commit is contained in:
lwvmobile
2026-03-28 11:54:16 -04:00
parent 56f6f6d78e
commit ed1d1d630c
5 changed files with 115 additions and 38 deletions

View File

@@ -521,6 +521,12 @@ void decode_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t *
lip_protocol_decoder(opts, state, bits);
}
//known P25 Ports
else if (port1 == 9361 && port2 == 9361)
{
sprintf (state->dmr_lrrp_gps[slot], "P25 Atlas SRC(IP): %d.%d.%d.%d; DST(IP): %d.%d.%d.%d; ",
input[12], input[13], input[14], input[15], input[16], input[17], input[18], input[19]);
fprintf (stderr, "Atlas Data Registration Server;"); //EF Johnson Atlas
}
else if (port1 == 49198 && port2 == 49198)
{
sprintf (state->dmr_lrrp_gps[slot], "P25 Tier 2 LOCN SRC(IP): %d.%d.%d.%d; DST(IP): %d.%d.%d.%d; ",

View File

@@ -724,12 +724,10 @@ void decode_ars(dsd_opts * opts, dsd_state * state, uint8_t * input, int len)
void nxdn_gps_report(dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src)
{
// Basic fields
// uint8_t quality = (uint8_t)convert_bits_into_output(input+8, 4); //can't seem to work these first two out correctly
// uint8_t num_sat = (uint8_t)convert_bits_into_output(input+12, 4); //can't seem to work these first two out correctly
//Elevation
int16_t elevation = (int16_t)convert_bits_into_output(input+56, 16);
// Speed & Heading (in tenths)
//Speed & Heading (in tenths)
uint16_t speed_raw = (uint16_t)convert_bits_into_output(input+74, 14);
uint16_t heading_raw = (uint16_t)convert_bits_into_output(input+92, 12);
double speed = speed_raw / 10.0; //knots or k/h
@@ -740,7 +738,7 @@ void nxdn_gps_report(dsd_opts * opts, dsd_state * state, uint8_t * input, uint32
uint8_t month = (uint8_t) convert_bits_into_output(input+143,4);
uint8_t day = (uint8_t)(convert_bits_into_output(input+147,5) + 1);
// Longitude (DDMM.mmmm format)
//Longitude (DDMM.mmmm format)
uint16_t lon_degmin = (uint16_t)convert_bits_into_output(input+152, 16);
uint16_t lon_frac = (uint16_t)convert_bits_into_output(input+16, 15);
uint8_t lon_hem = (uint8_t) convert_bits_into_output(input+183, 1);
@@ -748,7 +746,7 @@ void nxdn_gps_report(dsd_opts * opts, dsd_state * state, uint8_t * input, uint32
double lon_decimal = (lon_degmin / 100) + (lon_minutes / 60.0);
double longitude = (lon_hem == 0) ? lon_decimal : -lon_decimal;
// Latitude (DDMM.mmmm format)
//Latitude (DDMM.mmmm format)
uint16_t lat_degmin = (uint16_t)convert_bits_into_output(input+184,16);
uint16_t lat_frac = (uint16_t)convert_bits_into_output(input+200,15);
uint8_t lat_hem = (uint8_t) convert_bits_into_output(input+215,1);
@@ -757,9 +755,8 @@ void nxdn_gps_report(dsd_opts * opts, dsd_state * state, uint8_t * input, uint32
double latitude = (lat_hem == 0) ? lat_decimal : -lat_decimal;
//Time
// uint8_t hour = (uint8_t) convert_bits_into_output(input+247,5);
// uint8_t minute = (uint8_t) convert_bits_into_output(input+252,6);
// uint8_t second = (uint8_t) convert_bits_into_output(input+258,6); //this seems to be zero, recheck time
uint8_t hour = (uint8_t) convert_bits_into_output(input+247,5);
uint8_t minute = (uint8_t) convert_bits_into_output(input+252,6);
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
@@ -769,12 +766,19 @@ void nxdn_gps_report(dsd_opts * opts, dsd_state * state, uint8_t * input, uint32
fprintf (stderr, "Speed: %lf k/h; ", speed);
fprintf (stderr, "COG: %lf; ", heading);
fprintf (stderr, "Elevation: %i; ", elevation);
// fprintf (stderr, "Quality: %d / %d; ", quality, num_sat);
fprintf (stderr, "Date: %04d/%02d/%02d ", year, month, day);
// fprintf (stderr, "Time: %02d:%02d:%02d ", hour, minute, second);
fprintf (stderr, "Time: %02d:%02d ", hour, minute);
//dump to event history
sprintf (state->event_history_s[0].Event_History_Items[0].gps_s, "(%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
uint32_t source = state->dmr_lrrp_source[0];
uint32_t target = state->dmr_lrrp_target[0];
char comp_string[500]; memset (comp_string, 0, sizeof(comp_string));
sprintf (comp_string, "GPS SRC: %d; TGT: %d;", source, target);
watchdog_event_datacall (opts, state, source, target, comp_string, 0);
//save to LRRP report for mapping/logging
if (opts->lrrp_file_output == 1 && src != 0) //&& quality?
if (opts->lrrp_file_output == 1 && src != 0)
{
char * datestr = getDateS();

View File

@@ -2964,15 +2964,39 @@ int nxdn_dcall_data(dsd_opts * opts, dsd_state * state, int type, uint8_t * Mess
nxdn_gps_report(opts, state, reverse_byte_bits+16, state->dmr_lrrp_source[0]);
}
// else if (0 == 1) //future case
// {
// uint8_t bytes[total_bytes];
// memset(bytes, 0, sizeof(bytes));
// for (int i = 0; i < total_bytes-4; i++)
// bytes[i] = (uint8_t)ConvertBitIntoBytes(state->dmr_pdu_sf[0]+(i*8), 8);
// }
else
{
//Anything else?
//dump to event history as generic data call with no decode
sprintf (state->event_history_s[0].Event_History_Items[0].text_message, "Unknown Data Call Format: %04X;", (uint16_t)ConvertBitIntoBytes(state->dmr_pdu_sf[0], 16));
uint32_t source = state->dmr_lrrp_source[0];
uint32_t target = state->dmr_lrrp_target[0];
char comp_string[500]; memset (comp_string, 0, sizeof(comp_string));
sprintf (comp_string, "DATA CALL SRC: %d; TGT: %d;", source, target);
watchdog_event_datacall (opts, state, source, target, comp_string, 0);
}
}
else
{
fprintf (stderr, " CRC: %08X / %08X;", crc_ext, crc_chk);
fprintf (stderr, " (CRC ERR) ");
//dump to event history as generic data call with no decode, if still encrypted, yielding bad CRC32
if (state->payload_algid != 0)
{
sprintf (state->event_history_s[0].Event_History_Items[0].text_message, "Encrypted PDU; Cipher: %d; KID: %02X;", state->payload_algid, state->payload_keyid);
uint32_t source = state->dmr_lrrp_source[0];
uint32_t target = state->dmr_lrrp_target[0];
char comp_string[500]; memset (comp_string, 0, sizeof(comp_string));
sprintf (comp_string, "DATA CALL SRC: %d; TGT: %d;", source, target);
watchdog_event_datacall (opts, state, source, target, comp_string, 0);
}
}
//clear storage

View File

@@ -489,11 +489,53 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
{
fprintf (stderr, "\n");
fprintf (stderr, "%s",KYEL);
fprintf (stderr, " MFID 90 (Moto) Acknoledge Response: ");
fprintf (stderr, " MFID 90 (Moto) Acknowledge Response: ");
for (i = 2; i < 10; i++)
fprintf (stderr, "%02X", tsbk_byte[i]);
}
else if ( (tsbk_byte[0] & 0x3F) == 0x09 )
{
fprintf (stderr, "\n");
fprintf (stderr, " MFID 90 (Moto) Scan Marker: ");
for (i = 2; i < 10; i++)
fprintf (stderr, "%02X", tsbk_byte[i]);
}
else if ( (tsbk_byte[0] & 0x3F) == 0x0B )
{
uint16_t channel = (tsbk_byte[8] << 8) | tsbk_byte[9];
fprintf (stderr, "\n");
fprintf (stderr, " MFID 90 (Moto) ID Channel: %04X;", channel);
char sid_string[10];
memset(sid_string, 0, sizeof(sid_string));
int k = 0;
if (tsbk_byte[2] != 0)
{
fprintf (stderr, " Station ID: ");
uint8_t sid_bits[42];
memset(sid_bits, 0, sizeof(sid_bits));
unpack_byte_array_into_bit_array(tsbk_byte+2, sid_bits, 6);
for (i = 0; i < 42; i+=6)
{
uint8_t bsi_char = convert_bits_into_output(sid_bits+i, 6) + 43;
if (bsi_char > 0x1F && bsi_char < 0x7F)
{
fprintf (stderr, "%c", bsi_char);
sid_string[k++] = bsi_char;
}
else break;
}
}
//debug, may assign this string to something else later on
// fprintf (stderr, " - Str: %s;", sid_string);
process_channel_to_freq(opts, state, channel);
}
//Some of these Opcodes that aren't found in any TIA manual come from SDRTrunk (or other sources),
//but can't verify the accuracy of their meaning/context
@@ -505,22 +547,6 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
// fprintf (stderr, "%02X", tsbk_byte[i]);
// }
// else if ( (tsbk_byte[0] & 0x3F) == 0x09 )
// {
// fprintf (stderr, "\n");
// fprintf (stderr, " MFID 90 (Moto) Channel Loading: "); //don't understand the context for this one, waiting on units to arrive on channel?
// for (i = 2; i < 10; i++)
// fprintf (stderr, "%02X", tsbk_byte[i]);
// }
// else if ( (tsbk_byte[0] & 0x3F) == 0x0B )
// {
// fprintf (stderr, "\n");
// fprintf (stderr, " MFID 90 (Moto) Control Channel: "); //this appears to echo the 16-bit channel number for the main control channel/RFSS
// for (i = 2; i < 10; i++)
// fprintf (stderr, "%02X", tsbk_byte[i]);
// }
// else if ( (tsbk_byte[0] & 0x3F) == 0x0E )
// {
// fprintf (stderr, "\n");
@@ -537,14 +563,6 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
// fprintf (stderr, "%02X", tsbk_byte[i]);
// }
// else if ( (tsbk_byte[0] & 0x3F) == 0x15 ) //noted on RR, but not observed as of yet, this may actualy be a LCW and not a TSBK?
// {
// fprintf (stderr, "\n");
// fprintf (stderr, " MFID 90 (Moto) Talker Alias: ");
// for (i = 2; i < 10; i++)
// fprintf (stderr, "%02X", tsbk_byte[i]);
// }
// else if ( (tsbk_byte[0] & 0x3F) == 0x16 )
// {
// fprintf (stderr, "\n");

View File

@@ -1628,6 +1628,31 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
}
//Extended Function Command - Abbreviated (Generic non MFID variant)
if (MAC[1+len_a] == 0x64)
{
uint8_t class = MAC[2+len_a];
uint8_t operand = MAC[3+len_a];
uint32_t argument = (MAC[4+len_a] << 16) | (MAC[5+len_a] << 8) | MAC[6+len_a];
uint32_t target = (MAC[7+len_a] << 16) | (MAC[8+len_a] << 8) | MAC[9+len_a];
fprintf (stderr, "\n Extended Function Command: Class: %02X; Operand: %02X; Arg/Src: %06X; Target: %d; ", class, operand, argument, target);
//WIP: Further Decode
if (class == 0)
{
if ((operand & 0x7F) == 0x00) fprintf (stderr, "Radio Check; ");
else if ((operand & 0x7F) == 0x7D) fprintf (stderr, "Radio Detach; ");
else if ((operand & 0x7F) == 0x7E) fprintf (stderr, "Radio Uninhibit; ");
else if ((operand & 0x7F) == 0x7F) fprintf (stderr, "Radio Inhibit; ");
else fprintf (stderr, "Reserved; ");
//MSB is an ack of the above command
if ((operand >> 7) == 1) fprintf (stderr, "Ack; ");
}
else fprintf (stderr, "Other Command; ");
}
//MFID90 Group Regroup Add Command
if (MAC[1+len_a] == 0x81 && MAC[2+len_a] == 0x90)
{