From ed1d1d630ce79db890bbf4b890317341bc5aa580 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Sat, 28 Mar 2026 11:54:16 -0400 Subject: [PATCH] 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; --- src/dmr_pdu.c | 6 ++++ src/dsd_gps.c | 28 +++++++++++-------- src/nxdn_element.c | 26 +++++++++++++++++- src/p25p1_tsbk.c | 68 +++++++++++++++++++++++++++++----------------- src/p25p2_vpdu.c | 25 +++++++++++++++++ 5 files changed, 115 insertions(+), 38 deletions(-) diff --git a/src/dmr_pdu.c b/src/dmr_pdu.c index 3973f3a..4535ef9 100644 --- a/src/dmr_pdu.c +++ b/src/dmr_pdu.c @@ -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; ", diff --git a/src/dsd_gps.c b/src/dsd_gps.c index 87f4bb6..0f13e17 100644 --- a/src/dsd_gps.c +++ b/src/dsd_gps.c @@ -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(); diff --git a/src/nxdn_element.c b/src/nxdn_element.c index cf6afbb..331c9f3 100644 --- a/src/nxdn_element.c +++ b/src/nxdn_element.c @@ -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 diff --git a/src/p25p1_tsbk.c b/src/p25p1_tsbk.c index 3682265..8e0af75 100644 --- a/src/p25p1_tsbk.c +++ b/src/p25p1_tsbk.c @@ -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"); diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c index 9c4a5e6..e54a4f9 100644 --- a/src/p25p2_vpdu.c +++ b/src/p25p2_vpdu.c @@ -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) {