diff --git a/examples/Example_Usage.md b/examples/Example_Usage.md index 7b272d3..90ffeae 100644 --- a/examples/Example_Usage.md +++ b/examples/Example_Usage.md @@ -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. -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 ## diff --git a/examples/hytera_xpt_chan.csv b/examples/hytera_xpt_chan.csv index 31b33a9..764172c 100644 --- a/examples/hytera_xpt_chan.csv +++ b/examples/hytera_xpt_chan.csv @@ -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 2,858606250 3,859606250 diff --git a/src/dmr_block.c b/src/dmr_block.c index 9411eca..8440127 100644 --- a/src/dmr_block.c +++ b/src/dmr_block.c @@ -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 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 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 (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 if (dpf == 15) sap = p_sap; diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c index dfbc3db..8874c9e 100644 --- a/src/dmr_csbk.c +++ b/src/dmr_csbk.c @@ -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 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 "); else fprintf (stderr, "Group "); if (content == 0) fprintf (stderr, "CSBK - "); 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 @@ -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)]; 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); fprintf (stderr, " TGT %d;", private_target); 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; 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 { 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 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) { //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_bank = 0; - if (xpt_seq) xpt_bank = xpt_seq*6; + //xpt_bank needs testing on busier systems/samples still to verify accuracy + if (xpt_seq) xpt_bank = xpt_seq*6; //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); - 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 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); fprintf (stderr, "ST-%X", xpt_ch[i]); //status bits value 0,1,2, or 3 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 "); - //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 - 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 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; //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 { @@ -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 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); 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) - 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 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); - SetFreq(opts->rigctl_sockfd, 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_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_bank+1]; 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 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 else if (opts->audio_in_type == 3) { - rtl_udp_tune (opts, state, 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_seq*6)+1]; + //debug + 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; dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away 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 "); - //Trunking Note: My understanding is that XPT calls always start on the 'home' repeater, and then expand - //outward to the free repeaters, so its probably easiest for a user to load the frequencies in a csv file - //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 + //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, + //albeit a very quiet system that makes it difficult to know for certain if every aspect is working correctly - //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 //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 @@ -1195,54 +1228,62 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 fprintf (stderr, "\n"); fprintf (stderr, "%s", KYEL); - fprintf (stderr, " Hytera XPT CSBK 0x0B "); - //wraithe's theory -- seems pretty good to me //still only a theory though until can be verified //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] // Unknown_3 [3 bits] // Free Repeater on site [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) - // int i; - // uint8_t xpt_site_id[4]; - // uint8_t xpt_site_rp[4]; - // uint8_t xpt_site_u1[4]; - // uint8_t xpt_site_u2[4]; + //new samples show this doesn't always quite work, there seems to be + //more than one data set transmitted in this CSBK, when the first two bits aren't 0 + //one set works, the other doesn't fit the pattern - // for (i = 0; i < 4; i++) - // { - // xpt_site_id[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16+(i*16)], 5); - // xpt_site_u1[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[21+(i*16)], 3); - // 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); - // } + // 18:55:56 Sync: +DMR slot1 [slot2] | Color Code=01 | CSBK + // Hytera XPT Site Id: 1 - Free LCN: 2 + // XPT Adj Site(s): Site:4 Free:1; Site:2 Free:1; Site:5 Free:1; + // DMR PDU Payload [0B][68][08][20][20][10][10][10][28][10][F4][C0] + // 18:55:56 Sync: +DMR [slot1] slot2 | Color Code=01 | CSBK + // 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]); - // // fprintf (stderr, " RS1: %d RS2: %d", xpt_site_u1[0], xpt_site_u2[1]); //debug + int i; + 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"); - // fprintf (stderr, " XPT Adj Site(s): "); - // for (i = 1; i < 4; i++) - // { - // if (xpt_site_id[i] != 0) - // { - // fprintf (stderr, "%d (%d) ", xpt_site_id[i], xpt_site_rp[i]); - // // fprintf (stderr, "RS1: %d RS2: %d - ", xpt_site_u1[i], xpt_site_u2[i]); //debug - // } - // } + 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? + uint8_t adj_flag = cs_pdu_bits[1]; //this is NOT the TS bit like in other XPT PDUs + + for (i = 0; i < 4; i++) + { + xpt_site_id[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16+(i*16)], 5); + xpt_site_u1[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[21+(i*16)], 3); + 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 "); diff --git a/src/dmr_flco.c b/src/dmr_flco.c index 642f280..c8bd7b8 100644 --- a/src/dmr_flco.c +++ b/src/dmr_flco.c @@ -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 //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 //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); } - //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) { - //The CSBK always uses an 8-bit TG; 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 + //The CSBK always uses an 8-bit TG/TGT; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing + //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_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 //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_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 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, " 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, "RS [%02X][%02X][%02X] ", xpt_res_a, xpt_res_b, xpt_res_c); + fprintf (stderr, " SLOT %d ", state->currentslot+1); + if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid); + fprintf (stderr, "TGT=%u SRC=%u ", target, source); fprintf (stderr, "Hytera XPT "); if (reserved == 1) fprintf (stderr, "Group "); //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); - fprintf (stderr, "F-Rpt %d", xpt_free); + //reorganized all the 'extra' data to a second line and added extra verbosity + 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); //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; goto END_FLCO; } - //XPT 'Handshake' -- not observed as of yet on any samples - if ( fid == 0x68 && (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) + //Hytera XPT 'Others' -- moved the patent opcodes here as well for now + if ( fid == 0x68 && (flco == 0x13 || flco == 0x2E || flco == 0x2F) ) { if (type == 1) 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) { //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 - 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 "); //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);