Hytera XPT WIP #110

This commit is contained in:
lwvmobile 2023-04-08 19:14:47 -04:00
parent ce75acb41a
commit ba0e422f23
5 changed files with 161 additions and 128 deletions

View File

@ -143,7 +143,7 @@ NXDN Trunking Update: NXDN DFA (Direct Frequency Assignment) has been coded from
Channel Map and Group CSV Note: Leave the top line of the channel_map.csv and group.csv as the label, do not delete the line, if no line is there, dsd_import skips the first line so it will not import the first channel or first group in those files if there is something there that isn't a label. Channel Map and Group CSV Note: Leave the top line of the channel_map.csv and group.csv as the label, do not delete the line, if no line is there, dsd_import skips the first line so it will not import the first channel or first group in those files if there is something there that isn't a label.
Hytera XPT: Experimental Code has been added for XPT system slco/flco/csbk decoding and trunking. The setup will be similar to Capacity Plus trunking in the csv file, but add a channel 0 and frequency value as the 'home' repeater. This is based off of my best understanding that the 'home' repeater is the starting point of all XPT calls, and that calls only expand outwards to the next free repeater the busier the system gets. I cannot guarantee that XPT will 'trunk' correctly, it may in fact stay on the home repeater most times since theoretically, if my understanding is correct, all calls start there and there should be a voice call there before there is one on a free repeater. To properly decode an XPT system, having multiple instances of DSD-FME passively listening to each repeater channel may be a more complete method than attempting to trunk it directly. Hytera XPT: Experimental Code has been added for XPT system slco/flco/csbk decoding and trunking. The setup will be similar to Capacity Plus trunking in the csv file. This is based off of my best understanding that the 'home' repeater LCN is the starting point of all XPT calls, and that calls only expand outwards to the next free repeater LCN the busier the system gets. I cannot guarantee that XPT will 'trunk' correctly, it may in fact stay on the home repeater most times since theoretically, if my understanding is correct, all calls start there and there should be a voice call there before there is one on a free repeater. To properly decode an XPT system, having multiple instances of DSD-FME passively listening to each repeater channel may be a more complete method than attempting to trunk it directly.
## NCurses Keyboard Shortcuts ## ## NCurses Keyboard Shortcuts ##

View File

@ -1,4 +1,4 @@
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly) LSN Number(dec),frequency(Hz) (do not delete this line or won't import properly)
1,858606250 1,858606250
2,858606250 2,858606250
3,859606250 3,859606250

1 ChannelNumber(dec) LSN Number(dec) frequency(Hz) (do not delete this line or won't import properly)
2 1 858606250
3 2 858606250
4 3 859606250

View File

@ -34,6 +34,25 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
uint32_t target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[16], 24); //destination llid uint32_t target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[16], 24); //destination llid
uint32_t source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[40], 24); //source llid uint32_t source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[40], 24); //source llid
//extra tgt/src handling for XPT
uint8_t target_hash[24];
uint8_t tg_hash = 0;
uint8_t is_xpt = 0;
//set flag if XPT
if (strcmp (state->dmr_branding_sub, "XPT ") == 0) is_xpt = 1;
//truncate tgt/src to 16-bit values if XPT
if (is_xpt == 1)
{
target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[24], 16); //destination llid
source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 16); //source llid
if (gi == 0)
{
for (int i = 0; i < 16; i++) target_hash[i] = dheader_bits[24+i];
tg_hash = crc8 (target_hash, 16);
}
}
//store source for dmr pdu packet handling (lrrp) when not available in completed message //store source for dmr pdu packet handling (lrrp) when not available in completed message
if (dpf != 15) state->dmr_lrrp_source[slot] = source; if (dpf != 15) state->dmr_lrrp_source[slot] = source;
@ -112,6 +131,9 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
if (a == 1 && dpf != 15) fprintf(stderr, "- Response Requested "); if (a == 1 && dpf != 15) fprintf(stderr, "- Response Requested ");
if (dpf != 15) fprintf (stderr, "- Source: %d Target: %d ", source, target); if (dpf != 15) fprintf (stderr, "- Source: %d Target: %d ", source, target);
//include the hash value if this is an XPT and if its IND data
if (dpf != 15 && is_xpt == 1 && gi == 0) fprintf (stderr, "Hash: %d ", tg_hash);
//sap string handling //sap string handling
if (dpf == 15) sap = p_sap; if (dpf == 15) sap = p_sap;

