mirror of https://github.com/lwvmobile/dsd-fme.git
EDACS: Standard display rewrite, parsing/RE fixes, tune i-calls and all-calls (#246)
* EDACS EA: Fix reversed TDMA/data calls * EDACS: deduplicate ncurses printing logic * EDACS: pass call state via new state struct field * EDACS: RE some differences from Standard spec * EDACS: show state for data calls * EDACS: tune individual calls on Standard * EDACS: tune all-calls on Standard * EDACS: properly identify emergency on channel updates * EDACS: fix build break * EDACS: fix conditions for refreshing the display source * EDACS EA: Identify calls as voice for display * EDACS: voice channel update emergency refactor * EDACS: Show interconnect calls in call log * EDACS EA: show unknown data channel assignments in log * EDACS: check LCN is not 0 before assigning it * EDACS: C operator precedence is dumb * Initialize edacs_vc_call_type * use j and not i in call_matrix for call history; --------- Co-authored-by: lwvmobile <lwvmobile@gmail.com>
This commit is contained in:
parent
c8d00846b1
commit
a5c5be3b95
|
|
@ -702,6 +702,16 @@ typedef struct
|
|||
int edacs_cc_lcn; //current lcn for the edacs control channel
|
||||
int edacs_vc_lcn; //current lcn for any active vc (not the one we are tuned/tuning to)
|
||||
int edacs_tuned_lcn; //the vc we are currently tuned to...above variable is for updating all in the matrix
|
||||
int edacs_vc_call_type; //the type of call on the given VC - see defines below
|
||||
|
||||
//flags for EDACS call type
|
||||
#define EDACS_IS_VOICE 0x01
|
||||
#define EDACS_IS_DIGITAL 0x02
|
||||
#define EDACS_IS_EMERGENCY 0x04
|
||||
#define EDACS_IS_GROUP 0x08
|
||||
#define EDACS_IS_INDIVIDUAL 0x10
|
||||
#define EDACS_IS_ALL_CALL 0x20
|
||||
#define EDACS_IS_INTERCONNECT 0x40
|
||||
|
||||
//trunking group and lcn freq list
|
||||
long int trunk_lcn_freq[26]; //max number on an EDACS system, should be enough on DMR too hopefully
|
||||
|
|
|
|||
|
|
@ -1047,7 +1047,7 @@ initState (dsd_state * state)
|
|||
|
||||
//edacs - may need to make these user configurable instead for stability on non-ea systems
|
||||
state->ea_mode = -1; //init on -1, 0 is standard, 1 is ea
|
||||
|
||||
state->edacs_vc_call_type = 0;
|
||||
state->esk_mask = 0x0; //esk mask value
|
||||
state->edacs_site_id = 0;
|
||||
state->edacs_lcn_count = 0;
|
||||
|
|
|
|||
|
|
@ -2012,13 +2012,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||
call_matrix[state->edacs_vc_lcn][1] = state->edacs_vc_lcn;
|
||||
call_matrix[state->edacs_vc_lcn][2] = state->lasttg;
|
||||
//EDACS standard does not provide source LIDs on channel update messages; instead, for the sake of display, let's
|
||||
//assume the prior source for a given LCN is still accurate, unless we have an updated one provided.
|
||||
//assume the prior source for a given LCN is still accurate, unless we have an updated one provided (or the call
|
||||
//type has changed under us).
|
||||
//
|
||||
//If you MUST have perfectly-accurate source LIDs, look at the logged CC messages yourself - incorrect source LIDs
|
||||
//may be displayed if we miss an initial call channel assignment.
|
||||
if (state->ea_mode == 1 || state->lastsrc != 0)
|
||||
if (state->ea_mode == 1 || (state->lastsrc != 0 || call_matrix[state->edacs_vc_lcn][4] != state->edacs_vc_call_type))
|
||||
call_matrix[state->edacs_vc_lcn][3] = state->lastsrc;
|
||||
call_matrix[state->edacs_vc_lcn][4] = 1;
|
||||
call_matrix[state->edacs_vc_lcn][4] = state->edacs_vc_call_type;
|
||||
call_matrix[state->edacs_vc_lcn][5] = time(NULL);
|
||||
}
|
||||
|
||||
|
|
@ -3511,76 +3512,81 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||
printw (" Control Channel");
|
||||
attroff (COLOR_PAIR(1));
|
||||
}
|
||||
|
||||
int print_call = 0;
|
||||
//print active calls on corresponding LCN line
|
||||
if ((i != state->edacs_cc_lcn) && time(NULL) - call_matrix[i][5] < 2)
|
||||
{
|
||||
print_call = 3;
|
||||
attron (COLOR_PAIR(3));
|
||||
if (state->ea_mode == 1) {
|
||||
if (call_matrix[i][2] + 1 == 0)
|
||||
// System all-call
|
||||
printw (" TGT [ SYSTEM ] SRC [%8lld] All-Call", call_matrix[i][3] );
|
||||
else if (call_matrix[i][2] > 100000)
|
||||
// I-Call
|
||||
printw (" TGT [%8lld] SRC [%8lld] I-Call", call_matrix[i][2] - 100000, call_matrix[i][3] );
|
||||
else
|
||||
// Group call
|
||||
printw (" TGT [%8lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (call_matrix[i][2] + 1 == 0)
|
||||
// System all-call
|
||||
printw (" TGT [SYSTEM][SYSTEM] SRC [%5lld] All-Call", call_matrix[i][3] );
|
||||
else if (call_matrix[i][2] > 10000)
|
||||
// I-Call
|
||||
printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", call_matrix[i][2] - 10000, call_matrix[i][3] );
|
||||
else
|
||||
// Group call
|
||||
printw (" TGT [%6lld][%02d-%03d] SRC [%5lld]", call_matrix[i][2], a, fs, call_matrix[i][3] );
|
||||
}
|
||||
for (int k = 0; k < state->group_tally; k++)
|
||||
{
|
||||
if (state->group_array[k].groupNumber == call_matrix[i][2] && call_matrix[i][2] != 0)
|
||||
{
|
||||
printw (" [%s]", state->group_array[k].groupName);
|
||||
printw ("[%s]", state->group_array[k].groupMode);
|
||||
break;
|
||||
}
|
||||
else if (state->group_array[k].groupNumber == call_matrix[i][3] && call_matrix[i][3] != 0)
|
||||
{
|
||||
printw (" [%s]", state->group_array[k].groupName);
|
||||
printw ("[%s]", state->group_array[k].groupMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
attroff (COLOR_PAIR(3));
|
||||
}
|
||||
//print dying or dead calls in red for x seconds longer
|
||||
if ( (i != state->edacs_cc_lcn) && (time(NULL) - call_matrix[i][5] >= 2) && (time(NULL) - call_matrix[i][5] < 5) )
|
||||
else if ( (i != state->edacs_cc_lcn) && (time(NULL) - call_matrix[i][5] >= 2) && (time(NULL) - call_matrix[i][5] < 5) )
|
||||
{
|
||||
print_call = 2;
|
||||
attron (COLOR_PAIR(2));
|
||||
}
|
||||
|
||||
if (print_call != 0)
|
||||
{
|
||||
if (state->ea_mode == 1) {
|
||||
if (call_matrix[i][2] + 1 == 0)
|
||||
// Voice call
|
||||
if ((call_matrix[i][4] & EDACS_IS_VOICE) != 0)
|
||||
{
|
||||
// System all-call
|
||||
printw (" TGT [ SYSTEM ] SRC [%8lld] All-Call", call_matrix[i][3] );
|
||||
else if (call_matrix[i][2] > 100000)
|
||||
if ((call_matrix[i][4] & EDACS_IS_GROUP) != 0)
|
||||
printw (" TGT [%8lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] );
|
||||
// I-Call
|
||||
printw (" TGT [%8lld] SRC [%8lld] I-Call", call_matrix[i][2] - 100000, call_matrix[i][3] );
|
||||
else if ((call_matrix[i][4] & EDACS_IS_INDIVIDUAL) != 0)
|
||||
printw (" TGT [%8lld] SRC [%8lld] I-Call", call_matrix[i][2], call_matrix[i][3] );
|
||||
// System all-call
|
||||
else if ((call_matrix[i][4] & EDACS_IS_ALL_CALL) != 0)
|
||||
printw (" TGT [ SYSTEM ] SRC [%8lld] All-Call", call_matrix[i][3] );
|
||||
// Interconnect call
|
||||
else if ((call_matrix[i][4] & EDACS_IS_INTERCONNECT) != 0)
|
||||
printw (" TGT [ SYSTEM ] SRC [%8lld] Interconnect", call_matrix[i][3] );
|
||||
// Unknown call
|
||||
else
|
||||
printw (" Unknown call type" );
|
||||
|
||||
// Call flags
|
||||
if ((call_matrix[i][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]");
|
||||
else printw (" [Dig]");
|
||||
if ((call_matrix[i][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]");
|
||||
}
|
||||
else
|
||||
// Group call
|
||||
printw (" TGT [%8lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] );
|
||||
// Data call
|
||||
printw (" TGT [ DATA ] SRC [%8lld] Data", call_matrix[i][3] );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (call_matrix[i][2] + 1 == 0)
|
||||
// System all-call
|
||||
printw (" TGT [SYSTEM][SYSTEM] SRC [%5lld] All-Call", call_matrix[i][3] );
|
||||
else if (call_matrix[i][2] > 10000)
|
||||
// I-Call
|
||||
printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", call_matrix[i][2] - 10000, call_matrix[i][3] );
|
||||
else
|
||||
// Voice call
|
||||
if ((call_matrix[i][4] & EDACS_IS_VOICE) != 0)
|
||||
{
|
||||
// Group call
|
||||
printw (" TGT [%6lld][%02d-%03d] SRC [%5lld]", call_matrix[i][2], a, fs, call_matrix[i][3] );
|
||||
if ((call_matrix[i][4] & EDACS_IS_GROUP) != 0)
|
||||
printw (" TGT [%6lld][%02d-%03d] SRC [%5lld]", call_matrix[i][2], a, fs, call_matrix[i][3] );
|
||||
// I-Call
|
||||
else if ((call_matrix[i][4] & EDACS_IS_INDIVIDUAL) != 0)
|
||||
printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", call_matrix[i][2], call_matrix[i][3] );
|
||||
// System all-call
|
||||
else if ((call_matrix[i][4] & EDACS_IS_ALL_CALL) != 0)
|
||||
printw (" TGT [ SYSTEM ] SRC [%5lld] All-Call", call_matrix[i][3] );
|
||||
// Interconnect call
|
||||
else if ((call_matrix[i][4] & EDACS_IS_INTERCONNECT) != 0)
|
||||
printw (" TGT [ SYSTEM ] SRC [%5lld] Interconnect", call_matrix[i][3] );
|
||||
// Unknown call
|
||||
else
|
||||
printw (" Unknown call type" );
|
||||
|
||||
// Call flags
|
||||
if ((call_matrix[i][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]");
|
||||
else printw (" [Dig]");
|
||||
if ((call_matrix[i][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]");
|
||||
}
|
||||
else
|
||||
// Data call
|
||||
printw (" TGT [ DATA ] SRC [%8lld] Data", call_matrix[i][3] );
|
||||
}
|
||||
for (int k = 0; k < state->group_tally; k++)
|
||||
{
|
||||
|
|
@ -3597,9 +3603,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||
break;
|
||||
}
|
||||
}
|
||||
attroff (COLOR_PAIR(2));
|
||||
|
||||
if (print_call == 3)
|
||||
attroff (COLOR_PAIR(3));
|
||||
else if (print_call == 2)
|
||||
attroff (COLOR_PAIR(2));
|
||||
}
|
||||
if (i == state->edacs_tuned_lcn && opts->p25_is_tuned == 1) printw (" **T**"); //asterisk which lcn is opened
|
||||
|
||||
if (i == state->edacs_tuned_lcn && opts->p25_is_tuned == 1) printw (" **T**"); //asterisk which lcn is tuned
|
||||
printw ("\n");
|
||||
}
|
||||
if (state->carrier == 1)
|
||||
|
|
@ -3704,30 +3715,67 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||
printw ("LCN [%2lld] ", call_matrix[j][1]);
|
||||
if (state->ea_mode == 1)
|
||||
{
|
||||
if (call_matrix[j][2] + 1 == 0)
|
||||
// System all-call
|
||||
printw ("Target [ SYSTEM ] Source [%8lld] All-Call", call_matrix[j][3]);
|
||||
else if (call_matrix[j][2] > 100000)
|
||||
// I-Call
|
||||
printw ("Target [%8lld] Source [%8lld] I-Call", call_matrix[j][2] - 100000, call_matrix[j][3]);
|
||||
else
|
||||
// Voice call
|
||||
if ((call_matrix[j][4] & EDACS_IS_VOICE) != 0)
|
||||
{
|
||||
// Group call
|
||||
printw ("Target [%8lld] Source [%8lld]", call_matrix[j][2], call_matrix[j][3]);
|
||||
if ((call_matrix[j][4] & EDACS_IS_GROUP) != 0)
|
||||
printw ("Target [%8lld] Source [%8lld]", call_matrix[j][2], call_matrix[j][3]);
|
||||
// I-Call
|
||||
else if ((call_matrix[j][4] & EDACS_IS_INDIVIDUAL) != 0)
|
||||
printw ("Target [%8lld] Source [%8lld] I-Call", call_matrix[j][2], call_matrix[j][3]);
|
||||
// System all-call
|
||||
else if ((call_matrix[j][4] & EDACS_IS_ALL_CALL) != 0)
|
||||
printw ("Target [ SYSTEM ] Source [%8lld] All-Call", call_matrix[j][3]);
|
||||
// Interconnect
|
||||
else if ((call_matrix[j][4] & EDACS_IS_INTERCONNECT) != 0)
|
||||
printw ("Target [ SYSTEM ] Source [%8lld] Interconnect", call_matrix[j][3]);
|
||||
// Unknown call
|
||||
else
|
||||
printw ("Unknown call type");
|
||||
|
||||
// Call flags
|
||||
if ((call_matrix[j][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]");
|
||||
else printw (" [Dig]");
|
||||
if ((call_matrix[j][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]");
|
||||
}
|
||||
else
|
||||
// Data call
|
||||
printw ("Target [ DATA ] Source [%8lld] Data", call_matrix[j][3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute 4:4:3 AFS for display purposes only
|
||||
int a = (call_matrix[j][2] >> 7) & 0xF;
|
||||
int fs = call_matrix[j][2] & 0x7F;
|
||||
if (call_matrix[j][2] + 1 == 0)
|
||||
// System all-call
|
||||
printw ("Target [SYSTEM][SYSTEM] Source [%5lld] All-Call", call_matrix[j][3]);
|
||||
else if (call_matrix[j][2] > 10000)
|
||||
// I-Call
|
||||
printw ("Target [%6lld][ UNIT ] Source [%5lld] I-Call", call_matrix[j][2] - 10000, call_matrix[j][3]);
|
||||
else
|
||||
// Voice call
|
||||
if ((call_matrix[j][4] & EDACS_IS_VOICE) != 0)
|
||||
{
|
||||
// Compute 4:4:3 AFS for display purposes only
|
||||
int a = (call_matrix[j][2] >> 7) & 0xF;
|
||||
int fs = call_matrix[j][2] & 0x7F;
|
||||
|
||||
// Group call
|
||||
printw ("Target [%6lld][%02d-%03d] Source [%5lld]", call_matrix[j][2], a, fs, call_matrix[j][3]);
|
||||
if ((call_matrix[j][4] & EDACS_IS_GROUP) != 0)
|
||||
printw ("Target [%6lld][%02d-%03d] Source [%5lld]", call_matrix[j][2], a, fs, call_matrix[j][3]);
|
||||
// I-Call
|
||||
else if ((call_matrix[j][4] & EDACS_IS_INDIVIDUAL) != 0)
|
||||
printw ("Target [%6lld][ UNIT ] Source [%5lld] I-Call", call_matrix[j][2], call_matrix[j][3]);
|
||||
// System all-call
|
||||
else if ((call_matrix[j][4] & EDACS_IS_ALL_CALL) != 0)
|
||||
printw ("Target [ SYSTEM ] Source [%5lld] All-Call", call_matrix[j][3]);
|
||||
// Interconnect
|
||||
else if ((call_matrix[j][4] & EDACS_IS_INTERCONNECT) != 0)
|
||||
printw ("Target [ SYSTEM ] Source [%5lld] Interconnect", call_matrix[j][3]);
|
||||
// Unknown call
|
||||
else
|
||||
printw ("Unknown call type");
|
||||
|
||||
// Call flags
|
||||
if ((call_matrix[j][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]");
|
||||
else printw (" [Dig]");
|
||||
if ((call_matrix[j][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]");
|
||||
}
|
||||
else
|
||||
// Data call
|
||||
printw ("Target [ DATA ] Source [%5lld] Data", call_matrix[j][3]);
|
||||
}
|
||||
//test
|
||||
for (int k = 0; k < state->group_tally; k++)
|
||||
|
|
@ -4524,6 +4572,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||
state->edacs_cc_lcn = 0;
|
||||
state->edacs_vc_lcn = 0;
|
||||
state->edacs_tuned_lcn = -1;
|
||||
state->edacs_vc_call_type = 0;
|
||||
state->p25_cc_freq = 0;
|
||||
opts->p25_is_tuned = 0;
|
||||
state->lasttg = 0;
|
||||
|
|
|
|||
289
src/edacs-fme.c
289
src/edacs-fme.c
|
|
@ -542,6 +542,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
unsigned char mt1 = (fr_1t & 0xF800000000) >> 35;
|
||||
unsigned char mt2 = (fr_1t & 0x780000000) >> 31;
|
||||
|
||||
state->edacs_vc_call_type = 0;
|
||||
|
||||
//TODO: initialize where they are actually used
|
||||
unsigned long long int site_id = 0; //we probably could just make this an int as well as the state variables
|
||||
unsigned char lcn = 0;
|
||||
|
|
@ -690,8 +692,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
lcn = (fr_1t & 0x3E0000000) >> 29;
|
||||
int group = (fr_1t & 0xFFFF000) >> 12;
|
||||
int source = (fr_4t & 0xFFFFF000) >> 12;
|
||||
fprintf (stderr, "%s", KBLU);
|
||||
fprintf (stderr, " Data Group Call :: Group [%05d] Source [%08d] LCN [%02d]%s", group, source, lcn, get_lcn_status_string(lcn));
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " TDMA Group Call :: Group [%05d] Source [%08d] LCN [%02d]%s", group, source, lcn, get_lcn_status_string(lcn));
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
//Data Group Grant Update
|
||||
|
|
@ -700,8 +702,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
lcn = (fr_1t & 0x3E0000000) >> 29;
|
||||
int group = (fr_1t & 0xFFFF000) >> 12;
|
||||
int source = (fr_4t & 0xFFFFF000) >> 12;
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " TDMA Group Call :: Group [%05d] Source [%08d] LCN [%02d]%s", group, source, lcn, get_lcn_status_string(lcn));
|
||||
fprintf (stderr, "%s", KBLU);
|
||||
fprintf (stderr, " Data Group Call :: Group [%05d] Source [%08d] LCN [%02d]%s", group, source, lcn, get_lcn_status_string(lcn));
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
//Voice Call Grant Update
|
||||
|
|
@ -724,9 +726,16 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
int is_tx_trunking = (fr_4t & 0x200000000) >> 33;
|
||||
int group = (fr_1t & 0xFFFF000) >> 12;
|
||||
int source = (fr_4t & 0xFFFFF000) >> 12;
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = group; // 0 is a valid TG, it's the all-call for agency 0
|
||||
if (source != 0) state->lastsrc = source;
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_GROUP;
|
||||
if (is_digital == 1) state->edacs_vc_call_type |= EDACS_IS_DIGITAL;
|
||||
if (is_emergency == 1) state->edacs_vc_call_type |= EDACS_IS_EMERGENCY;
|
||||
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
if (is_digital == 0) fprintf (stderr, " Analog Group Call");
|
||||
|
|
@ -823,9 +832,15 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
int is_update = (fr_1t & 0x100000000) >> 32;
|
||||
int target = (fr_1t & 0xFFFFF000) >> 12;
|
||||
int source = (fr_4t & 0xFFFFF000) >> 12;
|
||||
if (target != 0) state->lasttg = target + 100000; //Use IDs > 100000 to represent i-call targets to differentiate from TGs
|
||||
if (source != 0) state->lastsrc = source;
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
if (target != 0) state->lasttg = target;
|
||||
if (source != 0) state->lastsrc = source;
|
||||
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_INDIVIDUAL;
|
||||
if (is_digital == 1) state->edacs_vc_call_type |= EDACS_IS_DIGITAL;
|
||||
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
if (is_digital == 0) fprintf (stderr, " Analog I-Call");
|
||||
|
|
@ -890,6 +905,19 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
fprintf (stderr, "%s", KBLU);
|
||||
fprintf (stderr, " Channel Assignment (Unknown Data) :: Source [%08d] LCN [%02d]%s", source, lcn, get_lcn_status_string(lcn));
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//LCNs greater than 26 are considered status values, "Busy, Queue, Deny, etc"
|
||||
if (lcn > state->edacs_lcn_count && lcn < 26)
|
||||
{
|
||||
state->edacs_lcn_count = lcn;
|
||||
}
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
if (source != 0) state->lastsrc = source;
|
||||
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_INDIVIDUAL;
|
||||
}
|
||||
//System All-Call Grant Update
|
||||
else if (mt1 == 0x16)
|
||||
|
|
@ -905,9 +933,15 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
int is_digital = (fr_1t & 0x10000000) >> 28;
|
||||
int is_update = (fr_1t & 0x8000000) >> 27;
|
||||
int source = (fr_4t & 0xFFFFF000) >> 12;
|
||||
state->lasttg = -1; // represent system all-call as TG -1 to differentiate from real TGs
|
||||
if (source != 0) state->lastsrc = source;
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = 0;
|
||||
if (source != 0) state->lastsrc = source;
|
||||
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_ALL_CALL;
|
||||
if (is_digital == 1) state->edacs_vc_call_type |= EDACS_IS_DIGITAL;
|
||||
|
||||
fprintf (stderr, "%s", KMAG);
|
||||
if (is_digital == 0) fprintf (stderr, " Analog System All-Call");
|
||||
|
|
@ -997,6 +1031,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
unsigned char mt_b = (fr_1t & 0x1C00000000) >> 34;
|
||||
unsigned char mt_d = (fr_1t & 0x3E0000000) >> 29;
|
||||
|
||||
state->edacs_vc_call_type = 0;
|
||||
|
||||
//Add raw payloads and MT-A/MT-B/MT-D for easy debug
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
|
|
@ -1028,7 +1064,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
//April 1998. Where real world systems are found to diverge from this bulletin, please note the basis for the
|
||||
//deviation.
|
||||
|
||||
//MT-A 0 and 1 as analog/digital mode indicator reverse engineered from Quebec STM and San Antonio/Bexar Co
|
||||
//MT-A 0 and 1 as analog/digital mode indicator reverse engineered from Montreal STM and San Antonio/Bexar Co
|
||||
//systems; occurs immediately prior to Voice Group Channel Update.
|
||||
//
|
||||
//Voice Group Channel Assignment (6.2.4.1)
|
||||
|
|
@ -1060,9 +1096,16 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
{
|
||||
state->edacs_lcn_count = lcn;
|
||||
}
|
||||
state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = group;
|
||||
state->lastsrc = lid;
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = group;
|
||||
state->lastsrc = lid;
|
||||
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_GROUP;
|
||||
if (is_digital == 1) state->edacs_vc_call_type |= EDACS_IS_DIGITAL;
|
||||
if (is_emergency == 1) state->edacs_vc_call_type |= EDACS_IS_EMERGENCY;
|
||||
|
||||
char mode[8]; //allow, block, digital enc
|
||||
sprintf (mode, "%s", "");
|
||||
|
|
@ -1139,16 +1182,34 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
int lid = (fr_1t & 0x3FFF000) >> 12;
|
||||
int group = (fr_1t & 0x7FF000) >> 12;
|
||||
|
||||
//Abstract away to a target, and be sure to check whether it's an individual call later
|
||||
int target = (is_individual_id == 0) ? group : lid;
|
||||
|
||||
fprintf (stderr, "%s", KBLU);
|
||||
fprintf (stderr, " Data Call Channel Assignment :: Type");
|
||||
if (is_individual_call == 1) fprintf (stderr, " [Individual]");
|
||||
else fprintf (stderr, " [Group]");
|
||||
if (is_individual_id == 1) fprintf (stderr, " LID [%05d]", lid);
|
||||
else fprintf (stderr, " Group [%04d]", group);
|
||||
if (is_individual_id == 1) fprintf (stderr, " LID [%05d]", target);
|
||||
else fprintf (stderr, " Group [%04d]", target);
|
||||
if (is_from_lid == 1) fprintf (stderr, " -->");
|
||||
else fprintf (stderr, " <--");
|
||||
fprintf (stderr, " Port [%02d] LCN [%02d]%s", port, lcn, get_lcn_status_string(lcn));
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//LCNs >= 26 are reserved to indicate status (queued, busy, denied, etc)
|
||||
if (lcn > state->edacs_lcn_count && lcn < 26)
|
||||
{
|
||||
state->edacs_lcn_count = lcn;
|
||||
}
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = target;
|
||||
state->lastsrc = 0;
|
||||
|
||||
//Call type for state
|
||||
if (is_individual_call == 0) state->edacs_vc_call_type = EDACS_IS_GROUP;
|
||||
else state->edacs_vc_call_type = EDACS_IS_INDIVIDUAL;
|
||||
}
|
||||
//Login Acknowledge (6.2.4.4)
|
||||
else if (mt_a == 0x6)
|
||||
|
|
@ -1186,26 +1247,44 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
//Abstract away to a target, and be sure to check whether it's an individual call later
|
||||
int target = (is_individual_id == 0) ? group : lid;
|
||||
|
||||
//Technically only MT-C 0x2 is defined in TSB 69.3 - using and extrapolating on legacy code
|
||||
int is_digital = (mt_c == 2 || mt_c == 3) ? 1 : 0;
|
||||
|
||||
fprintf (stderr, "%s", KMAG);
|
||||
fprintf (stderr, " Interconnect Channel Assignment :: Type");
|
||||
if (mt_c == 0x2) fprintf (stderr, " [Voice]");
|
||||
else fprintf (stderr, " [Reserved]");
|
||||
if (is_digital == 0) fprintf (stderr, " Analog");
|
||||
else fprintf (stderr, " Digital");
|
||||
if (is_individual_id == 1) fprintf (stderr, " LID [%05d]", target);
|
||||
else fprintf (stderr, " Group [%04d]", target);
|
||||
fprintf (stderr, " LCN [%02d]%s", lcn, get_lcn_status_string(lcn));
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// TODO: Actually process the call
|
||||
//LCNs >= 26 are reserved to indicate status (queued, busy, denied, etc)
|
||||
if (lcn > state->edacs_lcn_count && lcn < 26)
|
||||
{
|
||||
state->edacs_lcn_count = lcn;
|
||||
}
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = target;
|
||||
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_INTERCONNECT;
|
||||
if (is_digital == 1) state->edacs_vc_call_type |= EDACS_IS_DIGITAL;
|
||||
}
|
||||
//Channel Updates (6.2.4.7)
|
||||
//Source/caller being present in individual call channel updates reverse engineered from Montreal STM system
|
||||
else if (mt_b == 0x3)
|
||||
{
|
||||
int mt_c = (fr_1t & 0x300000000) >> 32;
|
||||
int lcn = (fr_1t & 0xF8000000) >> 27;
|
||||
int is_individual = (fr_1t & 0x4000000) >> 26;
|
||||
int is_emergency = (fr_1t & 0x2000000) >> 25;
|
||||
int is_emergency = (is_individual == 0) ? (fr_1t & 0x2000000) >> 25 : 0;
|
||||
int group = (fr_1t & 0x7FF000) >> 12;
|
||||
int lid = ((fr_1t & 0x1FC0000) >> 11) | ((fr_4t & 0x7F000) >> 12);
|
||||
int lid = (fr_1t & 0x3FFF000) >> 12;
|
||||
int source = (fr_4t & 0x3FFF000) >> 12; //Source only present in individual calls
|
||||
|
||||
//Abstract away to a target, and be sure to check whether it's an individual call later
|
||||
int target = (is_individual == 0) ? group : lid;
|
||||
|
|
@ -1227,7 +1306,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
if (is_digital == 0) fprintf (stderr, " Analog");
|
||||
else fprintf (stderr, " Digital");
|
||||
if (is_individual == 0) fprintf (stderr, " Group [%04d]", target);
|
||||
else fprintf (stderr, " LID [%05d]", target);
|
||||
else fprintf (stderr, " Callee [%05d] Caller [%05d]", target, source);
|
||||
fprintf (stderr, " LCN [%02d]%s", lcn, get_lcn_status_string(lcn));
|
||||
if (is_tx_trunk == 0) fprintf (stderr, " [Message Trunking]");
|
||||
if (is_emergency == 1)
|
||||
|
|
@ -1242,14 +1321,19 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
{
|
||||
state->edacs_lcn_count = lcn;
|
||||
}
|
||||
state->edacs_vc_lcn = lcn;
|
||||
|
||||
//Use IDs > 10000 to represent i-call targets to differentiate from TGs
|
||||
if (is_individual == 0) state->lasttg = target;
|
||||
else state->lasttg = target + 10000;
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = target;
|
||||
//Alas, EDACS standard does not provide a source LID on channel updates - try to work around this on the display end instead
|
||||
state->lastsrc = 0;
|
||||
|
||||
//Alas, EDACS standard does not provide a source LID on channel updates - try to work around this on the display end instead
|
||||
state->lastsrc = 0;
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_VOICE;
|
||||
if (is_individual == 0) state->edacs_vc_call_type |= EDACS_IS_GROUP;
|
||||
else state->edacs_vc_call_type |= EDACS_IS_INDIVIDUAL;
|
||||
if (is_digital == 1) state->edacs_vc_call_type |= EDACS_IS_DIGITAL;
|
||||
if (is_emergency == 1) state->edacs_vc_call_type |= EDACS_IS_EMERGENCY;
|
||||
|
||||
char mode[8]; //allow, block, digital enc
|
||||
sprintf (mode, "%s", "");
|
||||
|
|
@ -1332,23 +1416,88 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
//Individual Call Channel Assignment (6.2.4.9)
|
||||
//Analog and digital flag reverse engineered from Montreal STM system
|
||||
else if (mt_b == 0x5)
|
||||
{
|
||||
int is_tx_trunk = (fr_1t & 0x200000000) >> 33;
|
||||
int lcn = (fr_1t & 0xF8000000) >> 27;
|
||||
int call_type = (fr_1t & 0x4000000) >> 26;
|
||||
int is_digital = (fr_1t & 0x4000000) >> 26;
|
||||
int target = (fr_1t & 0x3FFF000) >> 12;
|
||||
int source = (fr_4t & 0x3FFF000) >> 12;
|
||||
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Individual Call Channel Assignment :: Type");
|
||||
if (call_type == 1) fprintf (stderr, " [Voice]");
|
||||
else fprintf (stderr, " [Reserved]");
|
||||
fprintf (stderr, " Caller [%05d] Callee [%05d] LCN [%02d]%s", source, target, lcn, get_lcn_status_string(lcn));
|
||||
fprintf (stderr, " Individual Call Channel Assignment ::");
|
||||
if (is_digital == 0) fprintf (stderr, " Analog");
|
||||
else fprintf (stderr, " Digital");
|
||||
fprintf (stderr, " Callee [%05d] Caller [%05d] LCN [%02d]%s", target, source, lcn, get_lcn_status_string(lcn));
|
||||
if (is_tx_trunk == 0) fprintf (stderr, " [Message Trunking]");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// TODO: Actually process the call
|
||||
//LCNs >= 26 are reserved to indicate status (queued, busy, denied, etc)
|
||||
if (lcn > state->edacs_lcn_count && lcn < 26)
|
||||
{
|
||||
state->edacs_lcn_count = lcn;
|
||||
}
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = target;
|
||||
state->lastsrc = source;
|
||||
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_INDIVIDUAL;
|
||||
if (is_digital == 1) state->edacs_vc_call_type |= EDACS_IS_DIGITAL;
|
||||
|
||||
char mode[8]; //allow, block, digital enc
|
||||
sprintf (mode, "%s", "");
|
||||
|
||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
//Individual calls always remain blocked if in allow/whitelist mode
|
||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
||||
|
||||
//NOTE: Restructured below so that analog and digital are handled the same, just that when
|
||||
//its analog, it will now start edacs_analog which will while loop analog samples until
|
||||
//signal level drops (RMS, or a dotting sequence is detected)
|
||||
|
||||
//this is working now with the new import setup
|
||||
if ((opts->trunk_tune_private_calls == 1) && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
{
|
||||
if (lcn > 0 && lcn < 26 && state->edacs_cc_lcn != 0 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||
{
|
||||
//openwav file and do per call right here
|
||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||
{
|
||||
sprintf (opts->wav_out_file, "./WAV/%s %s EDACS Site %lld TGT %05d SRC %05d I-Call.wav", getDateE(), timestr, state->edacs_site_id, target, state->lastsrc);
|
||||
if (is_digital == 0) openWavOutFile48k (opts, state); //analog at 48k
|
||||
else openWavOutFile (opts, state); //digital
|
||||
}
|
||||
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
//only set bandwidth IF we have an original one to fall back to (experimental, but requires user to set the -B 12000 or -B 24000 value manually)
|
||||
if (opts->setmod_bw != 0)
|
||||
{
|
||||
if (is_digital == 0) SetModulation(opts->rigctl_sockfd, 7000); //narrower bandwidth, but has issues with dotting sequence
|
||||
else SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
}
|
||||
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
if (is_digital == 0) edacs_analog(opts, state, target, lcn);
|
||||
}
|
||||
|
||||
if (opts->audio_in_type == 3) //rtl dongle
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
if (is_digital == 0) edacs_analog(opts, state, target, lcn);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Console Unkey / Drop (6.2.4.10)
|
||||
else if (mt_b == 0x6)
|
||||
|
|
@ -1552,26 +1701,90 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||
}
|
||||
}
|
||||
//System All-Call (6.2.4.19)
|
||||
//Analog and digital flag extrapolated from reverse engineering of other messages
|
||||
else if (mt_d == 0x0F)
|
||||
{
|
||||
int lcn = (fr_1t & 0x1F000000) >> 24;
|
||||
int qualifier = (fr_1t & 0x800000) >> 23;
|
||||
int is_digital = (fr_1t & 0x800000) >> 23;
|
||||
int is_update = (fr_1t & 0x400000) >> 22;
|
||||
int is_tx_trunk = (fr_1t & 0x200000) >> 21;
|
||||
int lid = ((fr_1t & 0x7F000) >> 5) | ((fr_4t & 0x7F000) >> 12);
|
||||
int lid = ((fr_1t & 0x7F000) >> 12) | ((fr_4t & 0xFE000) >> 6);
|
||||
|
||||
fprintf (stderr, "%s", KMAG);
|
||||
fprintf (stderr, " System All-Call Channel");
|
||||
if (is_update == 0) fprintf (stderr, " Assignment");
|
||||
else fprintf (stderr, " Update");
|
||||
fprintf (stderr, " ::");
|
||||
if (qualifier == 1) fprintf (stderr, " [Voice]");
|
||||
else fprintf (stderr, " [Reserved]");
|
||||
if (is_digital == 0) fprintf (stderr, " Analog");
|
||||
else fprintf (stderr, " Digital");
|
||||
fprintf (stderr, " LID [%05d] LCN [%02d]%s", lid, lcn, get_lcn_status_string(lcn));
|
||||
if (is_tx_trunk == 0) fprintf (stderr, " [Message Trunking]");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// TODO: Actually process the call
|
||||
//LCNs >= 26 are reserved to indicate status (queued, busy, denied, etc)
|
||||
if (lcn > state->edacs_lcn_count && lcn < 26)
|
||||
{
|
||||
state->edacs_lcn_count = lcn;
|
||||
}
|
||||
|
||||
//Call info for state
|
||||
if (lcn != 0) state->edacs_vc_lcn = lcn;
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = lid;
|
||||
|
||||
//Call type for state
|
||||
state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_ALL_CALL;
|
||||
if (is_digital == 1) state->edacs_vc_call_type |= EDACS_IS_DIGITAL;
|
||||
|
||||
char mode[8]; //allow, block, digital enc
|
||||
sprintf (mode, "%s", "");
|
||||
|
||||
//if we are using allow/whitelist mode, then write 'A' to mode for allow - always allow all-calls by default
|
||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "A");
|
||||
|
||||
//NOTE: Restructured below so that analog and digital are handled the same, just that when
|
||||
//its analog, it will now start edacs_analog which will while loop analog samples until
|
||||
//signal level drops (RMS, or a dotting sequence is detected)
|
||||
|
||||
//this is working now with the new import setup
|
||||
if ((opts->trunk_tune_group_calls == 1) && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
{
|
||||
if (lcn > 0 && lcn < 26 && state->edacs_cc_lcn != 0 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||
{
|
||||
//openwav file and do per call right here
|
||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||
{
|
||||
sprintf (opts->wav_out_file, "./WAV/%s %s EDACS Site %lld SRC %05d All-Call.wav", getDateE(), timestr, state->edacs_site_id, state->lastsrc);
|
||||
if (is_digital == 0) openWavOutFile48k (opts, state); //analog at 48k
|
||||
else openWavOutFile (opts, state); //digital
|
||||
}
|
||||
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
//only set bandwidth IF we have an original one to fall back to (experimental, but requires user to set the -B 12000 or -B 24000 value manually)
|
||||
if (opts->setmod_bw != 0)
|
||||
{
|
||||
if (is_digital == 0) SetModulation(opts->rigctl_sockfd, 7000); //narrower bandwidth, but has issues with dotting sequence
|
||||
else SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
}
|
||||
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
if (is_digital == 0) edacs_analog(opts, state, 0, lcn);
|
||||
}
|
||||
|
||||
if (opts->audio_in_type == 3) //rtl dongle
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
if (is_digital == 0) edacs_analog(opts, state, 0, lcn);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Dynamic Regrouping (6.2.4.20)
|
||||
else if (mt_d == 0x10)
|
||||
|
|
|
|||
Loading…
Reference in New Issue