Cap+ NL; Hytera XPT Trunk Support (experimental)
This commit is contained in:
parent
a9742043b8
commit
e95e2218d9
431
src/dmr_csbk.c
431
src/dmr_csbk.c
|
|
@ -22,31 +22,33 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
int csbk_pf = 0;
|
||||
int csbk_o = 0;
|
||||
int csbk_fid = 0;
|
||||
uint64_t csbk_data = 0;
|
||||
int csbk = 0;
|
||||
|
||||
long int ccfreq = 0;
|
||||
|
||||
if(IrrecoverableErrors == 0 && CRCCorrect == 1)
|
||||
csbk_lb = ( (cs_pdu[0] & 0x80) >> 7 );
|
||||
csbk_pf = ( (cs_pdu[0] & 0x40) >> 6 );
|
||||
csbk_o = cs_pdu[0] & 0x3F;
|
||||
csbk_fid = cs_pdu[1]; //feature set id
|
||||
|
||||
//check, regardless of CRC err
|
||||
if (IrrecoverableErrors == 0)
|
||||
{
|
||||
|
||||
csbk_lb = ( (cs_pdu[0] & 0x80) >> 7 );
|
||||
csbk_pf = ( (cs_pdu[0] & 0x40) >> 6 );
|
||||
csbk_o = cs_pdu[0] & 0x3F;
|
||||
csbk_fid = cs_pdu[1]; //feature set id
|
||||
csbk_pf = ( (cs_pdu[1] & 0x80) >> 7);
|
||||
csbk = ((cs_pdu[0] & 0x3F) << 8) | cs_pdu[1]; //opcode and fid combo set
|
||||
|
||||
//update time to prevent random 'Control Channel Signal Lost' hopping
|
||||
//in the middle of voice call on current Control Channel (con+ and t3)
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
|
||||
//Hytera XPT CSBK Check -- if bits 0 and 1 are used as lcss, gi, ts, then this bit may be set on
|
||||
if (csbk_fid == 0x68 && csbk_o == 0x0A) csbk_pf = 0;
|
||||
if (csbk_pf == 1) //check the protect flag, don't run if set
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "\n Protected Control Signalling Block(s)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
if(IrrecoverableErrors == 0 && CRCCorrect == 1)
|
||||
{
|
||||
|
||||
//update time to prevent random 'Control Channel Signal Lost' hopping
|
||||
//in the middle of voice call on current Control Channel (con+ and t3)
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
|
||||
if (csbk_pf == 0) //okay to run
|
||||
{
|
||||
|
|
@ -209,6 +211,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
SetFreq(opts->rigctl_sockfd, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
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
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
|
|
@ -217,6 +220,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
rtl_udp_tune (opts, state, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -624,7 +628,56 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
//experimental, but seems to be working well
|
||||
if (csbk_fid == 0x10)
|
||||
{
|
||||
//Cap+ Channel Status PDU
|
||||
|
||||
//Cap+ Something
|
||||
if (csbk_o == 0x3A)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
fprintf (stderr, " Capacity Plus CSBK 0x3A ");
|
||||
|
||||
// 01:15:08 Sync: +DMR slot1 [slot2] | Color Code=03 | CSBK
|
||||
// Capacity Plus Channel Status - FL: 3 TS: 1 RS: 0 - Rest Channel 1 - Single Block
|
||||
// Ch1: Rest Ch2: Idle Ch3: Idle Ch4: Idle
|
||||
// Ch5: Idle Ch6: Idle Ch7: Idle Ch8: Idle
|
||||
// DMR PDU Payload [BE][10][E1][00][00][00][00][00][00][00][4E][15]
|
||||
// 01:15:08 Sync: +DMR [slot1] slot2 | Color Code=03 | CSBK
|
||||
|
||||
//FL, TS, and Rest Channel seem to be in same location as the Channel Status CSBK
|
||||
//other values are currently unknown
|
||||
// DMR PDU Payload [BA][10][C1][3B][61][11][51][00][00][00][3D][D6]
|
||||
// 01:15:08 Sync: +DMR slot1 [slot2] | Color Code=03 | CSBK
|
||||
// DMR PDU Payload [BA][10][E1][3B][61][11][51][00][00][00][46][BE]
|
||||
|
||||
}
|
||||
|
||||
//Cap+ Neighbors
|
||||
if (csbk_o == 0x3B)
|
||||
{
|
||||
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
fprintf (stderr, " Capacity Plus Neighbor List ");
|
||||
|
||||
uint8_t nl[6]; //neighbors numerical value
|
||||
uint8_t nr[6]; //neighbors current rest channel
|
||||
memset (nl, 0, sizeof (nl));
|
||||
memset (nr, 0, sizeof (nr));
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
nl[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[32+(i*8)], 4);
|
||||
nr[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[36+(i*8)], 4);
|
||||
if (nl[i]) fprintf (stderr, "S: %d R(%d) ", nl[i], nr[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Cap+ Channel Status
|
||||
if (csbk_o == 0x3E)
|
||||
{
|
||||
|
||||
|
|
@ -634,8 +687,8 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
|
||||
uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
|
||||
uint8_t ts = cs_pdu_bits[18]; //timeslot this PDU occurs in
|
||||
uint8_t res = cs_pdu_bits[19]; //unknown, always seems to be 0
|
||||
uint8_t rest_channel = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20], 4);
|
||||
uint8_t res = cs_pdu_bits[19]; //unknown, always seems to be 0 -- could be used in larger Cap+? like a bank switch?
|
||||
uint8_t rest_channel = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20], 4);
|
||||
uint8_t group_tally = 0; //set this to the number of active group channels tallied
|
||||
|
||||
uint8_t block_num = state->cap_plus_block_num;
|
||||
|
|
@ -809,6 +862,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+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
|
||||
}
|
||||
|
||||
|
|
@ -818,6 +872,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
|
|
@ -849,154 +904,20 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
} //opcode == 0x3E
|
||||
} //fid == 0x10
|
||||
|
||||
//Capacity+ Section -- fallback if issues arise
|
||||
// if (csbk_fid == 0x10)
|
||||
// {
|
||||
// //not quite sure how these tuning rules will go over
|
||||
// //if they don't work so well, may just fall back to
|
||||
// //a 'follow rest channel on no sync' only approach
|
||||
// if (csbk_o == 0x3E)
|
||||
// {
|
||||
|
||||
// //initial line break
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
|
||||
// uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
|
||||
// uint8_t ts = cs_pdu_bits[18]; //accurate?
|
||||
// uint8_t res = cs_pdu_bits[19]; //unknown??
|
||||
// uint8_t rest_channel = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20], 4);
|
||||
|
||||
// uint8_t ch[8]; //one bit per channel
|
||||
// uint8_t tg = 0;
|
||||
// uint32_t tghex = 0; //combined all tgs for debug
|
||||
// int i, j, k;
|
||||
|
||||
// //tg and channel info for trunking purposes
|
||||
// uint8_t t_tg[9];
|
||||
// memset (t_tg, 0, sizeof(t_tg));
|
||||
|
||||
// k = 0;
|
||||
// if (rest_channel != state->dmr_rest_channel)
|
||||
// {
|
||||
// state->dmr_rest_channel = rest_channel;
|
||||
// }
|
||||
// for (int i = 0; i < 8; i++)
|
||||
// {
|
||||
// ch[i] = cs_pdu_bits[i+24];
|
||||
// }
|
||||
|
||||
// //assign to cc freq to follow during no sync
|
||||
// if (state->trunk_chan_map[rest_channel] != 0)
|
||||
// {
|
||||
// state->p25_cc_freq = state->trunk_chan_map[rest_channel];
|
||||
// //set to always tuned
|
||||
// opts->p25_is_tuned = 1;
|
||||
// }
|
||||
|
||||
// fprintf (stderr, " Capacity Plus Channel Status - FL: %d TS: %d RS: %d - Rest Channel %d", fl, ts, res, rest_channel);
|
||||
|
||||
// fprintf (stderr, "\n ");
|
||||
// for (i = 0; i < 8; i++)
|
||||
// {
|
||||
// fprintf (stderr, "Ch%d: ", i+1);
|
||||
// if (ch[i] != 0)
|
||||
// {
|
||||
// tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[k*8+32], 8);
|
||||
// if (tg != 0) fprintf (stderr, " %03d ", tg);
|
||||
// else fprintf (stderr, "Priv "); //observed 000s for TG value seem to appear during a Cap+ Private TXI call
|
||||
// //add values to trunking tg/channel potentials
|
||||
// t_tg[i] = tg;
|
||||
// k++;
|
||||
|
||||
// }
|
||||
// else if (i+1 == rest_channel) fprintf (stderr, "Rest ");
|
||||
// else fprintf (stderr, "Idle ");
|
||||
|
||||
// if (i == 3) fprintf (stderr, "\n ");
|
||||
// }
|
||||
// tghex = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
// //fprintf (stderr, "\n TG Hex = 0x%06X", tghex);
|
||||
// state->dmr_mfid = 0x10;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
|
||||
// //nullify any previous TIII data (bugfix for bad assignments or system type switching)
|
||||
// sprintf(state->dmr_site_parms, "%s", "");
|
||||
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// //Skip tuning group calls if group calls are disabled
|
||||
// if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
|
||||
|
||||
// //don't tune if currently a vc on the current channel
|
||||
// if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
// {
|
||||
// for (j = 0; j < 8; j++) //go through the channels stored looking for active ones to tune to
|
||||
// {
|
||||
// char mode[8]; //allow, block, digital, enc, etc
|
||||
|
||||
// //if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
// //comparison below will look for an 'A' to write to mode if it is allowed
|
||||
// if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
||||
|
||||
// for (int i = 0; i < state->group_tally; i++)
|
||||
// {
|
||||
// if (state->group_array[i].groupNumber == t_tg[j])
|
||||
// {
|
||||
// fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
// strcpy (mode, state->group_array[i].groupMode);
|
||||
// }
|
||||
// }
|
||||
|
||||
// //no more 0 reporting, that was some bad code that caused that issue
|
||||
// //without priority, this will tune the first one it finds (if group isn't blocked)
|
||||
// if (t_tg[j] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
|
||||
// {
|
||||
// if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
|
||||
// {
|
||||
// //RIGCTL
|
||||
// if (opts->use_rigctl == 1)
|
||||
// {
|
||||
// if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
// SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
|
||||
// state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
// opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
// j = 11; //break loop
|
||||
// }
|
||||
|
||||
// //rtl_udp
|
||||
// else if (opts->audio_in_type == 3)
|
||||
// {
|
||||
// rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
|
||||
// state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
// opts->p25_is_tuned = 1;
|
||||
// j = 11; //break loop
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
// SKIPCAP: ; //do nothing
|
||||
// }
|
||||
|
||||
//Connect+ Section
|
||||
if (csbk_fid == 0x06)
|
||||
{
|
||||
|
||||
if (csbk_o == 0x01)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint8_t nb1 = cs_pdu[2] & 0x3F;
|
||||
uint8_t nb2 = cs_pdu[3] & 0x3F;
|
||||
uint8_t nb3 = cs_pdu[4] & 0x3F;
|
||||
uint8_t nb4 = cs_pdu[5] & 0x3F;
|
||||
uint8_t nb5 = cs_pdu[6] & 0x3F;
|
||||
uint8_t nb5 = cs_pdu[6] & 0x3F;
|
||||
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Neighbors\n");
|
||||
fprintf (stderr, " NB1(%02d), NB2(%02d), NB3(%02d), NB4(%02d), NB5(%02d)", nb1, nb2, nb3, nb4, nb5);
|
||||
|
|
@ -1080,6 +1001,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->is_con_plus = 1; //flag on
|
||||
state->last_vc_sync_time = time(NULL); //bugfix: set sync here so we don't immediately tune back to CC constantly.
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
|
|
@ -1090,6 +1012,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
opts->p25_is_tuned = 1;
|
||||
state->is_con_plus = 1; //flag on
|
||||
state->last_vc_sync_time = time(NULL); //bugfix: set sync here so we don't immediately tune back to CC constantly.
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1102,7 +1025,201 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
}
|
||||
} //end Connect+
|
||||
|
||||
//Hytera XPT
|
||||
if (csbk_fid == 0x68)
|
||||
{
|
||||
//XPT Site Status -- Very Very Experimental, WIP, Don't be surprised by bad decodes or broken trunking
|
||||
if (csbk_o == 0x0A)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
uint8_t xpt_ch[6]; //one tg/call per timeslot
|
||||
uint16_t tg = 0; //8-bit TG value or hash
|
||||
int i, j;
|
||||
|
||||
//tg and channel info for trunking purposes
|
||||
uint8_t t_tg[24];
|
||||
memset (t_tg, 0, sizeof(t_tg));
|
||||
|
||||
uint8_t xpt_seq = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[0], 2); //this replaces the CSBK lb and pf
|
||||
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;
|
||||
|
||||
//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+1, 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)
|
||||
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);
|
||||
else
|
||||
{
|
||||
if (xpt_ch[i] == 3) fprintf (stderr, " Null "); //offline?, free? but also group call if the TG value is populated? Wut? Null should cover both cases...maybe
|
||||
else if (xpt_ch[i] == 2) fprintf (stderr, " Priv "); //This seems to be used on both private data and private calls, but one or the other has a 0 TG value?
|
||||
else if (xpt_ch[i] == 1) fprintf (stderr, " Unk "); //the 01 value has not been observed as of yet, group data?
|
||||
else if (xpt_ch[i] == 0) fprintf (stderr, " Idle "); //Idle appears to always be a 0, or could indicate Group Data (including status CSBK and VLC/TLC)
|
||||
}
|
||||
|
||||
if (i == 2) fprintf (stderr, "\n ");
|
||||
|
||||
|
||||
//add values to trunking tg/channel potentials
|
||||
if (tg != 0) t_tg[i+(xpt_seq*6)] = tg;
|
||||
|
||||
}
|
||||
|
||||
//add string for ncurses terminal display
|
||||
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free+1);
|
||||
|
||||
//assign to cc freq to follow during no sync
|
||||
//current theory is that user should set channel 0 as the 'home repeater' frequency
|
||||
//this can change if this is ever tested by anybody properly
|
||||
if (state->trunk_chan_map[0] != 0)
|
||||
{
|
||||
state->p25_cc_freq = state->trunk_chan_map[0];
|
||||
//set to always tuned
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
|
||||
//Skip tuning calls if group calls are disabled
|
||||
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) )
|
||||
{
|
||||
for (j = 0; j < 6; j++) //go through the channels stored looking for active ones to tune to
|
||||
{
|
||||
char mode[8]; //allow, block, digital, enc, etc
|
||||
|
||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
||||
|
||||
//this won't work properly on hashed TGT values
|
||||
//unless users load a TGT hash in a csv file
|
||||
//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)])
|
||||
{
|
||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
strcpy (mode, state->group_array[i].groupMode);
|
||||
}
|
||||
}
|
||||
|
||||
//without priority, this will tune the first one it finds (if group isn't blocked)
|
||||
if (t_tg[j+(xpt_seq*6)] != 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
|
||||
{
|
||||
//RIGCTL
|
||||
if (opts->use_rigctl == 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+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
|
||||
}
|
||||
|
||||
//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+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} //end tuning
|
||||
|
||||
SKIPXPT: ;
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
//XPT Site Information - Adj Site Info
|
||||
if (csbk_o == 0x0B)
|
||||
{
|
||||
|
||||
//initial line break
|
||||
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
|
||||
|
||||
// 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];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
sprintf (state->dmr_branding_sub, "XPT ");
|
||||
|
||||
|
||||
}
|
||||
|
||||
} //end Hytera XPT section
|
||||
|
||||
}
|
||||
END:
|
||||
|
|
|
|||
349
src/dmr_flco.c
349
src/dmr_flco.c
|
|
@ -30,18 +30,43 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
int is_cap_plus = 0;
|
||||
int is_alias = 0;
|
||||
int is_gps = 0;
|
||||
|
||||
//XPT 'Things'
|
||||
int is_xpt = 0;
|
||||
uint8_t xpt_hand = 0; //handshake
|
||||
uint8_t xpt_free = 0; //free repeater
|
||||
uint8_t xpt_int = 0; //xpt channel to interrupt (channel/repeater call should occur on?)
|
||||
uint8_t xpt_res_a = 0; //unknown values of other bits of the XPT LC
|
||||
uint8_t xpt_res_b = 0; //unknown values of other bits of the XPT LC
|
||||
uint8_t xpt_res_c = 0; //unknown values of other bits of the XPT LC
|
||||
uint8_t target_hash[24]; //for XPT (and others if desired, get the hash and compare against SLC or XPT Status CSBKs)
|
||||
uint8_t tg_hash = 0; //value of the hashed TG
|
||||
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t unk = 0; //flag for unknown FLCO + FID combo
|
||||
|
||||
|
||||
pf = (uint8_t)(lc_bits[0]); //Protect Flag
|
||||
reserved = (uint8_t)(lc_bits[1]); //Reserved
|
||||
pf = (uint8_t)(lc_bits[0]); //Protect Flag -- Hytera XPT uses this to signify which TS the PDU is on
|
||||
reserved = (uint8_t)(lc_bits[1]); //Reserved -- Hytera XPT G/I bit; 0 - Individual; 1 - Group;
|
||||
flco = (uint8_t)ConvertBitIntoBytes(&lc_bits[2], 6); //Full Link Control Opcode
|
||||
fid = (uint8_t)ConvertBitIntoBytes(&lc_bits[8], 8); //Feature set ID (FID)
|
||||
so = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //Service Options
|
||||
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //Target or Talk Group
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24);
|
||||
|
||||
//read ahead a little to get this for the xpt flag
|
||||
if (IrrecoverableErrors == 0 && flco == 0x09 && fid == 0x68)
|
||||
{
|
||||
sprintf (state->dmr_branding, "%s", " Hytera");
|
||||
sprintf (state->dmr_branding_sub, "XPT ");
|
||||
}
|
||||
|
||||
//look at the dmr_branding_sub for the XPT string
|
||||
//branding sub is set at CSBK(68-3A and 3B), SLCO 8, and here on 0x09
|
||||
if (strcmp (state->dmr_branding_sub, "XPT ") == 0) is_xpt = 1;
|
||||
|
||||
//hytera XPT -- disable the pf flag, is used for TS value in some Hytera XPT PDUs
|
||||
if (is_xpt) pf = 0;
|
||||
|
||||
//check protect flag
|
||||
if (pf == 1)
|
||||
{
|
||||
|
|
@ -53,18 +78,6 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
goto END_FLCO;
|
||||
}
|
||||
|
||||
//look for Cap+ on VLC header, then set source and/or rest channel appropriately
|
||||
if (IrrecoverableErrors == 0 && type == 1 && fid == 0x10 && (flco == 0x04 || flco == 0x07) ) //0x07 appears to be a cap+ txi private call
|
||||
{
|
||||
is_cap_plus = 1;
|
||||
capsite = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 4); //can't verify, just speculating
|
||||
restchannel = (int)ConvertBitIntoBytes(&lc_bits[52], 4); //was 48,8
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
}
|
||||
|
||||
|
||||
if (IrrecoverableErrors == 0)
|
||||
{
|
||||
|
||||
|
|
@ -72,25 +85,34 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
else state->dmr_flcoR = flco;
|
||||
|
||||
//Embedded Talker Alias Header Only (format and len storage)
|
||||
if (fid == 0 && type == 3 && flco == 0x04)
|
||||
if ( (fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
|
||||
{
|
||||
dmr_embedded_alias_header(opts, state, lc_bits);
|
||||
}
|
||||
|
||||
//Embedded Talker Alias Header (continuation) and Blocks
|
||||
if (fid == 0 && type == 3 && flco > 0x3 && flco < 0x08)
|
||||
if ( (fid == 0 || fid == 0x68) && type == 3 && flco > 0x03 && flco < 0x08)
|
||||
{
|
||||
is_alias = 1;
|
||||
dmr_embedded_alias_blocks(opts, state, lc_bits);
|
||||
}
|
||||
|
||||
//Embedded GPS
|
||||
if (fid == 0 && type == 3 && flco == 0x08)
|
||||
if ( (fid == 0 || fid == 0x68) && fid == 0 && type == 3 && flco == 0x08)
|
||||
{
|
||||
is_gps = 1;
|
||||
dmr_embedded_gps(opts, state, lc_bits);
|
||||
}
|
||||
|
||||
//look for Cap+ on VLC header, then set source and/or rest channel appropriately
|
||||
if (type == 1 && fid == 0x10 && (flco == 0x04 || flco == 0x07) ) //0x07 appears to be a cap+ txi private call
|
||||
{
|
||||
is_cap_plus = 1;
|
||||
capsite = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 4); //don't believe so
|
||||
restchannel = (int)ConvertBitIntoBytes(&lc_bits[52], 4); //
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
|
||||
}
|
||||
|
||||
//Unknown CapMax/Moto Things
|
||||
if (fid == 0x10 && (flco == 0x08 || flco == 0x28))
|
||||
{
|
||||
|
|
@ -113,8 +135,16 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
{
|
||||
fprintf (stderr, "%s \n", KRED);
|
||||
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||
fprintf (stderr, " Data Terminator (TD_LC)");
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
fprintf (stderr, " Data Terminator (TD_LC) ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//reset data header format storage
|
||||
state->data_header_format[slot] = 7;
|
||||
//flag off data header validity
|
||||
state->data_header_valid[slot] = 0;
|
||||
//flag off conf data flag
|
||||
state->data_conf_data[slot] = 0;
|
||||
|
||||
goto END_FLCO;
|
||||
}
|
||||
|
||||
|
|
@ -132,8 +162,127 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
goto END_FLCO;
|
||||
}
|
||||
|
||||
//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
|
||||
//the TLC preceeds the VLC for a 'handshake' call setup in XPT
|
||||
|
||||
//truncate if XPT is set
|
||||
if (is_xpt == 1)
|
||||
{
|
||||
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[32], 16); //16-bit allocation
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16); //16-bit allocation
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
//XPT Call 'Grant' 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
|
||||
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;
|
||||
|
||||
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[32], 16); //16-bit allocation
|
||||
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_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);
|
||||
|
||||
//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
|
||||
|
||||
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=%X ", xpt_int+1); //repeater channel to 'interrupt' with this call?
|
||||
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, "Hytera XPT ");
|
||||
if (reserved == 1) fprintf (stderr, "Group "); //according to observation
|
||||
else fprintf (stderr, "Private "); //according to observation
|
||||
fprintf (stderr, "Call Grant ");
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "F-Rpt %d", xpt_free+1);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
|
||||
//add string for ncurses terminal display
|
||||
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free+1);
|
||||
|
||||
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)
|
||||
{
|
||||
if (type == 1) fprintf (stderr, "%s \n", KCYN);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KCYN);
|
||||
if (type == 3) fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||
fprintf (stderr, " Hytera ");
|
||||
unk = 1;
|
||||
goto END_FLCO;
|
||||
}
|
||||
|
||||
//unknown other manufacturer or OTA ENC, etc.
|
||||
if (fid != 0 && fid != 0x68 && fid != 0x10) //removed tait from the list
|
||||
//removed tait from the list, added hytera 0x08
|
||||
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08)
|
||||
{
|
||||
if (type == 1) fprintf (stderr, "%s \n", KYEL);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KYEL);
|
||||
|
|
@ -147,11 +296,9 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
}
|
||||
|
||||
//will want to continue to observe for different flco and fid combinations to find out their meaning
|
||||
//Standard Addressing/Cap+ Addressing (trying to avoid embedded alias and gps, etc)
|
||||
if(IrrecoverableErrors == 0 && is_alias == 0 && is_gps == 0)
|
||||
{
|
||||
//set overarching manufacturer in use when non-standard feature id set is up
|
||||
//may not want to set moto 0x10 here either, lots of radios use that set as well
|
||||
if (fid != 0) state->dmr_mfid = fid;
|
||||
|
||||
if (type != 2) //VLC and EMB, set our target, source, so, and fid per channel
|
||||
|
|
@ -222,6 +369,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
|
||||
fprintf (stderr, " SLOT %d ", state->currentslot+1);
|
||||
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
|
||||
if (opts->payload == 1 && is_xpt == 1) fprintf(stderr, "HASH=%d ", tg_hash);
|
||||
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
|
||||
|
||||
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
|
||||
|
|
@ -229,7 +377,10 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
//0x23 on the Embedded Voice Burst Sync seems to indicate a Cap+ or Cap+ TXI Private Call in progress
|
||||
//0x20 on the Embedded Voice Burst Sync seems to indicate a Moto (non-specific) Group Call in progress
|
||||
//its possible that both EMB FID 0x10 FLCO 0x20 and 0x23 are just Moto but non-specific (observed 0x20 on Tier 2)
|
||||
if (flco == 0x4 || flco == 0x5 || flco == 0x7 || flco == 0x23) //Cap+ Things
|
||||
|
||||
if (fid == 0x68) sprintf (state->call_string[slot], " Hytera ");
|
||||
|
||||
else if (flco == 0x4 || flco == 0x5 || flco == 0x7 || flco == 0x23) //Cap+ Things
|
||||
{
|
||||
sprintf (state->call_string[slot], " Cap+");
|
||||
fprintf (stderr, "Cap+ ");
|
||||
|
|
@ -244,12 +395,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
fprintf (stderr, "Private ");
|
||||
}
|
||||
}
|
||||
else if (flco == 0x3) //UU_V_Ch_Usr
|
||||
else if (flco == 0x3) //UU_V_Ch_Usr -- still valid on hytera VLC
|
||||
{
|
||||
sprintf (state->call_string[slot], " Private ");
|
||||
fprintf (stderr, "Private ");
|
||||
}
|
||||
else //Grp_V_Ch_Usr
|
||||
else //Grp_V_Ch_Usr -- still valid on hytera VLC
|
||||
{
|
||||
sprintf (state->call_string[slot], " Group ");
|
||||
fprintf (stderr, "Group ");
|
||||
|
|
@ -273,64 +424,74 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
//REMUS! Uncomment Line Below if desired
|
||||
// else strcat (state->call_string[slot], " ");
|
||||
|
||||
/* Check the "Service Option" bits */
|
||||
if(so & 0x30)
|
||||
//Motorola FID 0x10 Only
|
||||
if (fid == 0x10)
|
||||
{
|
||||
/* Experimentally determined with DSD+,
|
||||
* is equal to 0x2, this is a TXI call */
|
||||
if((so & 0x30) == 0x20)
|
||||
/* Check the "Service Option" bits */
|
||||
if(so & 0x30)
|
||||
{
|
||||
/* Experimentally determined with DSD+,
|
||||
* is equal to 0x2, this is a TXI call */
|
||||
if((so & 0x30) == 0x20)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " TXI");
|
||||
fprintf(stderr, "TXI ");
|
||||
}
|
||||
else
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " RES");
|
||||
fprintf(stderr, "RS%d ", (so & 0x30) >> 4);
|
||||
}
|
||||
}
|
||||
if(so & 0x08)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " TXI");
|
||||
fprintf(stderr, "TXI ");
|
||||
// strcat (state->call_string[slot], "-BC ");
|
||||
fprintf(stderr, "Broadcast ");
|
||||
}
|
||||
else
|
||||
if(so & 0x04)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " RES");
|
||||
fprintf(stderr, "RS%d ", (so & 0x30) >> 4);
|
||||
// strcat (state->call_string[slot], "-OVCM ");
|
||||
fprintf(stderr, "OVCM ");
|
||||
}
|
||||
}
|
||||
if(so & 0x08)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], "-BC ");
|
||||
fprintf(stderr, "Broadcast ");
|
||||
}
|
||||
if(so & 0x04)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], "-OVCM ");
|
||||
fprintf(stderr, "OVCM ");
|
||||
}
|
||||
if(so & 0x03)
|
||||
{
|
||||
if((so & 0x03) == 0x01)
|
||||
if(so & 0x03)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], "-P1");
|
||||
fprintf(stderr, "Priority 1 ");
|
||||
}
|
||||
else if((so & 0x03) == 0x02)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], "-P2");
|
||||
fprintf(stderr, "Priority 2 ");
|
||||
}
|
||||
else if((so & 0x03) == 0x03)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], "-P3");
|
||||
fprintf(stderr, "Priority 3 ");
|
||||
}
|
||||
else /* We should never go here */
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " ");
|
||||
fprintf(stderr, "No Priority ");
|
||||
}
|
||||
if((so & 0x03) == 0x01)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], "-P1");
|
||||
fprintf(stderr, "Priority 1 ");
|
||||
}
|
||||
else if((so & 0x03) == 0x02)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], "-P2");
|
||||
fprintf(stderr, "Priority 2 ");
|
||||
}
|
||||
else if((so & 0x03) == 0x03)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], "-P3");
|
||||
fprintf(stderr, "Priority 3 ");
|
||||
}
|
||||
else /* We should never go here */
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " ");
|
||||
fprintf(stderr, "No Priority ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//should rework this back into the upper portion
|
||||
if (fid == 0x68) fprintf (stderr, "Hytera ");
|
||||
if (is_xpt) fprintf (stderr, "XPT ");
|
||||
if (fid == 0x68 && flco == 0x00) fprintf (stderr, "Group ");
|
||||
if (fid == 0x68 && flco == 0x03) fprintf (stderr, "Private ");
|
||||
|
||||
fprintf(stderr, "Call ");
|
||||
|
||||
|
||||
|
|
@ -380,8 +541,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||
END_FLCO:
|
||||
if (unk == 1 || pf == 1)
|
||||
{
|
||||
// fprintf(stderr, " FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
|
||||
fprintf(stderr, " FLCO=0x%02X FID=0x%02X ", flco, fid); //not all LC PDUs contain SVC bits (see TD_LC)
|
||||
fprintf(stderr, " FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
|
|
@ -648,10 +808,17 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||
//Con+
|
||||
uint8_t con_netid = (uint8_t)ConvertBitIntoBytes(&slco_bits[8], 8);
|
||||
uint8_t con_siteid = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 8);
|
||||
|
||||
//Cap+
|
||||
uint8_t capsite = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 4); //can't verify, just speculating
|
||||
uint8_t restchannel = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 4); //was 12,8
|
||||
uint8_t cap_reserved = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //unknown if any significant value?
|
||||
uint8_t capsite = (uint8_t)ConvertBitIntoBytes(&slco_bits[22], 3); //Seems more consistent
|
||||
uint8_t restchannel = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 4);
|
||||
uint8_t cap_reserved = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 2); //significant value?
|
||||
|
||||
//Hytera XPT
|
||||
uint8_t xpt_free = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 4); //free repeater
|
||||
//the next two per SDRTrunk, but only 0 values ever observed here
|
||||
uint8_t xpt_pri = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 4); //priority repeater
|
||||
uint8_t xpt_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //priority TG hash
|
||||
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
|
|
@ -700,20 +867,12 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||
fprintf (stderr, " SLCO Activity Update TS1: %X Hash: %02X TS2: %X Hash: %02X", ts1_act, ts1_hash, ts2_act, ts2_hash); //102 361-2 7.1.3.2
|
||||
else if (slco == 0x9)
|
||||
{
|
||||
//remove all setting of branding/sub from SLCO, can cause false positives even with seeming good CRC
|
||||
|
||||
// state->dmr_mfid = 0x10;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Con+ ");
|
||||
fprintf (stderr, " SLCO Connect Plus Voice Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
|
||||
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
|
||||
}
|
||||
|
||||
else if (slco == 0xA)
|
||||
{
|
||||
// state->dmr_mfid = 0x10;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Con+ ");
|
||||
fprintf (stderr, " SLCO Connect Plus Control Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
|
||||
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
|
||||
|
||||
|
|
@ -727,19 +886,21 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||
|
||||
else if (slco == 0xF)
|
||||
{
|
||||
// state->dmr_mfid = 0x10;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest Channel %d - RS: %02X", capsite+1, restchannel, cap_reserved);
|
||||
// state->dmr_rest_channel = restchannel; //test without, may work better
|
||||
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest Channel %d - RS: %02X", capsite, restchannel, cap_reserved);
|
||||
//assign to cc freq if available
|
||||
if (state->trunk_chan_map[restchannel] != 0)
|
||||
{
|
||||
state->p25_cc_freq = state->trunk_chan_map[restchannel];
|
||||
}
|
||||
|
||||
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
|
||||
// sprintf(state->dmr_site_parms, "%s", "");
|
||||
}
|
||||
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);
|
||||
//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+1);
|
||||
sprintf (state->dmr_branding_sub, "XPT ");
|
||||
}
|
||||
|
||||
else fprintf (stderr, " SLCO Unknown - %d ", slco);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ char * FM_banner[9] = {
|
|||
" ██║ ██║ ╚═══██╗██║ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
|
||||
" ██████╔╝██████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║███████╗",
|
||||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝",
|
||||
" 'Lite' Edition v2.0.0-31-g3167f9d Windows 32-bit RC4 "
|
||||
" 'Lite' Edition v2.0.0-35-g37c24d0 Windows 32-bit RC4 "
|
||||
};
|
||||
|
||||
int comp (const void *a, const void *b)
|
||||
|
|
|
|||
|
|
@ -2061,7 +2061,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||
if (opts->ncurses_compact == 1)
|
||||
{
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
printw ("| Digital Speech Decoder: Florida Man Edition - Win32 %s \n", "v2.0.0-31-g3167f9d RC4");
|
||||
printw ("| Digital Speech Decoder: Florida Man Edition - Win32 %s \n", "v2.0.0-35-g37c24d0 RC4");
|
||||
}
|
||||
if (opts->ncurses_compact == 0)
|
||||
{
|
||||
|
|
@ -2073,7 +2073,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||
if (i == 2) printw (" 'q' to Quit ");
|
||||
if (i == 4) printw (" MBElib %s", versionstr);
|
||||
if (i == 5) printw (" %s ", "Win32 RC4"); //printw (" %s \n", GIT_TAG);
|
||||
if (i == 6) printw (" %s \n", "v2.0.0-31-g3167f9d"); //printw (" %s \n", GIT_TAG);
|
||||
if (i == 6) printw (" %s \n", "v2.0.0-35-g37c24d0"); //printw (" %s \n", GIT_TAG);
|
||||
else printw ("\n");
|
||||
}
|
||||
attroff(COLOR_PAIR(6)); //6
|
||||
|
|
|
|||
Loading…
Reference in New Issue