NXDN DFA Support;

This commit is contained in:
lwvmobile
2023-03-22 20:00:41 -04:00
parent b639f6af28
commit dc49e0d08b
5 changed files with 301 additions and 114 deletions

View File

@@ -654,11 +654,18 @@ typedef struct
uint8_t nxdn_sacch_frame_segcrc[4];
uint8_t nxdn_alias_block_number;
char nxdn_alias_block_segment[4][4][8];
//site/srv/cch info
char nxdn_location_category[14];
uint32_t nxdn_location_sys_code;
uint16_t nxdn_location_site_code;
//channel access information
uint8_t nxdn_rcn;
uint8_t nxdn_base_freq;
uint8_t nxdn_step;
uint8_t nxdn_bw;
//multi-key array
unsigned long long int rkey_array[0xFFFF];

View File

@@ -234,6 +234,12 @@ noCarrier (dsd_opts * opts, dsd_state * state)
state->nxdn_location_sys_code = 0;
sprintf (state->nxdn_location_category, "%s", " ");
//channel access information
state->nxdn_rcn = 0;
state->nxdn_base_freq = 0;
state->nxdn_step = 0;
state->nxdn_bw = 0;
//dmr mfid branding and site parms
sprintf(state->dmr_branding_sub, "%s", "");
sprintf(state->dmr_branding, "%s", "");
@@ -881,11 +887,18 @@ initState (dsd_state * state)
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
state->nxdn_alias_block_number = 0;
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
//site/srv/cch info
state->nxdn_location_site_code = 0;
state->nxdn_location_sys_code = 0;
sprintf (state->nxdn_location_category, "%s", " ");
//channel access information
state->nxdn_rcn = 0;
state->nxdn_base_freq = 0;
state->nxdn_step = 0;
state->nxdn_bw = 0;
//multi-key array
memset (state->rkey_array, 0, sizeof(state->rkey_array));

View File

@@ -2290,6 +2290,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("Site Code [%d] ", state->nxdn_location_site_code);
}
//if system supports Direct Frequency Assignment
if (state->nxdn_rcn == 1) printw ("DFA ");
printw ("\n");
printw ("| ");
printw ("TGT: [%5d] ", tgn);

View File