View File

@ -615,13 +615,35 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24); uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24); uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
uint8_t target_hash[24];
uint8_t tg_hash = 0;
if (gi == 0) fprintf (stderr, "Individual "); if (gi == 0) fprintf (stderr, "Individual ");
else fprintf (stderr, "Group "); else fprintf (stderr, "Group ");
if (content == 0) fprintf (stderr, "CSBK - "); if (content == 0) fprintf (stderr, "CSBK - ");
else fprintf (stderr, "Data - "); else fprintf (stderr, "Data - ");
fprintf (stderr, "Target [%d] - Source [%d] ", target, source); // check to see if this is XPT
if (strcmp (state->dmr_branding_sub, "XPT ") == 0)
{
//get 16-bit truncated target and source ids
target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16); //40, or 32?
source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[64], 16); //56, or 64?
//check to see if this is indiv data (private) then we will need to report the hash value as well
if (gi == 0)
{
//the crc8 hash is the value represented in the Hytera XPT Site Status CSBK when dealing with indiv data
for (int i = 0; i < 16; i++) target_hash[i] = cs_pdu_bits[40+i];
tg_hash = crc8 (target_hash, 16);
fprintf (stderr, "Source: %d - Target: %d - Hash: %d ", source, target, tg_hash);
}
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
}
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
} }
//end tier 2 csbks //end tier 2 csbks
@ -780,7 +802,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
pch[i] = state->cap_plus_csbk_bits[i+48+(group_tally*8)]; pch[i] = state->cap_plus_csbk_bits[i+48+(group_tally*8)];
if (pch[i] == 1) if (pch[i] == 1)
{ {
fprintf (stderr, " Ch%d:", i+1); fprintf (stderr, " LSN %d:", i+1);
private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[56+(k*16)+(group_tally*8)], 16); private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[56+(k*16)+(group_tally*8)], 16);
fprintf (stderr, " TGT %d;", private_target); fprintf (stderr, " TGT %d;", private_target);
if (opts->trunk_tune_data_calls == 1) t_tg[i] = private_target; //set here for tuning allow/block if (opts->trunk_tune_data_calls == 1) t_tg[i] = private_target; //set here for tuning allow/block
@ -799,7 +821,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
k = 0; k = 0;
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
{ {
fprintf (stderr, "Ch%d: ", i+1); fprintf (stderr, "LSN %d: ", i+1);
if (ch[i] == 1) //group voice channels if (ch[i] == 1) //group voice channels
{ {
tg = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[k*8+32], 8); tg = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[k*8+32], 8);
@ -1034,7 +1056,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
//Hytera XPT //Hytera XPT
if (csbk_fid == 0x68) if (csbk_fid == 0x68)
{ {
//XPT Site Status -- Very Very Experimental, WIP, Don't be surprised by bad decodes or broken trunking //XPT Site Status -- Experimental, WIP, Don't be surprised by bad decodes or broken trunking
if (csbk_o == 0x0A) if (csbk_o == 0x0A)
{ {
//initial line break //initial line break
@ -1053,17 +1075,19 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
uint8_t xpt_free = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 4); //free repeater channel uint8_t xpt_free = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 4); //free repeater channel
uint8_t xpt_bank = 0; uint8_t xpt_bank = 0;
//xpt_bank needs testing on busier systems/samples still to verify accuracy
if (xpt_seq) xpt_bank = xpt_seq*6; if (xpt_seq) xpt_bank = xpt_seq*6;
//get 2-bit status values for each 6 channels (timeslots) //get 2-bit status values for each 6 channels (timeslots)
for (i = 0; i < 6; i++) xpt_ch[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20+(i*2)], 2); for (i = 0; i < 6; i++) xpt_ch[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20+(i*2)], 2);
fprintf (stderr, " Hytera XPT Site Status - Free RPT: %d SN: %d\n ", xpt_free, xpt_seq); fprintf (stderr, " Hytera XPT Site Status - Free LCN: %d SN: %d \n ", xpt_free, xpt_seq);
//Print List of Channels and Activity //Print List of Channels and Activity
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
{ {
fprintf (stderr, "Ch%02d: ", i+xpt_bank+1); //(xpt_seq*6) //LSN value here is logical slot, in flco, we get the logical channel (which is the repeater, does not include the slot value)
fprintf (stderr, "LSN %02d: ", i+xpt_bank+1); //swap out xpt_bank for all (xpt_seq*6) to simplify things
tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[i*8+32], 8); tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[i*8+32], 8);
fprintf (stderr, "ST-%X", xpt_ch[i]); //status bits value 0,1,2, or 3 fprintf (stderr, "ST-%X", xpt_ch[i]); //status bits value 0,1,2, or 3
if (tg != 0) fprintf (stderr, " %03d ", tg); if (tg != 0) fprintf (stderr, " %03d ", tg);
@ -1077,14 +1101,17 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
if (i == 2) fprintf (stderr, "\n "); if (i == 2) fprintf (stderr, "\n ");
//add values to trunking tg/channel potentials //add values to trunking tg/channel potentials
if (tg != 0) t_tg[i+(xpt_seq*6)] = tg; if (tg != 0) t_tg[i+xpt_bank] = tg;
} }
//debug ncurses terminal display
// sprintf (state->dmr_lrrp_gps[0], "XPT SN %d LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d;", xpt_seq, xpt_bank+1, t_tg[0], xpt_bank+2, t_tg[1], xpt_bank+3, t_tg[2]);
// sprintf (state->dmr_lrrp_gps[1], "XPT SN %d LSN: %02d TG: %03d; LSN: %02d TG: %03d; LSN: %02d TG: %03d;", xpt_seq, xpt_bank+4, t_tg[3], xpt_bank+5, t_tg[4], xpt_bank+6, t_tg[5]);
//add string for ncurses terminal display //add string for ncurses terminal display
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free); sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
//assign to cc freq to follow during no sync //assign to cc freq to follow during no sync
long int ccfreq = 0; long int ccfreq = 0;
@ -1116,7 +1143,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
if (opts->trunk_tune_group_calls == 0) goto SKIPXPT; if (opts->trunk_tune_group_calls == 0) goto SKIPXPT;
//don't tune if vc on the current channel //don't tune if vc on the current channel
if ( (time(NULL) - state->last_vc_sync_time > 2) ) if ( (time(NULL) - state->last_vc_sync_time) > 2 ) //parenthesis error fixed
{ {
for (j = 0; j < 6; j++) //go through the channels stored looking for active ones to tune to for (j = 0; j < 6; j++) //go through the channels stored looking for active ones to tune to
{ {
@ -1131,7 +1158,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
//and hope it doesn't clash with other normal TG values //and hope it doesn't clash with other normal TG values
for (int i = 0; i < state->group_tally; i++) for (int i = 0; i < state->group_tally; i++)
{ {
if (state->group_array[i].groupNumber == t_tg[j+(xpt_seq*6)]) if (state->group_array[i].groupNumber == t_tg[j+xpt_bank])
{ {
fprintf (stderr, " [%s]", state->group_array[i].groupName); fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode); strcpy (mode, state->group_array[i].groupMode);
@ -1139,16 +1166,22 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
} }
//without priority, this will tune the first one it finds (if group isn't blocked) //without priority, this will tune the first one it finds (if group isn't blocked)
if (t_tg[j+(xpt_seq*6)+1] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0)) if (t_tg[j+xpt_bank] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
{ {
if (state->trunk_chan_map[j+(xpt_seq*6)+1] != 0) //if we have a valid frequency //debug print for tuning verification
fprintf (stderr, "\n LSN/TG to tune to: %d - %d", j+xpt_bank+1, t_tg[j+xpt_bank]);
if (state->trunk_chan_map[j+xpt_bank+1] != 0) //if we have a valid frequency
{ {
//RIGCTL //RIGCTL
if (opts->use_rigctl == 1) if (opts->use_rigctl == 1)
{ {
//debug
fprintf (stderr, " - Freq: %ld", state->trunk_chan_map[j+xpt_bank+1]);
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+(xpt_seq*6)+1]); SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+xpt_bank+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+(xpt_seq*6)+1]; state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+xpt_bank+1];
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
j = 11; //break loop j = 11; //break loop
@ -1157,8 +1190,11 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
//rtl_udp //rtl_udp
else if (opts->audio_in_type == 3) else if (opts->audio_in_type == 3)
{ {
rtl_udp_tune (opts, state, state->trunk_chan_map[j+(xpt_seq*6)+1]); //debug
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+(xpt_seq*6)+1]; fprintf (stderr, " - Freq: %ld", state->trunk_chan_map[j+xpt_bank+1]);
rtl_udp_tune (opts, state, state->trunk_chan_map[j+xpt_bank+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+xpt_bank+1];
opts->p25_is_tuned = 1; opts->p25_is_tuned = 1;
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
j = 11; //break loop j = 11; //break loop
@ -1174,13 +1210,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
sprintf (state->dmr_branding_sub, "XPT "); sprintf (state->dmr_branding_sub, "XPT ");
//Trunking Note: My understanding is that XPT calls always start on the 'home' repeater, and then expand //Notes: I had a few issues to fix in this CSBK, but it does appear that this is trunking on at least one system now,
//outward to the free repeaters, so its probably easiest for a user to load the frequencies in a csv file //albeit a very quiet system that makes it difficult to know for certain if every aspect is working correctly
//and let FME scan through them as opposed to actively trunking, it will spend most of the time on the home repeater
//and if calls occur on the home repeater, it'll be too busy with those to go to the free repeater
//DSD-FME doesn't have any sort of TG priority, so its first come first served, just block or allow
//Additional Notes: I've set XPT to set a CC frequency to whichever frequency its tuned to currently and getting //Notes: I've set XPT to set a CC frequency to whichever frequency its tuned to currently and getting
//this particular CSBK, if the status portion does work correctly, then it shouldn't matter which frequency it is on //this particular CSBK, if the status portion does work correctly, then it shouldn't matter which frequency it is on
//as long as this CSBK comes in and we can tune to other repeater lcns if they have activity and the frequency mapping //as long as this CSBK comes in and we can tune to other repeater lcns if they have activity and the frequency mapping
//is correct in the csv file, assuming the current frequency doesn't have voice activity //is correct in the csv file, assuming the current frequency doesn't have voice activity
@ -1195,54 +1228,62 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
fprintf (stderr, "\n"); fprintf (stderr, "\n");
fprintf (stderr, "%s", KYEL); fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Hytera XPT CSBK 0x0B ");
//wraithe's theory -- seems pretty good to me //wraithe's theory -- seems pretty good to me
//still only a theory though until can be verified //still only a theory though until can be verified
//by having a system with precisely known variables //by having a system with precisely known variables
//new samples show this doesn't always quite work, there seems to be
//more than one data set transmitted in this CSBK
//one set works, the other doesn't fit the pattern
// Site ID [5 bits] // Site ID [5 bits]
// Unknown_3 [3 bits] // Unknown_3 [3 bits]
// Free Repeater on site [4 bits] // Free Repeater on site [4 bits]
// Unknown_4 [4 bits] // Unknown_4 [4 bits]
// 11:44:58 Sync: +DMR slot1 [slot2] | Color Code=01 | CSBK
// Hytera XPT CSBK 0x0B
// DMR PDU Payload [0B][68][10][20][18][10][20][10][28][20][EF][DA]
// repeat x3 (for total of 4 sites) // repeat x3 (for total of 4 sites)
// int i; //new samples show this doesn't always quite work, there seems to be
// uint8_t xpt_site_id[4]; //more than one data set transmitted in this CSBK, when the first two bits aren't 0
// uint8_t xpt_site_rp[4]; //one set works, the other doesn't fit the pattern
// uint8_t xpt_site_u1[4];
// uint8_t xpt_site_u2[4];
// for (i = 0; i < 4; i++) // 18:55:56 Sync: +DMR slot1 [slot2] | Color Code=01 | CSBK
// { // Hytera XPT Site Id: 1 - Free LCN: 2
// xpt_site_id[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16+(i*16)], 5); // XPT Adj Site(s): Site:4 Free:1; Site:2 Free:1; Site:5 Free:1;
// xpt_site_u1[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[21+(i*16)], 3); // DMR PDU Payload [0B][68][08][20][20][10][10][10][28][10][F4][C0]
// xpt_site_rp[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24+(i*16)], 4); // 18:55:56 Sync: +DMR [slot1] slot2 | Color Code=01 | CSBK
// xpt_site_u2[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[28+(i*16)], 4); // Hytera XPT CSBK 0x0B - SN: 1
// } // DMR PDU Payload [4B][68][54][F0][00][00][00][00][00][00][E9][8F] <--site ID: 10 Free: 15 doesn't make sense compared to other data here
// fprintf (stderr, " Hytera XPT Site Id: %d - Free RPT: %d", xpt_site_id[0], xpt_site_rp[0]); int i;
// // fprintf (stderr, " RS1: %d RS2: %d", xpt_site_u1[0], xpt_site_u2[1]); //debug uint8_t xpt_site_id[4];
uint8_t xpt_site_rp[4];
uint8_t xpt_site_u1[4];
uint8_t xpt_site_u2[4];
// fprintf (stderr, "\n"); uint8_t xpt_sn = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[0], 2); //this is not the protect flag and reserved flag, could be a seq number of fl?
// fprintf (stderr, " XPT Adj Site(s): "); uint8_t adj_flag = cs_pdu_bits[1]; //this is NOT the TS bit like in other XPT PDUs
// for (i = 1; i < 4; i++)
// { for (i = 0; i < 4; i++)
// if (xpt_site_id[i] != 0) {
// { xpt_site_id[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16+(i*16)], 5);
// fprintf (stderr, "%d (%d) ", xpt_site_id[i], xpt_site_rp[i]); xpt_site_u1[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[21+(i*16)], 3);
// // fprintf (stderr, "RS1: %d RS2: %d - ", xpt_site_u1[i], xpt_site_u2[i]); //debug xpt_site_rp[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24+(i*16)], 4);
// } xpt_site_u2[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[28+(i*16)], 4);
// } }
if (xpt_sn == 0) //for now, only run on 0, 1 could be appended data, but I don't think its adj_site related; could be other info;
{
fprintf (stderr, " Hytera XPT Site Id: %d - Free LCN: %d", xpt_site_id[0], xpt_site_rp[0]);
// fprintf (stderr, " RS1: %d RS2: %d", xpt_site_u1[0], xpt_site_u2[1]); //debug
fprintf (stderr, "\n");
fprintf (stderr, " XPT Adj Site(s): ");
for (i = 1; i < 4; i++)
{
if (xpt_site_id[i] != 0)
{
fprintf (stderr, "Site:%d Free:%d; ", xpt_site_id[i], xpt_site_rp[i]);
// fprintf (stderr, "RS1: %d RS2: %d - ", xpt_site_u1[i], xpt_site_u2[i]); //debug
}
}
}
else fprintf (stderr, " Hytera XPT CSBK 0x0B - SN: %d", xpt_sn);
sprintf (state->dmr_branding_sub, "XPT "); sprintf (state->dmr_branding_sub, "XPT ");

View File

@ -172,7 +172,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
//look for any Hytera XPT system, adjust TG to 16-bit allocation //look for any Hytera XPT system, adjust TG to 16-bit allocation
//Groups use only 8 out of 16, but 16 always seems to be allocated //Groups use only 8 out of 16, but 16 always seems to be allocated
//private calls use 16-bit target values hased to 8-bit in the site status csbk //private calls use 16-bit target values hashed to 8-bit in the site status csbk
//the TLC preceeds the VLC for a 'handshake' call setup in XPT //the TLC preceeds the VLC for a 'handshake' call setup in XPT
//truncate if XPT is set //truncate if XPT is set
@ -186,11 +186,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
tg_hash = crc8 (target_hash, 16); tg_hash = crc8 (target_hash, 16);
} }
//XPT Call 'Grant' Setup Occurs in TLC (TermLC Handshake) with a flco 0x09 //XPT Call 'Grant/Alert' Setup Occurs in TLC (TermLC 'Handshake') with a flco 0x09
if (fid == 0x68 && flco == 0x09) if (fid == 0x68 && flco == 0x09)
{ {
//The CSBK always uses an 8-bit TG; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing //The CSBK always uses an 8-bit TG/TGT; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing
//It seems that private calls and indiv data calls use a hash of their 8 bit tgt values in the CSBK //private calls and indiv data calls use a hash of their 8 bit tgt values in the CSBK
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //This is consistent with an LCN value, not an LSN value
xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 4); //24 and 4 on 0x09 xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 4); //24 and 4 on 0x09
xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[28], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved; xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[28], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved;
@ -198,86 +199,55 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16); //16-bit allocation source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16); //16-bit allocation
//the bits that are left behind //the bits that are left behind
xpt_res_a = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //Where the SVC bits would usually be xpt_res_a = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 4); //after the xpt_int channel, before the free repeater channel
xpt_res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 8); //where the first 8 bits of the SRC would be xpt_res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 8); //where the first 8 bits of the SRC would be
xpt_res_c = (uint8_t)ConvertBitIntoBytes(&lc_bits[72], 8); //some unknown 8 bit value after the SRC xpt_res_c = (uint8_t)ConvertBitIntoBytes(&lc_bits[72], 8); //some unknown 8 bit value after the SRC
//speculation: 16,4 may be the current repeater channel this call will occur on? or the channel to interrupt?, could also be 8 bits?
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //not sure about this value for this FLCO
//the crc8 hash is the value represented in the CSBK when dealing with private calls //the crc8 hash is the value represented in the CSBK when dealing with private calls
for (int i = 0; i < 16; i++) target_hash[i] = lc_bits[32+i]; for (int i = 0; i < 16; i++) target_hash[i] = lc_bits[32+i];
tg_hash = crc8 (target_hash, 16); //This is a different poly, but using as placeholder tg_hash = crc8 (target_hash, 16);
fprintf (stderr, "%s \n", KGRN); fprintf (stderr, "%s \n", KGRN);
fprintf (stderr, " SLOT %d ", state->currentslot+1); fprintf (stderr, " SLOT %d ", state->currentslot+1);
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
// Here are some of the RIDs with hash address seen in that sample:
// 930 = 88
// 9317 = 198
// 10002 = 187
if (opts->payload == 1) fprintf(stderr, "HASH=%d ", tg_hash);
// if (opts->payload == 1) fprintf(stderr, "HSK [%X] ", xpt_hand);
// if (opts->payload == 1) fprintf(stderr, "CH=%d ", xpt_int);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid); if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
fprintf (stderr, "TGT=%u SRC=%u ", target, source);
// if (opts->payload == 1) fprintf(stderr, "RS [%02X][%02X][%02X] ", xpt_res_a, xpt_res_b, xpt_res_c);
fprintf (stderr, "Hytera XPT "); fprintf (stderr, "Hytera XPT ");
if (reserved == 1) fprintf (stderr, "Group "); //according to observation if (reserved == 1) fprintf (stderr, "Group "); //according to observation
else fprintf (stderr, "Private "); //according to observation else fprintf (stderr, "Private "); //according to observation
fprintf (stderr, "Call Alert "); //sounds more reasonable than 'protect' fprintf (stderr, "Call Alert "); //Alert or Grant
fprintf (stderr, "%s", KYEL); //reorganized all the 'extra' data to a second line and added extra verbosity
fprintf (stderr, "F-Rpt %d", xpt_free); if (opts->payload == 1) fprintf (stderr, "\n ");
if (opts->payload == 1) fprintf (stderr, "%s", KYEL);
//only display the hashed tgt value if its a private call and not a group call
if (reserved == 0 && opts->payload == 1) fprintf(stderr, "TGT Hash=%d; ", tg_hash);
if (opts->payload == 1) fprintf(stderr, "HSK=%X; ", xpt_hand);
//extra verbosity on handshake type
if (opts->payload == 1)
{
fprintf (stderr, "Handshake - ");
if (xpt_hand == 0) fprintf (stderr, "Ordinary; ");
else if (xpt_hand == 1) fprintf (stderr, "Callback/Alarm Interrupt; ");
else if (xpt_hand == 2) fprintf (stderr, "Release Channel Interrupt; ");
else fprintf (stderr, "Reserved; ");
}
//logical repeater channel, not the logical slot value in the CSBK
if (opts->payload == 1) fprintf(stderr, "Call on LCN %d; ", xpt_int); //LCN channel call or 'interrupt' will occur on
// if (opts->payload == 1) fprintf(stderr, "RS A[%01X]B[%02X]C[%02X]; ", xpt_res_a, xpt_res_b, xpt_res_c); //leftover bits
if (opts->payload == 1) fprintf (stderr, "Free LCN %d; ", xpt_free); //current free repeater LCN channel
fprintf (stderr, "%s ", KNRM); fprintf (stderr, "%s ", KNRM);
//add string for ncurses terminal display //add string for ncurses terminal display
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free); sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
is_xpt = 1; is_xpt = 1;
goto END_FLCO; goto END_FLCO;
} }
//XPT 'Handshake' -- not observed as of yet on any samples //Hytera XPT 'Others' -- moved the patent opcodes here as well for now
if ( fid == 0x68 && (flco == 0x2E || flco == 0x2F) ) if ( fid == 0x68 && (flco == 0x13 || flco == 0x2E || flco == 0x2F) )
{
//all below is according to the patent, but never observed on any samples I have
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //24-bit values according to patent
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 24); //24-bit values according to patent
xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //16 and 4 on 2E and 2F
xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved;
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 8); //Interrupt Designated Channel (No idea?)
fprintf (stderr, "%s \n", KGRN);
fprintf (stderr, " SLOT %d ", state->currentslot+1);
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
if (opts->payload == 1) fprintf(stderr, "HASH=%d ", tg_hash);
// if (opts->payload == 1) fprintf(stderr, "HSK=[%X] ", xpt_hand);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
fprintf (stderr, "Hytera XPT ");
if (reserved == 1) fprintf (stderr, "Group ");
else fprintf (stderr, "Private ");
fprintf (stderr, "Call ");
if (flco == 0x2E) fprintf (stderr, "Request ");
if (flco == 0x2F) fprintf (stderr, "Response ");
fprintf (stderr, "%s ", KNRM);
is_xpt = 1;
goto END_FLCO;
}
//Hytera XPT "something" -- seen on Embedded
if (fid == 0x68 && flco == 0x13)
{ {
if (type == 1) fprintf (stderr, "%s \n", KCYN); if (type == 1) fprintf (stderr, "%s \n", KCYN);
if (type == 2) fprintf (stderr, "%s \n", KCYN); if (type == 2) fprintf (stderr, "%s \n", KCYN);
@ -905,13 +875,13 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
else if (slco == 0x08) else if (slco == 0x08)
{ {
//The Priority Repeater and Priority Hash values stem from SDRTrunk, but I've never seen these values not be zeroes //The Priority Repeater and Priority Hash values stem from SDRTrunk, but I've never seen these values not be zeroes
// fprintf (stderr, " SLCO Hytera XPT - Free RPT %d - PRI RPT %d - PRI HASH: %02X", xpt_free, xpt_pri, xpt_hash); fprintf (stderr, " SLCO Hytera XPT - Free LCN %d - PRI LCN %d - PRI HASH: %02X", xpt_free, xpt_pri, xpt_hash);
//NOTE: on really busy systems, this free repeater assignment can lag due to the 4 TS requirment to get SLC //NOTE: on really busy systems, this free repeater assignment can lag due to the 4 TS requirment to get SLC
fprintf (stderr, " SLCO Hytera XPT - Free RPT %d ", xpt_free); // fprintf (stderr, " SLCO Hytera XPT - Free LCN %d ", xpt_free);
sprintf (state->dmr_branding_sub, "XPT "); sprintf (state->dmr_branding_sub, "XPT ");
//add string for ncurses terminal display //add string for ncurses terminal display
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free); sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
} }
else fprintf (stderr, " SLCO Unknown - %d ", slco); else fprintf (stderr, " SLCO Unknown - %d ", slco);