Files
dsd-fme/src/p25_lcw.c
2023-11-20 21:49:58 -05:00

513 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*-------------------------------------------------------------------------------
* p25_lcw.c
* P25p1 Link Control Word Decoding
*
* LWVMOBILE
* 2023-05 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
//new p25_lcw function here -- TIA-102.AABF-D LCW Format Messages (if anybody wants to fill the rest out)
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors)
{
UNUSED(irrecoverable_errors);
uint8_t lc_format = (uint8_t)ConvertBitIntoBytes(&LCW_bits[0], 8); //format
uint8_t lc_opcode = (uint8_t)ConvertBitIntoBytes(&LCW_bits[2], 6); //opcode portion of format
uint8_t lc_mfid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 8); //mfid
uint8_t lc_svcopt = (uint8_t)ConvertBitIntoBytes(&LCW_bits[16], 8); //service options
uint8_t lc_pf = LCW_bits[0]; //protect flag
uint8_t lc_sf = LCW_bits[1]; //Implicit / Explicit MFID Format
UNUSED2(lc_opcode, lc_sf);
if (lc_pf == 1) //check the protect flag -- if set, its an encrypted lcw
{
fprintf (stderr, "%s",KRED);
fprintf (stderr, " LCW Protected ");
fprintf (stderr, "%s",KNRM);
}
if (lc_pf == 0) //not protected/encrypted lcw
{
if (opts->payload == 1) fprintf (stderr, " LCW");
//check to see if we need to run these as MFID 0 or 1 only (standard)
if (lc_mfid == 0 || lc_mfid == 1) //lc_mfid == 0
{
//check the service options on applicable formats
if (lc_format == 0x4A || lc_format == 0x46 || lc_format == 0x45
|| lc_format == 0x44 || lc_format == 0x03 || lc_format == 0x00)
{
if (lc_svcopt & 0x80) fprintf (stderr, " Emergency");
if (lc_svcopt & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (lc_svcopt & 0x20) fprintf (stderr, " Duplex");
if (lc_svcopt & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (lc_svcopt & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", lc_svcopt & 0x7); //call priority
}
}
if (lc_format == 0x00)
{
fprintf (stderr, " Group Voice Channel User");
uint8_t res = (uint8_t)ConvertBitIntoBytes(&LCW_bits[24], 7);
uint8_t explicit = LCW_bits[24]; //explicit source id required == 1, full SUID on seperate LCW
uint16_t group = (uint16_t)ConvertBitIntoBytes(&LCW_bits[32], 16);
uint32_t source = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
fprintf (stderr, " - Group %d Source %d", group, source);
UNUSED2(res, explicit);
//don't set this when zero, annoying blink occurs in ncurses
if (group != 0) state->lasttg = group;
if (source != 0) state->lastsrc = source;
sprintf (state->call_string[0], " Group ");
if (lc_svcopt & 0x80) strcat (state->call_string[0], " Emergency ");
else if (lc_svcopt & 0x40) strcat (state->call_string[0], " Encrypted ");
else strcat (state->call_string[0], " ");
}
else if (lc_format == 0x03)
{
fprintf (stderr, " Unit to Unit Voice Channel User");
uint32_t target = (uint32_t)ConvertBitIntoBytes(&LCW_bits[24], 24);
uint32_t source = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
fprintf (stderr, " - Target %d Source %d", target, source);
//don't set this when zero, annoying blink occurs in ncurses
if (target != 0) state->lasttg = target;
if (source != 0) state->lastsrc = source;
sprintf (state->call_string[0], " Private ");
if (lc_svcopt & 0x80) strcat (state->call_string[0], " Emergency ");
else if (lc_svcopt & 0x40) strcat (state->call_string[0], " Encrypted ");
else strcat (state->call_string[0], " ");
}
//TODO: Allow Tuning from Call Grants either in LDU1 or TDULC? (TDMA to p1 fallback?)
//TODO: Allow TG Hold overrides here either in LDU1 or TDULC?
//NOTE: If we have an active TG hold, we really should't be here anyways
else if (lc_format == 0x42) //is this group only, or group and private?
{
fprintf (stderr, " Group Voice Channel Update - ");
uint16_t channel1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[8], 16);
uint16_t group1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[24], 16);
uint16_t channel2 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[40], 16);
uint16_t group2 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
if (channel1 && group1)
{
fprintf (stderr, "Ch: %04X TG: %d; ", channel1, group1);
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; ", channel1, group1);
state->last_active_time = time(NULL);
}
if (channel2 && group2 && group1 != group2)
{
fprintf (stderr, "Ch: %04X TG: %d; ", channel2, group2);
sprintf (state->active_channel[1], "Active Ch: %04X TG: %d; ", channel2, group2);
state->last_active_time = time(NULL);
}
}
else if (lc_format == 0x44)
{
fprintf (stderr, " Group Voice Channel Update – Explicit");
uint16_t group1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[24], 16);
uint16_t channelt = (uint16_t)ConvertBitIntoBytes(&LCW_bits[40], 16);
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
fprintf (stderr, "Ch: %04X TG: %d; ", channelt, group1);
UNUSED(channelr);
}
else if (lc_format == 0x45)
{
fprintf (stderr, " Unit to Unit Answer Request");
}
else if (lc_format == 0x46)
{
fprintf (stderr, " Telephone Interconnect Voice Channel User");
}
else if (lc_format == 0x47)
{
fprintf (stderr, " Telephone Interconnect Answer Request");
}
else if (lc_format == 0x49)
{
fprintf (stderr, " Souce ID Extension");
}
else if (lc_format == 0x4A)
{
fprintf (stderr, " Unit to Unit Voice Channel User – Extended");
uint32_t target = (uint32_t)ConvertBitIntoBytes(&LCW_bits[16], 24);
uint32_t suid = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 24);
fprintf (stderr, "TGT: %04X SUID: %d; ", target, suid);
}
else if (lc_format == 0x50)
{
fprintf (stderr, " Group Affiliation Query");
}
else if (lc_format == 0x51)
{
fprintf (stderr, " Unit Registration Command");
}
else if (lc_format == 0x52) //wonder if anybody uses this if its deleted/obsolete
{
fprintf (stderr, " Unit Authentication Command - OBSOLETE");
}
else if (lc_format == 0x53)
{
fprintf (stderr, " Status Query");
}
else if (lc_format == 0x54)
{
fprintf (stderr, " Status Update");
}
else if (lc_format == 0x55)
{
fprintf (stderr, " Status Update");
}
else if (lc_format == 0x56)
{
fprintf (stderr, " Call Alert");
}
else if (lc_format == 0x57)
{
fprintf (stderr, " Extended Function Command");
}
else if (lc_format == 0x58)
{
fprintf (stderr, " Channel Identifier Update");
}
else if (lc_format == 0x59)
{
fprintf (stderr, " Channel Identifier Update VU");
}
else if (lc_format == 0x5A)
{
fprintf (stderr, " Status Update – Source ID Extension Required");
}
else if (lc_format == 0x5C)
{
fprintf (stderr, " Extended Function Command – Source ID Extension Required");
}
else if (lc_format == 0x60)
{
fprintf (stderr, " System Service Broadcast");
}
else if (lc_format == 0x61)
{
fprintf (stderr, " Secondary Control Channel Broadcast");
}
else if (lc_format == 0x62)
{
fprintf (stderr, " Adjacent Site Status Broadcast");
}
else if (lc_format == 0x63)
{
fprintf (stderr, " RFSS Status Broadcast");
}
else if (lc_format == 0x64)
{
fprintf (stderr, " Network Status Broadcast");
}
else if (lc_format == 0x65)
{
fprintf (stderr, " Protection Parameter Broadcast - OBSOLETE");
}
else if (lc_format == 0x66)
{
fprintf (stderr, " Secondary Control Channel Broadcast – Explicit (LCSCBX)");
}
else if (lc_format == 0x67) //explicit
{
fprintf (stderr, " Adjacent Site Status (LCASBX)");
uint8_t lra = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 8);
uint16_t channelt = (uint16_t)ConvertBitIntoBytes(&LCW_bits[16], 16);
uint8_t rfssid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[32], 8);
uint8_t siteid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[40], 8);
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[48], 16);
uint8_t cfva = (uint8_t)ConvertBitIntoBytes(&LCW_bits[64], 4);
fprintf (stderr, " - RFSS %d Site %d CH %04X", rfssid, siteid, channelt);
UNUSED2(lra, channelr);
//debug print only
// fprintf (stderr, "\n ");
// fprintf (stderr, " LRA [%02X] RFSS [%03d] SITE [%03d] CHAN-T [%04X] CHAN-R [%02X] CFVA [%X]\n ", lra, rfssid, siteid, channelt, channelr, cfva);
// if (cfva & 0x8) fprintf (stderr, " Conventional");
// if (cfva & 0x4) fprintf (stderr, " Failure Condition");
// if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
// else fprintf (stderr, " Last Known");
if (cfva & 0x1) fprintf (stderr, " - Connection Active");
// process_channel_to_freq (opts, state, channelt);
//end debug, way too much for a simple link control line
}
else if (lc_format == 0x68)
{
fprintf (stderr, " RFSS Status Broadcast – Explicit (LCRSBX)");
}
else if (lc_format == 0x69)
{
fprintf (stderr, " Network Status Broadcast – Explicit (LCNSBX)");
}
else if (lc_format == 0x6A)
{
fprintf (stderr, " Conventional Fallback");
}
else if (lc_format == 0x6B)
{
fprintf (stderr, " Message Update – Source ID Extension Required");
}
//tune back to CC here - save about 1-2 seconds
else if (lc_format == 0x4F) //# Call Termination/Cancellation
{
fprintf (stderr, " Call Termination");
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
{
//Will we need to check for a symbolrate change here, can a P25p2 TDMA-CC system
//revert back to a phase 1 traffic channel or carry a phase 1 traffic channel?
//clear heuristics from current traffic channel
if (opts->frame_p25p1 == 1 && opts->use_heuristics == 1)
{
initialize_p25_heuristics(&state->p25_heuristics);
initialize_p25_heuristics(&state->inv_p25_heuristics);
}
//re-enable both slots (failsafe)
opts->slot1_on = 1;
opts->slot2_on = 1;
//rigctl
if (opts->use_rigctl == 1)
{
state->lasttg = 0;
state->lastsrc = 0;
state->payload_algid = 0;
state->payload_keyid = 0;
// state->payload_miP = 0;
//reset some strings
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
sprintf (state->active_channel[0], "%s", "");
sprintf (state->active_channel[1], "%s", "");
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
}
//rtl
else if (opts->audio_in_type == 3)
{
#ifdef USE_RTLSDR
state->lasttg = 0;
state->lastsrc = 0;
state->payload_algid = 0;
state->payload_keyid = 0;
// state->payload_miP = 0;
//reset some strings
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
sprintf (state->active_channel[0], "%s", "");
sprintf (state->active_channel[1], "%s", "");
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
rtl_dev_tune (opts, state->p25_cc_freq);
#endif
}
}
}
else fprintf (stderr, " Unknown Format %02X MFID %02X SVC %02X", lc_format, lc_mfid, lc_svcopt);
}
//MFID 90 Embedded GPS
else if (lc_mfid == 0x90 && lc_opcode == 0x6)
{
fprintf (stderr, " MFID90 (Moto)");
apx_embedded_gps (opts, state, LCW_bits);
}
else if (lc_mfid == 0x90 && lc_opcode == 0x0)
fprintf (stderr, " MFID90 (Moto) Group Regroup Channel User (LCGRGR)");
else if (lc_mfid == 0x90 && lc_opcode == 0x1)
fprintf (stderr, " MFID90 (Moto) Group Regroup Channel Update (LCGRGU)");
else if (lc_mfid == 0x90 && lc_opcode == 0x3)
fprintf (stderr, " MFID90 (Moto) Group Regroup Add");
else if (lc_mfid == 0x90 && lc_opcode == 0x4)
fprintf (stderr, " MFID90 (Moto) Group Regroup Delete");
else if (lc_mfid == 0x90 && lc_opcode == 0xF)
{
uint32_t src = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
fprintf (stderr, " MFID90 (Moto) Talker EOT; SRC: %d", src);
}
//not a duplicate, this one will print if not MFID 0 or 1
else
{
fprintf (stderr, " Unknown Format %02X MFID %02X ", lc_format, lc_mfid);
if (lc_mfid == 0x90) fprintf (stderr, "(Moto)");
else if (lc_mfid == 0xA4) fprintf (stderr, "(Harris)");
}
}
//ending line break
fprintf (stderr, "\n");
}
//This Function has been redone and variables fixed to mirror SDRTrunk
//my earlier assumption that this was the same format as DMR Embedded GPS was incorrect
void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " GPS:");
uint8_t slot = state->currentslot;
uint8_t pf = lc_bits[0];
uint8_t res_a = lc_bits[1];
uint8_t res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 7);
uint8_t expired = lc_bits[23]; //this bit seems to indicate that the GPS coordinates are out of date or fresh
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
uint32_t lon_sign = lc_bits[48];
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[49], 23);
uint32_t lat_sign = lc_bits[24];
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[25], 23);
//todo: acquire more samples for additional validation
double lat_unit = 90.0f / 0x7FFFFF;
double lon_unit = 180.0f / 0x7FFFFF;
double lon_sf = 1.0f; //float value we can multiple longitude with
double lat_sf = 1.0f; //float value we can multiple latitude with
char latstr[3];
char lonstr[3];
char valid[9];
sprintf (latstr, "%s", "N");
sprintf (lonstr, "%s", "E");
sprintf (valid, "%s", "Current");
double latitude = 0;
double longitude = 0;
if (pf) fprintf (stderr, " Protected");
else
{
if (lat_sign)
{
sprintf (latstr, "%s", "S");
lat_sf = -1.0f;
}
latitude = ((double)lat * lat_unit);
if (lon_sign)
{
sprintf (lonstr, "%s", "W");
lon_sf = -1.0f;
}
longitude = ((double)lon * lon_unit);
//sanity check
if (abs (latitude) < 90 && abs(longitude) < 180)
{
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf) ", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, latitude * lat_sf, longitude * lon_sf);
if (expired)
{
fprintf (stderr, "Expired; ");
sprintf (valid, "%s", "Expired");
}
else if (!expired)
fprintf (stderr, "Current; ");
if (res_a)
fprintf (stderr, "RES_A: %d; ", res_a);
if (res_b)
fprintf (stderr, "RES_B: %02X; ", res_b);
//save to array for ncurses
sprintf (state->dmr_embedded_gps[slot], "GPS: %lf%s%s %lf%s%s %s", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, valid);
//save to LRRP report for mapping/logging
FILE * pFile; //file pointer
if (opts->lrrp_file_output == 1)
{
int src = 0;
if (slot == 0) src = state->lasttg;
if (slot == 1) src = state->lasttgR;
//open file by name that is supplied in the ncurses terminal, or cli
pFile = fopen (opts->lrrp_out_file, "a");
fprintf (pFile, "%s\t", getDateL() );
fprintf (pFile, "%s\t", getTimeL() );
fprintf (pFile, "%08d\t", src);
fprintf (pFile, "%.5lf\t", latitude);
fprintf (pFile, "%.5lf\t", longitude);
fprintf (pFile, "0\t " ); //zero for velocity
fprintf (pFile, "0\t " ); //zero for azimuth
fprintf (pFile, "\n");
fclose (pFile);
}
}
}
fprintf (stderr, "%s", KNRM);
}