@@ -197,6 +197,153 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
} /* End NXDN_Elements_Content_decode() */
//externalize multiple sub-element handlers
void nxdn_location_id_handler (dsd_state * state, uint32_t location_id)
{
//6.5.2 Location ID
uint8_t category_bit = location_id >> 22;
uint32_t sys_code = 0;
uint16_t site_code = 0;
char category[14]; //G, R, or L
if (category_bit == 0)
{
sys_code = ( (location_id & 0x3FFFFF) >> 12); //10 bits
site_code = location_id & 0x3FF; //12 bits
sprintf (category, "%s", "Global");
}
else if (category_bit == 2)
{
sys_code = ( (location_id & 0x3FFFFF) >> 8); //14 bits
site_code = location_id & 0xFF; //8 bits
sprintf (category, "%s", "Regional");
}
else if (category_bit == 1)
{
sys_code = ( (location_id & 0x3FFFFF) >> 5); //17 bits
site_code = location_id & 0x1F; //5 bits
sprintf (category, "%s", "Local");
}
else
{
//err, or we shouldn't ever get here
sprintf (category, "%s", "Reserved/Err");
}
//not entirely convinced that site code and ran are the exact same thing due to bit len differences
//site code is meant to be a color code (but this could also be like the P25 p1 nac and p2 cc being the same)
state->nxdn_last_ran = site_code; //this one may drop on nocarrier
if (site_code != 0) state->nxdn_location_site_code = site_code; //this one won't
if (sys_code != 0) state->nxdn_location_sys_code = sys_code;
sprintf (state->nxdn_location_category, "%s", category);
fprintf (stderr, "\n Location Information - Cat: %s - Sys Code: %d - Site Code %d ", category, sys_code, site_code);
}
void nxdn_srv_info_handler (dsd_state * state, uint16_t svc_info)
{
//handle the service information elements
//Part 1-A Common Air Interface Ver.2.0
//6.5.33. Service Information
fprintf (stderr, "\n Services:");
//check each SIF 1-bit element
if (svc_info & 0x8000) fprintf (stderr, " Multi-Site;");
if (svc_info & 0x4000) fprintf (stderr, " Multi-System;");
if (svc_info & 0x2000) fprintf (stderr, " Location Registration;");
if (svc_info & 0x1000) fprintf (stderr, " Group Registration;");
if (svc_info & 0x800) fprintf (stderr, " Authentication;");
if (svc_info & 0x400) fprintf (stderr, " Composite Control Channel;");
if (svc_info & 0x200) fprintf (stderr, " Voice Call;");
if (svc_info & 0x100) fprintf (stderr, " Data Call;");
if (svc_info & 0x80) fprintf (stderr, " Short Data Call;");
if (svc_info & 0x40) fprintf (stderr, " Status Call & Remote Control;");
if (svc_info & 0x20) fprintf (stderr, " PSTN Network Connection;");
if (svc_info & 0x10) fprintf (stderr, " IP Network Connection;");
//last 4-bits are spares
}
void nxdn_rst_info_handler (dsd_state * state, uint32_t rst_info)
{
//handle the restriction information elements
//Part 1-A Common Air Interface Ver.2.0
//6.5.34. Restriction Information
fprintf (stderr, "\n RST -");
//Mobile station operation information (Octet 0, Bits 7 to 4)
fprintf (stderr, " MS:");
if (rst_info & 0x800000) fprintf (stderr, " Access Restriction;");
else if (rst_info & 0x400000) fprintf (stderr, " Maintenance Restriction;");
// else fprintf (stderr, " No Restriction;");
//Access cycle interval (Octet 0, Bits 3 to 0)
fprintf (stderr, " ACI:");
uint8_t frames = (rst_info >> 16) & 0xF;
if (frames) fprintf (stderr, " %d Frame Restriction;", frames * 20);
// else fprintf (stderr, " No Restriction;");
//Restriction group specification (Octet 1, Bits 7 to 4)
fprintf (stderr, " RGS:");
uint8_t uid = (rst_info >> 12) & 0x7; //MSB is a spare, so only evaluate 3-bits
fprintf (stderr, " Lower 3 bits of Unit ID = %d %d %d", uid & 1, (uid >> 1) & 1, (uid >> 2) & 1);
//Restriction Information (Octet 1, Bits 3 to 0)
fprintf (stderr, " RI:");
if (rst_info & 0x800) fprintf (stderr, " Location Restriction;");
else if (rst_info & 0x400) fprintf (stderr, " Call Restriction;");
else if (rst_info & 0x200) fprintf (stderr, " Short Data Restriction;");
// else fprintf (stderr, " No Restriction;");
//Restriction group ratio specification (Octet 2, Bits 7 to 6)
fprintf (stderr, " RT:");
uint8_t ratio = (rst_info >> 22) & 0x3;
if (ratio == 1) fprintf (stderr, " 50 Restriction;");
else if (ratio == 2) fprintf (stderr, " 75 Restriction;");
else if (ratio == 3) fprintf (stderr, " 87.5 Restriction;");
// else fprintf (stderr, " No Restriction;");
//Delay time extension specification (Octet 2, Bits 5 to 4)
fprintf (stderr, " DT:");
uint8_t dt = (rst_info >> 20) & 0x3;
if (dt == 0) fprintf (stderr, " Timer T2 max x 1;");
else if (dt == 1) fprintf (stderr, " Timer T2 max x 2;");
else if (dt == 2) fprintf (stderr, " Timer T2 max x 3;");
else fprintf (stderr, " Timer T2 max x 4;");
//ISO Temporary Isolation Site -- This is valid only if the SIF 1 of Service Information is set to 1.
if (rst_info & 0x0001) fprintf (stderr, " - Site Isolation;");
//what a pain...
}
void nxdn_ca_info_handler (dsd_state * state, uint32_t ca_info)
{
//handle the channel access info for channel or dfa
//Part 1-A Common Air Interface Ver.2.0
//6.5.36. Channel Access Information
//this element only seems to appear in the SITE_INFO message
uint32_t RCN = ca_info >> 23; //Radio Channel Notation
uint32_t step = (ca_info >> 21) & 0x3; //Stepping
uint32_t base = (ca_info >> 19) & 0x7; //Base Frequency
uint32_t spare = ca_info & 0x3FF;
//set state variable here to tell us to use DFA or Channel Versions
if (RCN == 1)
{
state->nxdn_rcn = RCN;
state->nxdn_step = step;
state->nxdn_base_freq = base;
}
}
//end sub-element handlers
void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Message)
{
//just using 'short form' M only data, not the optional data
@@ -212,6 +359,11 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
uint8_t DuplexMode[32] = {0};
uint8_t TransmissionMode[32] = {0};
//DFA specific variables
uint8_t bw = 0;
uint16_t OFN = 0;
uint16_t IFN = 0;
/* Decode "CC Option" */
CCOption = (uint8_t)ConvertBitIntoBytes(&Message[8], 8);
state->NxdnElementsContent.CCOption = CCOption;
@@ -238,9 +390,14 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
/* Decode "Channel" */
Channel = (uint16_t)ConvertBitIntoBytes(&Message[62], 10);
/* Decode "Location ID Option" */ //is in the optional field, probably best not to run this one
//LocationIDOption = (uint8_t)ConvertBitIntoBytes(&Message[72], 5);
/* Decode DFA-only variables*/
if (state->nxdn_rcn == 1)
{
bw = (uint8_t)ConvertBitIntoBytes(&Message[62], 2);
OFN = (uint16_t)ConvertBitIntoBytes(&Message[64], 16);
IFN = (uint16_t)ConvertBitIntoBytes(&Message[80], 16);
}
/* Print the "CC Option" */
if(CCOption & 0x80) fprintf(stderr, "Emergency ");
if(CCOption & 0x40) fprintf(stderr, "Visitor ");
@@ -257,12 +414,18 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
/* Print Source ID and Destination ID (Talk Group or Unit ID) */
fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF);
/* Print Channel (Skipping Call Timer)*/
fprintf(stderr, "- Channel [%03X][%04d] ", Channel & 0x3FF, Channel & 0x3FF);
/* Print Channel */
if (state->nxdn_rcn == 0)
fprintf(stderr, "- Channel [%03X][%04d] ", Channel & 0x3FF, Channel & 0x3FF);
if (state->nxdn_rcn == 1)
fprintf(stderr, "- DFA Channel [%04X][%05d] ", OFN, OFN);
//run process to figure out frequency value from the channel, or from lcn import array
//run process to figure out frequency value from the channel import or from DFA
long int freq = 0;
freq = nxdn_channel_to_frequency(opts, state, Channel);
if (state->nxdn_rcn == 0)
freq = nxdn_channel_to_frequency(opts, state, Channel);
if (state->nxdn_rcn == 1)
freq = nxdn_channel_to_frequency(opts, state, OFN);
//check the rkey array for a scrambler key value
//TGT ID and Key ID could clash though if csv or system has both with different keys
@@ -288,7 +451,6 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
}
}
//run group/source analysis and tune if available/desired
//group list mode so we can look and see if we need to block tuning any groups, etc
char mode[8]; //allow, block, digital, enc, etc
@@ -430,6 +592,7 @@ void NXDN_decode_Alias(dsd_opts * opts, dsd_state * state, uint8_t * Message)
void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
{
//6.4.3.3. Control Channel Information (CCH_INFO) for more information
uint32_t location_id = 0;
uint8_t channel1sts = 0;
uint16_t channel1 = 0;
@@ -437,6 +600,14 @@ void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
uint16_t channel2 = 0;
long int freq1 = 0;
long int freq2 = 0;
//DFA
uint8_t bw1 = 0;
uint16_t OFN1 = 0;
uint16_t IFN1 = 0;
uint8_t bw2 = 0;
uint16_t OFN2 = 0;
uint16_t IFN2 = 0;
location_id = (uint32_t)ConvertBitIntoBytes(&Message[8], 24);
channel1sts = (uint8_t)ConvertBitIntoBytes(&Message[32], 6);
@@ -446,24 +617,43 @@ void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
fprintf (stderr, "%s", KYEL);
nxdn_location_id_handler (state, location_id);
fprintf (stderr, "\n Control Channel Information \n");
fprintf (stderr, " Location ID [%06X] CC1 [%03X][%04d] CC2 [%03X][%04d] Status: ", location_id, channel1, channel1, channel2, channel2);
//check the sts bits to determine if current, new, add, or delete
if (channel1sts & 0x20) fprintf (stderr, "Current ");
else if (channel1sts & 0x10) fprintf (stderr, "New ");
else if (channel1sts & 0x8) fprintf (stderr, "Candidate Added ");
else if (channel1sts & 0x4) fprintf (stderr, "Candidate Deleted ");
freq1 = nxdn_channel_to_frequency (opts, state, channel1);
freq2 = nxdn_channel_to_frequency (opts, state, channel2);
//non-DFA version
if (state->nxdn_rcn == 0)
{
fprintf (stderr, " Location ID [%06X] CC1 [%03X][%04d] CC2 [%03X][%04d] Status: ", location_id, channel1, channel1, channel2, channel2);
//check the sts bits to determine if current, new, add, or delete
if (channel1sts & 0x20) fprintf (stderr, "Current ");
if (channel1sts & 0x10) fprintf (stderr, "New ");
if (channel1sts & 0x08) fprintf (stderr, "Candidate Added ");
if (channel1sts & 0x04) fprintf (stderr, "Candidate Deleted ");
freq1 = nxdn_channel_to_frequency (opts, state, channel1);
freq2 = nxdn_channel_to_frequency (opts, state, channel2);
}
//DFA version
if (state->nxdn_rcn == 1)
{
bw1 = (uint8_t)ConvertBitIntoBytes(&Message[38], 2);
OFN1 = (uint16_t)ConvertBitIntoBytes(&Message[40], 16);
IFN1 = (uint16_t)ConvertBitIntoBytes(&Message[56], 16);
//removed code below, may have been causing issues with current CC frequency assignment
//removed code is unneccesary for trunking purposes
//facch1 will not have the below items
// bw2 = (uint8_t)ConvertBitIntoBytes(&Message[78], 2);
// OFN2 = (uint16_t)ConvertBitIntoBytes(&Message[80], 16);
// IFN2 = (uint16_t)ConvertBitIntoBytes(&Message[96], 16);
if (channel1sts & 0x10) fprintf (stderr, "New ");
if (channel1sts & 0x02) fprintf (stderr, "Current1 ");
if (channel1sts & 0x01) fprintf (stderr, "Current2 ");
freq1 = nxdn_channel_to_frequency (opts, state, OFN1);
//if a delete, let's not bother trying to remove it from the list for now
SKIP: ; //do nothing
//channel 2 should only be valid on 'current' status, but not sure what value it would contain vs channel 1
//facch1 does not carry this value, so let's not look at it
// freq2 = nxdn_channel_to_frequency (opts, state, OFN2);
}
fprintf (stderr, "%s", KNRM);
}
@@ -481,6 +671,13 @@ void NXDN_decode_srv_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
fprintf (stderr, "\n Service Information - ");
fprintf (stderr, "Location ID [%06X] SVC [%04X] RST [%06X] ", location_id, svc_info, rst_info);
nxdn_location_id_handler (state, location_id);
//run the srv info
nxdn_srv_info_handler (state, svc_info);
//run the rst info, if not zero
if (rst_info) nxdn_rst_info_handler (state, rst_info);
fprintf (stderr, "%s", KNRM);
//poll for current frequency, will always be the control channel
@@ -504,51 +701,6 @@ void NXDN_decode_srv_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
}
//externalize the location handler to its own function
void nxdn_location_id_handler (dsd_state * state, uint32_t location_id)
{
//6.5.2 Location ID
uint8_t category_bit = location_id >> 22;
uint32_t sys_code = 0;
uint16_t site_code = 0;
char category[14]; //G, R, or L
if (category_bit == 0)
{
sys_code = ( (location_id & 0x3FFFFF) >> 12); //10 bits
site_code = location_id & 0x3FF; //12 bits
sprintf (category, "%s", "Global");
}
else if (category_bit == 2)
{
sys_code = ( (location_id & 0x3FFFFF) >> 8); //14 bits
site_code = location_id & 0xFF; //8 bits
sprintf (category, "%s", "Regional");
}
else if (category_bit == 1)
{
sys_code = ( (location_id & 0x3FFFFF) >> 5); //17 bits
site_code = location_id & 0x1F; //5 bits
sprintf (category, "%s", "Local");
}
else
{
//err, or we shouldn't ever get here
sprintf (category, "%s", "Reserved/Err");
}
//not entirely convinced that site code and ran are the exact same thing due to bit len differences
//site code is meant to be a color code (but this could also be like the P25 p1 nac and p2 cc being the same)
state->nxdn_last_ran = site_code; //this one may drop on nocarrier
if (site_code != 0) state->nxdn_location_site_code = site_code; //this one won't
if (sys_code != 0) state->nxdn_location_sys_code = sys_code;
sprintf (state->nxdn_location_category, "%s", category);
fprintf (stderr, "\n Location Information - Cat: %s - Sys Code: %d - Site Code %d ", category, sys_code, site_code);
}
void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
{
uint32_t location_id = 0;
@@ -574,28 +726,41 @@ void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message
channel1 = (uint16_t)ConvertBitIntoBytes(&Message[124], 10);
channel2 = (uint16_t)ConvertBitIntoBytes(&Message[134], 10);
//check the channel access information first
nxdn_ca_info_handler (state, ca_info);
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "\n Location ID [%06X] CSC [%04X] SVC [%04X] RST [%06X] \n CA [%06X] V[%X] ADJ [%01X] ",
location_id, cs_info, svc_info, rst_info, ca_info, version_num, adj_alloc);
nxdn_location_id_handler(state, location_id);
if (channel1 != 0)
//run the srv info
nxdn_srv_info_handler (state, svc_info);
//run the rst info, if not zero
if (rst_info) nxdn_rst_info_handler (state, rst_info);
//only get frequencies if using channel version of message and not dfa
if (state->nxdn_rcn == 0)
{
fprintf (stderr, "\n Control Channel 1 [%03X][%04d] ", channel1, channel1 );
freq1 = nxdn_channel_to_frequency (opts, state, channel1);
if (channel1 != 0)
{
fprintf (stderr, "\n Control Channel 1 [%03X][%04d] ", channel1, channel1 );
freq1 = nxdn_channel_to_frequency (opts, state, channel1);
}
if (channel2 != 0)
{
fprintf (stderr, "\n Control Channel 2 [%03X][%04d] ", channel2, channel2 );
freq2 = nxdn_channel_to_frequency (opts, state, channel2);
}
}
if (channel2 != 0)
else
{
fprintf (stderr, "\n Control Channel 2 [%03X][%04d] ", channel2, channel2 );
freq2 = nxdn_channel_to_frequency (opts, state, channel2);
; //DFA version does not carry an OFN/IFN value, so no freqs
}
fprintf (stderr, "%s", KNRM);
//removed code below, may have been causing issues with current CC frequency assignment
//removed code is unneccesary for trunking purposes
SKIP: ; //do nothing
}

View File

@@ -2,7 +2,7 @@
* p25_frequency.c
* P25 Channel to Frequency Calculator
*
* NXDN Channel to Frequency, Courtesy of IcomIcR20 and EricCottrell (base values)
* NXDN Channel to Frequency Calculator
*
* LWVMOBILE
* 2022-11 DSD-FME Florida Man Edition
@@ -59,16 +59,16 @@ long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channe
}
//NXDN Channel to Frequency, Courtesy of IcomIcR20 on RR Forums
long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t channel)
{
long int freq;
long int base = 0;
long int step = 0;
//the base freq value is per EricCottrell in the Understanding NXDN Trunking Forum Thread
//will need to do some research or tests to confirm these values are accurate
//reworked to include Direct Frequency Assignment if available
//first, check channel map
//first, check channel map for imported value, DFA systems most likely won't need an import,
//unless it has 'system definable' attributes
if (state->trunk_chan_map[channel] != 0)
{
freq = state->trunk_chan_map[channel];
@@ -76,42 +76,41 @@ long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t
return (freq);
}
//then, let's see if its DFA instead -- 6.5.36
else if (state->nxdn_rcn == 1)
{
//determine the base frequency in Hz
if (state->nxdn_base_freq == 1) base = 100000000; //100 MHz
else if (state->nxdn_base_freq == 2) base = 330000000; //330 Mhz
else if (state->nxdn_base_freq == 3) base = 400000000; //400 Mhz
else if (state->nxdn_base_freq == 4) base = 750000000; //750 Mhz
else base = 0; //just set to zero, will be system definable most likely and won't be able to calc
//determine the step value in Hz
if (state->nxdn_step = 2) step = 1250; //1.25 kHz
else if (state->nxdn_step = 3) step = 3125; //3.125 kHz
else step = 0; //just set to zero, will be system definable most likely and won't be able to calc
//if we have a valid base and step, then calc frequency
//6.5.45. Outbound/Inbound Frequency Number (OFN/IFN)
if (base && step)
{
freq = base + (channel * step);
fprintf (stderr, "\n DFA Frequency [%.6lf] MHz", (double)freq/1000000);
return (freq);
}
else
{
fprintf(stderr, "\n Custom DFA Settings -- Unknown Freq;");
return (0);
}
}
else
{
fprintf(stderr, "\n Channel not found in import file");
return (0);
}
//if not found, attempt to find it via calculation
//disabled, frequency 'band plan' isn't standard
//like originally believed
// else
// {
// if ((channel > 0) && (channel <= 400))
// {
// if (opts->frame_nxdn48 == 1) base = 450000000;
// else base = 451000000;
// freq = base + (channel - 1) * 12500;
// fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
// return (freq);
// }
// else if ((channel >= 401) && (channel <= 800))
// {
// if (opts->frame_nxdn48 == 1) base = 460000000;
// else base = 461000000;
// freq = base + (channel - 401) * 12500;
// fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
// return (freq);
// }
// else
// {
// fprintf(stderr, "\n Non-standard frequency or channel not found in import file");
// return (0);
// }
// }
}