diff --git a/include/dsd.h b/include/dsd.h index fbe0a0d..be506ae 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -763,14 +763,16 @@ typedef struct int edacs_s_mask; //Calculated Mask for S Bits //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 - #define EDACS_IS_TESTCALL 0x100 + #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 + #define EDACS_IS_TEST_CALL 0x80 + #define EDACS_IS_AGENCY_CALL 0x100 + #define EDACS_IS_FLEET_CALL 0x200 //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 diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index f1e675d..e84ce89 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -315,6 +315,107 @@ char * getTimeC(time_t t) //get pretty hh:mm:ss timestamp return curr; } +int isCustomAfsString(dsd_state * state) { + return state->edacs_a_bits != 4 || state->edacs_f_bits != 4 || state->edacs_s_bits != 3; +} + +//Get the string length we need for an AFS string, math-style +int getAfsStringLength(dsd_state * state) { + if (!isCustomAfsString(state)) + return 6; + + int length = 0; + length += (state->edacs_a_bits + 2) / 3; + length += (state->edacs_f_bits + 2) / 3; + length += (state->edacs_s_bits + 2) / 3; + length += 2; //colon separators + + // This will be either 6 or 7 + return length; +} + +//Format the AFS string, Florida-style +int getAfsString(dsd_state * state, char * buffer, int a, int f, int s) { + if (!isCustomAfsString(state)) + { + sprintf(buffer, "%02d-%02d%01d", a, f, s); + return 6; + } + + int printed_chars = 0; + switch (state->edacs_a_bits) + { + case 1: + case 2: + case 3: + sprintf(buffer, "%01d:", a); + printed_chars += 1; + break; + case 4: + case 5: + case 6: + sprintf(buffer, "%02d:", a); + printed_chars += 2; + break; + case 7: + case 8: + case 9: + sprintf(buffer, "%03d:", a); + printed_chars += 3; + break; + } + + sprintf(buffer + printed_chars, ":"); + printed_chars++; + + switch (state->edacs_f_bits) { + case 1: + case 2: + case 3: + sprintf(buffer + printed_chars, "%01d", f); + printed_chars += 1; + break; + case 4: + case 5: + case 6: + sprintf(buffer + printed_chars, "%02d", f); + printed_chars += 2; + break; + case 7: + case 8: + case 9: + sprintf(buffer + printed_chars, "%03d", f); + printed_chars += 3; + break; + } + + sprintf(buffer + printed_chars, ":"); + printed_chars++; + + switch (state->edacs_s_bits) { + case 1: + case 2: + case 3: + sprintf(buffer + printed_chars, "%01d", s); + printed_chars += 1; + break; + case 4: + case 5: + case 6: + sprintf(buffer + printed_chars, "%02d", s); + printed_chars += 2; + break; + case 7: + case 8: + case 9: + sprintf(buffer + printed_chars, "%03d", s); + printed_chars += 3; + break; + } + + return printed_chars; +} + //testing a few things, going to put this into ncursesMenu #define WIDTH 36 #define HEIGHT 25 @@ -951,7 +1052,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) } - + TCP_END: ; //do nothing @@ -2608,7 +2709,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) int f = (state->tg_hold >> state->edacs_f_shift) & state->edacs_f_mask; int s = state->tg_hold & state->edacs_s_mask; if (state->ea_mode == 1) printw ("\n| \\TG HOLD: %d; ", state->tg_hold); - else printw ("\n| \\TG HOLD: %d [%02d-%02d%01d]; ", state->tg_hold, a, f, s); + else + { + char afs_str[8]; + getAfsString(state, afs_str, a, f, s); + printw ("\n| \\TG HOLD: %d [%s]; ", state->tg_hold, afs_str); + } } attron(COLOR_PAIR(4)); @@ -2649,7 +2755,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) int f = (state->tg_hold >> state->edacs_f_shift) & state->edacs_f_mask; int s = state->tg_hold & state->edacs_s_mask; if (state->ea_mode == 1) printw ("\n| \\TG HOLD: %d; ", state->tg_hold); - else printw ("\n| \\TG HOLD: %d [%02d-%02d%01d]; ", state->tg_hold, a, f, s); + else + { + char afs_str[8]; + getAfsString(state, afs_str, a, f, s); + printw ("\n| \\TG HOLD: %d [%s]; ", state->tg_hold, afs_str); + } } printw ("\n"); @@ -3608,7 +3719,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) // Voice call if ((call_matrix[i][4] & EDACS_IS_VOICE) != 0) { - // System all-call + // Group call if ((call_matrix[i][4] & EDACS_IS_GROUP) != 0) printw (" TGT [%8lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] ); // I-Call @@ -3621,14 +3732,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) else if ((call_matrix[i][4] & EDACS_IS_INTERCONNECT) != 0) printw (" TGT [ SYSTEM ] SRC [%8lld] Interconnect", call_matrix[i][3] ); // Test call - else if ((call_matrix[i][4] & EDACS_IS_TESTCALL) != 0) - printw (" TEST CALL"); + else if ((call_matrix[i][4] & EDACS_IS_TEST_CALL) != 0) + printw (" TGT [ SYSTEM ] SRC [ SYSTEM ] Test Call"); // Unknown call else printw (" Unknown call type" ); // Call flags - if ((call_matrix[i][4] & EDACS_IS_TESTCALL) != 0) {} + if ((call_matrix[i][4] & EDACS_IS_TEST_CALL) != 0) {} else 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]"); @@ -3644,32 +3755,53 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { // Group call if ((call_matrix[i][4] & EDACS_IS_GROUP) != 0) - printw (" TGT [%6lld][%02d-%02d%01d] SRC [%5lld]", call_matrix[i][2], a, f, s, call_matrix[i][3] ); + { + char afs_str[8]; + getAfsString(state, afs_str, a, f, s); + printw (" TGT [%6lld][%s] SRC [%5lld]", call_matrix[i][2], afs_str, 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] ); + if (getAfsStringLength(state) == 6) + printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", call_matrix[i][2], call_matrix[i][3] ); + else + 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] ); + if (getAfsStringLength(state) == 6) + printw (" TGT [ SYSTEM ] SRC [%5lld] All-Call", call_matrix[i][3] ); + else + 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] ); + if (getAfsStringLength(state) == 6) + printw (" TGT [ SYSTEM ] SRC [%5lld] Interconnect", call_matrix[i][3] ); + else + printw (" TGT [ SYSTEM ] SRC [%5lld] Interconnect", call_matrix[i][3] ); // Test call - else if ((call_matrix[i][4] & EDACS_IS_TESTCALL) != 0) - printw (" TEST CALL"); + else if ((call_matrix[i][4] & EDACS_IS_TEST_CALL) != 0) + if (getAfsStringLength(state) == 6) + printw (" TGT [ SYSTEM ] SRC [ SYS ] Test Call"); + else + printw (" TGT [ SYSTEM ] SRC [ SYS ] Test Call"); // Unknown call else printw (" Unknown call type" ); // Call flags - if ((call_matrix[i][4] & EDACS_IS_TESTCALL) != 0) {} + if ((call_matrix[i][4] & EDACS_IS_TEST_CALL) != 0) {} else if ((call_matrix[i][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]"); else printw (" [Dig]"); + if ((call_matrix[i][4] & EDACS_IS_AGENCY_CALL) != 0) printw ("[A]"); + if ((call_matrix[i][4] & EDACS_IS_FLEET_CALL) != 0) printw ("[F]"); if ((call_matrix[i][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]"); } + // Data call else - // Data call - printw (" TGT [ DATA ] SRC [%8lld] Data", call_matrix[i][3] ); + if (getAfsStringLength(state) == 6) + printw (" TGT [ DATA ] SRC [%5lld] Data", call_matrix[i][3] ); + else + printw (" TGT [ DATA ] SRC [%5lld] Data", call_matrix[i][3] ); } for (int k = 0; k < state->group_tally; k++) { @@ -3814,14 +3946,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) else if ((call_matrix[j][4] & EDACS_IS_INTERCONNECT) != 0) printw ("Target [ SYSTEM ] Source [%8lld] Interconnect", call_matrix[j][3]); // Test call - else if ((call_matrix[j][4] & EDACS_IS_TESTCALL) != 0) - printw ("TEST CALL"); + else if ((call_matrix[j][4] & EDACS_IS_TEST_CALL) != 0) + printw ("Target [ SYSTEM ] Source [ SYSTEM ] Test Call"); // Unknown call else printw ("Unknown call type"); // Call flags - if ((call_matrix[j][4] & EDACS_IS_TESTCALL) != 0) {} + if ((call_matrix[j][4] & EDACS_IS_TEST_CALL) != 0) {} else 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]"); @@ -3841,33 +3973,53 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) int s = call_matrix[j][2] & state->edacs_s_mask; // Group call - if ((call_matrix[j][4] & EDACS_IS_GROUP) != 0) - printw ("Target [%6lld][%02d-%02d%01d] Source [%5lld]", call_matrix[j][2], a, f, s, call_matrix[j][3]); + if ((call_matrix[j][4] & EDACS_IS_GROUP) != 0) { + char afs_str[8]; + getAfsString(state, afs_str, a, f, s); + printw ("Target [%6lld][%s] Source [%5lld]", call_matrix[j][2], afs_str, 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]); + if (getAfsStringLength(state) == 6) + printw ("Target [%6lld][ UNIT ] Source [%5lld] I-Call", call_matrix[j][2], call_matrix[j][3]); + else + 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]); + if (getAfsStringLength(state) == 6) + printw ("Target [ SYSTEM ] Source [%5lld] All-Call", call_matrix[j][3]); + else + 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]); + if (getAfsStringLength(state) == 6) + printw ("Target [ SYSTEM ] Source [%5lld] Interconnect", call_matrix[j][3]); + else + printw ("Target [ SYSTEM ] Source [%5lld] Interconnect", call_matrix[j][3]); // Test call - else if ((call_matrix[i][4] & EDACS_IS_TESTCALL) != 0) - printw (" TEST CALL"); + else if ((call_matrix[j][4] & EDACS_IS_TEST_CALL) != 0) + if (getAfsStringLength(state) == 6) + printw ("Target [ SYSTEM ] Source [ SYS ] Test Call"); + else + printw ("Target [ SYSTEM ] Source [ SYS ] Test Call"); // Unknown call else printw ("Unknown call type"); // Call flags - if ((call_matrix[i][4] & EDACS_IS_TESTCALL) != 0) {} + if ((call_matrix[j][4] & EDACS_IS_TEST_CALL) != 0) {} else if ((call_matrix[j][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]"); else printw (" [Dig]"); + if ((call_matrix[j][4] & EDACS_IS_AGENCY_CALL) != 0) printw ("[A]"); + if ((call_matrix[j][4] & EDACS_IS_FLEET_CALL) != 0) printw ("[F]"); if ((call_matrix[j][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]"); } + // Data call else - // Data call - printw ("Target [ DATA ] Source [%5lld] Data", call_matrix[j][3]); + if (getAfsStringLength(state) == 6) + printw ("Target [ DATA ] Source [%5lld] Data", call_matrix[j][3]); + else + printw ("Target [ DATA ] Source [%5lld] Data", call_matrix[j][3]); } //test for (int k = 0; k < state->group_tally; k++) diff --git a/src/edacs-fme.c b/src/edacs-fme.c index 894b385..dcf6c3d 100644 --- a/src/edacs-fme.c +++ b/src/edacs-fme.c @@ -53,7 +53,7 @@ char * getTimeE(void) //get pretty hhmmss timestamp return curr; } -char* get_lcn_status_string(int lcn) +char * getLcnStatusString(int lcn) { if (lcn == 26 || lcn == 27) return "[Reserved LCN Status]"; @@ -69,8 +69,22 @@ char* get_lcn_status_string(int lcn) return ""; } +int isAgencyCallGroup(int afs, dsd_state * state) +{ + int fs_mask = state->edacs_s_mask | (state->edacs_f_mask << state->edacs_f_shift); + return (afs & fs_mask) == 0; +} + +int isFleetCallGroup(int afs, dsd_state * state) +{ + if (isAgencyCallGroup(afs, state)) + return 0; + + return (afs & state->edacs_s_mask) == 0; +} + //Bitwise vote-compare the three copies of a message received. Note that fr_2 and fr_5 are transmitted inverted. -unsigned long long int edacs_vote_fr(unsigned long long int fr_1_4, unsigned long long int fr_2_5, unsigned long long int fr_3_6) +unsigned long long int edacsVoteFr(unsigned long long int fr_1_4, unsigned long long int fr_2_5, unsigned long long int fr_3_6) { fr_2_5 = (~fr_2_5) & 0xFFFFFFFFFF; @@ -453,36 +467,10 @@ void edacs(dsd_opts * opts, dsd_state * state) state->edacs_a_shift = state->edacs_f_bits + state->edacs_s_bits; state->edacs_f_shift = state->edacs_s_bits; - //calculate masks via overkill copy and paste - if (state->edacs_a_bits == 1) state->edacs_a_mask = 0x1; - if (state->edacs_a_bits == 2) state->edacs_a_mask = 0x3; - if (state->edacs_a_bits == 3) state->edacs_a_mask = 0x7; - if (state->edacs_a_bits == 4) state->edacs_a_mask = 0xF; - if (state->edacs_a_bits == 5) state->edacs_a_mask = 0x1F; - if (state->edacs_a_bits == 6) state->edacs_a_mask = 0x3F; - if (state->edacs_a_bits == 7) state->edacs_a_mask = 0x7F; - if (state->edacs_a_bits == 8) state->edacs_a_mask = 0xFF; - if (state->edacs_a_bits == 9) state->edacs_a_mask = 0x1FF; - - if (state->edacs_f_bits == 1) state->edacs_s_mask = 0x1; - if (state->edacs_f_bits == 2) state->edacs_s_mask = 0x3; - if (state->edacs_f_bits == 3) state->edacs_s_mask = 0x7; - if (state->edacs_f_bits == 4) state->edacs_s_mask = 0xF; - if (state->edacs_f_bits == 5) state->edacs_s_mask = 0x1F; - if (state->edacs_f_bits == 6) state->edacs_s_mask = 0x3F; - if (state->edacs_f_bits == 7) state->edacs_s_mask = 0x7F; - if (state->edacs_f_bits == 8) state->edacs_s_mask = 0xFF; - if (state->edacs_f_bits == 9) state->edacs_s_mask = 0x1FF; - - if (state->edacs_s_bits == 1) state->edacs_s_mask = 0x1; - if (state->edacs_s_bits == 2) state->edacs_s_mask = 0x3; - if (state->edacs_s_bits == 3) state->edacs_s_mask = 0x7; - if (state->edacs_s_bits == 4) state->edacs_s_mask = 0xF; - if (state->edacs_s_bits == 5) state->edacs_s_mask = 0x1F; - if (state->edacs_s_bits == 6) state->edacs_s_mask = 0x3F; - if (state->edacs_s_bits == 7) state->edacs_s_mask = 0x7F; - if (state->edacs_s_bits == 8) state->edacs_s_mask = 0xFF; - if (state->edacs_s_bits == 9) state->edacs_s_mask = 0x1FF; + //calculate masks using bitwise math + state->edacs_a_mask = (1 << state->edacs_a_bits) - 1; + state->edacs_f_mask = (1 << state->edacs_f_bits) - 1; + state->edacs_s_mask = (1 << state->edacs_s_bits) - 1; char * timestr; //add timestr here, so we can assign it and also free it to prevent memory leak timestr = getTimeE(); @@ -528,8 +516,8 @@ void edacs(dsd_opts * opts, dsd_state * state) } //Take our 3 copies of the first and second message and vote them to extract the two "error-corrected" messages - unsigned long long int msg_1_ec = edacs_vote_fr(fr_1, fr_2, fr_3); - unsigned long long int msg_2_ec = edacs_vote_fr(fr_4, fr_5, fr_6); + unsigned long long int msg_1_ec = edacsVoteFr(fr_1, fr_2, fr_3); + unsigned long long int msg_2_ec = edacsVoteFr(fr_4, fr_5, fr_6); //Get just the 28-bit message portion unsigned long long int msg_1_ec_m = msg_1_ec >> 12; @@ -569,9 +557,9 @@ void edacs(dsd_opts * opts, dsd_state * state) // - KYEL - system data // - KGRN - voice group calls // - KCYN - voice individual calls - // - KMAG - voice other calls (interconnect, all-call, etc) + // - KMAG - voice other calls (interconnect, all-call, test call, etc) // - KBLU - subscriber data - // - KWHT - unknown/reserved + // - KWHT - unknown/reserved/special //Account for ESK, if any unsigned long long int fr_esk_mask = ((unsigned long long int)state->esk_mask) << 20; @@ -607,17 +595,15 @@ void edacs(dsd_opts * opts, dsd_state * state) if (mt1 == 0x1F) { - //Test Call (not seen in the wild, see US patent US7546135B2, Figure 2b) - //Finally Captured in the wild, along with the "I-Call" with zero target and zero source + //Initiate Test Call (finally captured in the wild on SLERS EA, along with the "I-Call" with target and source of 0) if (mt2 == 0x0) { - // MSG_1 [F802180] MSG_2 [0000000] (MT1: 1F; MT2: 0) Initiate Test Call int cc_lcn = (msg_1 & 0x3E000) >> 13; //shifted to allow this example to be CC LCN 1, as was reported at the time of capture int wc_lcn = (msg_1 & 0xF80) >> 7; fprintf (stderr, "%s", KYEL); - fprintf (stderr, " Initiate Test Call :: CC LCN: %02d; WC LCN: %02d;", cc_lcn, wc_lcn); + fprintf (stderr, " Initiate Test Call :: CC LCN [%02d] WC LCN [%02d]", cc_lcn, wc_lcn); fprintf (stderr, "%s", KNRM); state->edacs_vc_lcn = wc_lcn; @@ -625,7 +611,7 @@ void edacs(dsd_opts * opts, dsd_state * state) //and overwrite current values in the matrix state->lasttg = 999999999; state->lastsrc = 999999999; - state->edacs_vc_call_type = 0x101; //manually set to 0x101 to trigger voice call in ncurses, but no other flags + state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_TEST_CALL; } //Adjacent Sites else if (mt2 == 0x1) @@ -633,11 +619,11 @@ void edacs(dsd_opts * opts, dsd_state * state) int adj_lcn = (msg_1 & 0x1F000) >> 12; int adj_idx = (msg_1 & 0xF00) >> 8; //site 177 has 8 adj_sites, so this appears to be a 4-bit value int adj_site = (msg_1 & 0xFF); - + fprintf (stderr, "%s", KYEL); fprintf (stderr, " Adjacent Site"); if (adj_site > 0) - fprintf (stderr, " :: Site ID [%02X][%03d] Index [%d] on CC LCN [%02d]%s", adj_site, adj_site, adj_idx, adj_lcn, get_lcn_status_string(lcn)); + fprintf (stderr, " :: Site ID [%02X][%03d] Index [%d] on CC LCN [%02d]%s", adj_site, adj_site, adj_idx, adj_lcn, getLcnStatusString(lcn)); else fprintf (stderr, " :: Total Indexed [%d]", adj_idx); //if site value is 0, then this tells us the total number of adjacent sites if (adj_site == 0 && adj_idx == 0) fprintf (stderr, " [Adjacency Table Reset]"); @@ -687,7 +673,7 @@ void edacs(dsd_opts * opts, dsd_state * state) { state->edacs_lcn_count = state->edacs_cc_lcn; } - fprintf (stderr, " :: System ID [%04X] Control Channel LCN [%d]%s", system, state->edacs_cc_lcn, get_lcn_status_string(lcn)); + fprintf (stderr, " :: System ID [%04X] CC LCN [%02d]%s", system, state->edacs_cc_lcn, getLcnStatusString(lcn)); //check for control channel lcn frequency if not provided in channel map or in the lcn list if (state->trunk_lcn_freq[state->edacs_cc_lcn-1] == 0) @@ -808,24 +794,88 @@ void edacs(dsd_opts * opts, dsd_state * state) fprintf (stderr, "%s", KNRM); } - //Patch Groups / Dynamic Regroup -- Reverse Engineer WIP from observations and guesswork + //Patch Groups / Dynamic Regroup -- Current Code + // else if (mt2 == 0xC) + // { + // //Note: First 9 bits of msg_1 are the mt1 and mt2 bits + // int unk1 = (msg_1 & 0x70000) >> 16; //unknown 3 bit value preceeding the SGID + // int sgid = (msg_1 & 0xFFFF); //patched supergroup ID + + // //Updated Observation: The 'SSN' value may not be unique in this instance, so may be an entirely different value + // //altogether. Its function is still unknown, but for the sake of displaying patches, is not required. + + // int ssn = (msg_2 & 0xFF00000) >> 20; //this value seems to incrememnt based on SGID, so assigning 8-bit as the SSN + // int target = (msg_2 & 0xFFFFF); //target group or individual ID (20-bit) to include in supergroup + + // fprintf (stderr, "%s", KWHT); + // fprintf (stderr, " System Dynamic Regroup :: SGID [%05d] Target [%07d]", sgid, target); + // if (unk1) fprintf (stderr, " UNK1 [%01X]", unk1); //this value seems to always be 7 for an active patch, 0 for a termination of a patch + // if (ssn) fprintf (stderr, " UNK2 [%02X]", ssn); //this may or may not be a unique value to each SGID, is FE for termination of a patch + // fprintf (stderr, "%s", KNRM); + // } + + //Patch Groups / Dynamic Regroup -- Reverse Engineer WIP from observations, guesswork, and documented P25 MFID A4 regroup operations else if (mt2 == 0xC) { + + //Note: Due to the method used to reverse engineer this patch using conventions from a newer documented P25 source (MFID A4 L3Harris), + //its possible that the conventions, terminology, and bits signalled in this message are not entirely accurate, but are just speculation + //Note: First 9 bits of msg_1 are the mt1 and mt2 bits - int unk1 = (msg_1 & 0x70000) >> 20; //unknown 3 bit value preceeding the SGID - int sgid = (msg_1 & 0xFFFF); //patched supergroup ID + // FF80000 (visualization aide) + int tga = (msg_1 & 0x70000) >> 16; //unknown 3 bit value preceeding the SGID (TGA?) + int unk1 = (msg_1 & 0xFF00) >> 8; //unknown 8 bit value preceeding the TGA/Options + int sgid = (msg_1 & 0xFF); //patched supergroup ID expressed as an 8 bit value - //Note: SSN is the supergroup sequence number in P25 Harris lingo, but you would think this would be kind of redundant - //since the SGID is itself a unique number as well (waste of bits), but guess that's how their systems work - //that being said, the SSN is always the same for each SGID, so those values seem to go together here as well - int ssn = (msg_2 & 0xFF00000) >> 20; //this value seems to incrememnt based on SGID, so assigning 8-bit as the SSN - int unk2 = (msg_2 & 0xF0000) >> 16; //unknown 4 bit value preceeding 20-bit target value of patch - int target = (msg_2 & 0xFFFFF); //target group or individual ID (20-bit) to include in supergroup + //Observation: The SSN value appears to be unique, but also different between sites, as in, each site + //has its own SSN for the same SGID patching, possibly a first come first serve pool value? + int ssn = (msg_2 & 0xF800000) >> 23; //this value seems to incrememnt based on SGID, 5-bit value + int unk2 = (msg_2 & 0x700000) >> 20; //unknown 3-bit value, possibly linked to TGA when patch is deleted + int target = (msg_2 & 0xFFFFF); //target group or individual ID (20-bit) to include in supergroup + + //look at the 'zero' fields when on 'delete' + // MSG_1 [FE00045] MSG_2 [FE00045] + // FF80000 (visualization aide) + int unk3 = (msg_1 & 0x7FF00) >> 8; + int unk4 = (msg_2 & 0x7FF00) >> 8; + + //Ilya, please don't nit fix my logging format for these, it breaks grep when parsing a bunch of these all at once + fprintf (stderr, "%s", KWHT); + fprintf (stderr, " System Dynamic Regroup :: SP-WGID: %03d; Target: %07d;", sgid, target); + + if (sgid != target) + { + //decode potential TGA values (assumming same as Harris P25) + //decided to disable the info presented below since I cannot confirm this + // if (tga & 4) fprintf (stderr, " One-Way"); //Simulselect + // else fprintf (stderr, " Two-Way"); //Patch + // if (tga & 2) fprintf (stderr, " Group"); + // else fprintf (stderr, " Radio"); //Individual + fprintf (stderr, " Patch"); + if (tga & 1) fprintf (stderr, " Active;"); + else fprintf (stderr, " Delete;"); + + //switched from using the TGA nomenclature to a more generic OPTion since I think this value is still a form of option + fprintf (stderr, " OPT: %01X;", tga); //this value seems to always be 7 for an active patch, 0 for a termination of a patch (6 if assigned the unk2 value) + if (unk1) + fprintf (stderr, " UNK1: %01X;", unk1); + if (unk2) + fprintf (stderr, " UNK2: %02X;", unk2); + fprintf (stderr, " SSN: %02X;", ssn); //this may or may not be a unique value to each SGID, is 1F for termination of a patch + } + + //07:25:17 Sync: +EDACS MSG_1 [FE00045] MSG_2 [FE00045] (MT1: 1F; MT2: C) System Dynamic Regroup :: SP-WGID: 069; Target: 0000069; One-Way Group Patch Delete TGA: 6; + //Upon Reflection, thinking the same MT1 and MT2 values are in both messages, so appears to just be the SP-WGID here and a bunch of zeroes leading into it, and not a TGA value + + else + { + fprintf (stderr, " Patch Delete;"); + if (unk3) + fprintf (stderr, " UNK3: %01X;", unk3); + if (unk4) + fprintf (stderr, " UNK4: %02X;", unk4); + } - fprintf (stderr, "%s", KMAG); //just make it stick out for now - fprintf (stderr, " System Dynamic Regroup :: SSN: %03d; SGID: %05d; Target: %07d;", ssn, sgid, target); - if (unk1) fprintf (stderr, " UNK1: %X;", unk1); //this value seems to always be zero - if (unk2) fprintf (stderr, " UNK2: %X;", unk2); //this value seems to always be zero fprintf (stderr, "%s", KNRM); } //Serial Number Request (not seen in the wild, see US patent 20030190923, Figure 2b) @@ -858,7 +908,7 @@ void edacs(dsd_opts * opts, dsd_state * state) int source = (msg_2 & 0xFFFFF); 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, " TDMA Group Call :: Group [%05d] Source [%08d] LCN [%02d]%s", group, source, lcn, getLcnStatusString(lcn)); fprintf (stderr, "%s", KNRM); } //Data Group Grant Update @@ -869,7 +919,7 @@ void edacs(dsd_opts * opts, dsd_state * state) int source = (msg_2 & 0xFFFFF); 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, " Data Group Call :: Group [%05d] Source [%08d] LCN [%02d]%s", group, source, lcn, getLcnStatusString(lcn)); fprintf (stderr, "%s", KNRM); } //Voice Call Grant Update @@ -908,7 +958,7 @@ void edacs(dsd_opts * opts, dsd_state * state) else fprintf (stderr, " Digital Group Call"); if (is_update == 0) fprintf (stderr, " Assignment"); else fprintf (stderr, " Update"); - fprintf (stderr, " :: Group [%05d] Source [%08d] LCN [%02d]%s", group, source, lcn, get_lcn_status_string(lcn)); + fprintf (stderr, " :: Group [%05d] Source [%08d] LCN [%02d]%s", group, source, lcn, getLcnStatusString(lcn)); //Trunking mode is correlated to (but not guaranteed to match) the type of call: // - emergency calls - usually message trunking @@ -983,7 +1033,7 @@ void edacs(dsd_opts * opts, dsd_state * state) } } - //I-Call Grant Update + //I-Call/Test Call Assignment/Update else if (mt1 == 0x10) { lcn = (msg_2 & 0x1F00000) >> 20; @@ -1005,34 +1055,34 @@ void edacs(dsd_opts * opts, dsd_state * state) if (source != 0) state->lastsrc = source; //Call type for state - state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_INDIVIDUAL; + if (target == 0 && source == 0) state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_TEST_CALL; + else 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); + //Test calls are just I-Calls with source and target of 0 if (target == 0 && source == 0) { - //this seems to be the continuation of the Initiate Test Call Command - //normally, this appears as an "Analog I-Call", but with 0 tg and src, - //its possible that those values could still be present, and that all - //"Analog I-Call" is meant to be the assignment and update of the initiation - if (is_update) fprintf (stderr, " Test Call Update :: LCN: %02d;", lcn); - else fprintf (stderr, " Test Call Assignment :: LCN: %02d;", lcn); + fprintf (stderr, "%s", KMAG); + fprintf (stderr, " Test Call"); + if (is_update == 0) fprintf (stderr, " Assignment"); + else fprintf (stderr, " Update"); + fprintf (stderr, " :: LCN [%02d]%s", lcn, getLcnStatusString(lcn)); state->edacs_vc_lcn = lcn; //assign bogus values so that this will show up in ncurses terminal //and overwrite current values in the matrix state->lasttg = 999999999; state->lastsrc = 999999999; - state->edacs_vc_call_type = 0x101; //manually set to 0x101 to trigger voice call in ncurses, but no other flags lcn = 0; //set to zero here, because this is not an actual call, so don't tune to it } else { + fprintf (stderr, "%s", KCYN); if (is_digital == 0) fprintf (stderr, " Analog I-Call"); else fprintf (stderr, " Digital I-Call"); if (is_update == 0) fprintf (stderr, " Assignment"); else fprintf (stderr, " Update"); - fprintf (stderr, " :: Target [%08d] Source [%08d] LCN [%02d]%s", target, source, lcn, get_lcn_status_string(lcn)); + fprintf (stderr, " :: Target [%08d] Source [%08d] LCN [%02d]%s", target, source, lcn, getLcnStatusString(lcn)); } fprintf (stderr, "%s", KNRM); @@ -1104,7 +1154,7 @@ void edacs(dsd_opts * opts, dsd_state * state) int source = (msg_2 & 0xFFFFF); fprintf (stderr, "%s", KBLU); - fprintf (stderr, " Channel Assignment (Unknown Data) :: Source [%08d] LCN [%02d]%s", source, lcn, get_lcn_status_string(lcn)); + fprintf (stderr, " Channel Assignment (Unknown Data) :: Source [%08d] LCN [%02d]%s", source, lcn, getLcnStatusString(lcn)); fprintf (stderr, "%s", KNRM); //LCNs greater than 26 are considered status values, "Busy, Queue, Deny, etc" @@ -1150,7 +1200,7 @@ void edacs(dsd_opts * opts, dsd_state * state) if (is_update == 0) fprintf (stderr, " Assignment"); else fprintf (stderr, " Update"); - fprintf (stderr, " :: Source [%08d] LCN [%02d]%s", source, lcn, get_lcn_status_string(lcn)); + fprintf (stderr, " :: Source [%08d] LCN [%02d]%s", source, lcn, getLcnStatusString(lcn)); fprintf (stderr, "%s", KNRM); char mode[8]; //allow, block, digital enc @@ -1276,18 +1326,22 @@ void edacs(dsd_opts * opts, dsd_state * state) //Emergency Voice Group Channel Assignment (6.2.4.2) if (mt_a == 0x0 || mt_a == 0x1 || mt_a == 0x2 || mt_a == 0x3) { - int is_digital = (mt_a == 0x2 || mt_a == 0x3) ? 1 : 0; - int is_emergency = (mt_a == 0x1 || mt_a == 0x3) ? 1 : 0; - int lid = ((msg_1 & 0x1FC0000) >> 11) | ((msg_2 & 0xFE0000) >> 17); - int lcn = (msg_1 & 0x1F000) >> 12; - int is_tx_trunk = (msg_1 & 0x800) >> 11; - int group = (msg_1 & 0x7FF); + int is_digital = (mt_a == 0x2 || mt_a == 0x3) ? 1 : 0; + int is_emergency = (mt_a == 0x1 || mt_a == 0x3) ? 1 : 0; + int lid = ((msg_1 & 0x1FC0000) >> 11) | ((msg_2 & 0xFE0000) >> 17); + int lcn = (msg_1 & 0x1F000) >> 12; + int is_tx_trunk = (msg_1 & 0x800) >> 11; + int group = (msg_1 & 0x7FF); + int is_agency_call = isAgencyCallGroup(group, state); + int is_fleet_call = isFleetCallGroup(group, state); fprintf (stderr, "%s", KGRN); fprintf (stderr, " Voice Group Channel Assignment ::"); if (is_digital == 0) fprintf (stderr, " Analog"); else fprintf (stderr, " Digital"); - fprintf (stderr, " Group [%04d] LID [%05d] LCN [%02d]%s", group, lid, lcn, get_lcn_status_string(lcn)); + fprintf (stderr, " Group [%04d] LID [%05d] LCN [%02d]%s", group, lid, lcn, getLcnStatusString(lcn)); + if (is_agency_call == 1) fprintf (stderr, " [Agency]"); + else if (is_agency_call == 1) fprintf (stderr, " [Fleet]"); if (is_tx_trunk == 0) fprintf (stderr, " [Message Trunking]"); if (is_emergency == 1) { @@ -1308,9 +1362,11 @@ void edacs(dsd_opts * opts, dsd_state * state) 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; + 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; + if (is_agency_call) state->edacs_vc_call_type |= EDACS_IS_AGENCY_CALL; + else if (is_fleet_call) state->edacs_vc_call_type |= EDACS_IS_FLEET_CALL; char mode[8]; //allow, block, digital enc sprintf (mode, "%s", ""); @@ -1398,7 +1454,7 @@ void edacs(dsd_opts * opts, dsd_state * state) 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, " Port [%02d] LCN [%02d]%s", port, lcn, getLcnStatusString(lcn)); fprintf (stderr, "%s", KNRM); //LCNs >= 26 are reserved to indicate status (queued, busy, denied, etc) @@ -1461,7 +1517,7 @@ void edacs(dsd_opts * opts, dsd_state * state) 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, " LCN [%02d]%s", lcn, getLcnStatusString(lcn)); fprintf (stderr, "%s", KNRM); //LCNs >= 26 are reserved to indicate status (queued, busy, denied, etc) @@ -1481,19 +1537,25 @@ void edacs(dsd_opts * opts, dsd_state * state) } //Channel Updates (6.2.4.7) //Source/caller being present in individual call channel updates reverse engineered from Montreal STM system + //Test calls reverse engineered from HartLink system else if (mt_b == 0x3) { - int mt_c = (msg_1 & 0x300000) >> 20; - int lcn = (msg_1 & 0xF8000) >> 15; - int is_individual = (msg_1 & 0x4000) >> 14; - int is_emergency = (is_individual == 0) ? (msg_1 & 0x2000) >> 13 : 0; - int group = (msg_1 & 0x7FF); - int lid = (msg_1 & 0x3FFF); - int source = (msg_2 & 0x3FFF); //Source only present in individual calls + int mt_c = (msg_1 & 0x300000) >> 20; + int lcn = (msg_1 & 0xF8000) >> 15; + int is_individual = (msg_1 & 0x4000) >> 14; + int is_emergency = (is_individual == 0) ? (msg_1 & 0x2000) >> 13 : 0; + int group = (msg_1 & 0x7FF); + int lid = (msg_1 & 0x3FFF); + int source = (msg_2 & 0x3FFF); //Source only present in individual calls + int is_agency_call = is_individual == 0 && isAgencyCallGroup(group, state); + int is_fleet_call = is_individual == 0 && isFleetCallGroup(group, state); //Abstract away to a target, and be sure to check whether it's an individual call later int target = (is_individual == 0) ? group : lid; + //Test calls are just individual calls with source and target of 0 + int is_test_call = (target == 0 && source == 0); + //Technically only MT-C 0x1 and 0x3 are defined in TSB 69.3 - using and extrapolating on legacy code int is_tx_trunk = (mt_c == 2 || mt_c == 3) ? 1 : 0; int is_digital = (mt_c == 1 || mt_c == 3) ? 1 : 0; @@ -1503,16 +1565,23 @@ void edacs(dsd_opts * opts, dsd_state * state) fprintf (stderr, "%s", KGRN); fprintf (stderr, " Voice Group Channel Update ::"); } - else + else if (is_test_call == 0) { fprintf (stderr, "%s", KCYN); fprintf (stderr, " Voice Individual Channel Update ::"); } + else + { + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " Voice Test Channel Update ::"); + } if (is_digital == 0) fprintf (stderr, " Analog"); else fprintf (stderr, " Digital"); - if (is_individual == 0) fprintf (stderr, " Group [%04d]", target); - else fprintf (stderr, " Callee [%05d] Caller [%05d]", target, source); - fprintf (stderr, " LCN [%02d]%s", lcn, get_lcn_status_string(lcn)); + if (is_individual == 0) fprintf (stderr, " Group [%04d]", target); + else if (is_test_call == 0) fprintf (stderr, " Callee [%05d] Caller [%05d]", target, source); + fprintf (stderr, " LCN [%02d]%s", lcn, getLcnStatusString(lcn)); + if (is_agency_call == 1) fprintf (stderr, " [Agency]"); + else if (is_fleet_call == 1) fprintf (stderr, " [Fleet]"); if (is_tx_trunk == 0) fprintf (stderr, " [Message Trunking]"); if (is_emergency == 1) { @@ -1539,6 +1608,8 @@ void edacs(dsd_opts * opts, dsd_state * state) 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; + if (is_agency_call) state->edacs_vc_call_type |= EDACS_IS_AGENCY_CALL; + else if (is_fleet_call) state->edacs_vc_call_type |= EDACS_IS_FLEET_CALL; char mode[8]; //allow, block, digital enc sprintf (mode, "%s", ""); @@ -1626,6 +1697,7 @@ void edacs(dsd_opts * opts, dsd_state * state) } //Individual Call Channel Assignment (6.2.4.9) //Analog and digital flag reverse engineered from Montreal STM system + //Test calls reverse engineered from HartLink system else if (mt_b == 0x5) { int is_tx_trunk = (msg_1 & 0x200000) >> 21; @@ -1634,12 +1706,26 @@ void edacs(dsd_opts * opts, dsd_state * state) int target = (msg_1 & 0x3FFF); int source = (msg_2 & 0x3FFF); - fprintf (stderr, "%s", KCYN); - 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]"); + if (target == 0 && source == 0) + { + fprintf (stderr, "%s", KMAG); + fprintf (stderr, " Test Call Channel Assignment ::"); + fprintf (stderr, " LCN [%02d]%s", lcn, getLcnStatusString(lcn)); + + state->edacs_vc_lcn = lcn; + //assign bogus values so that this will show up in ncurses terminal and overwrite current values in the matrix + state->lasttg = 999999999; + state->lastsrc = 999999999; + lcn = 0; //set to zero here, because this is not an actual call, so don't tune to it + } + else { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, " Voice Individual 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, getLcnStatusString(lcn)); + if (is_tx_trunk == 0) fprintf (stderr, " [Message Trunking]"); + } fprintf (stderr, "%s", KNRM); //LCNs >= 26 are reserved to indicate status (queued, busy, denied, etc) @@ -1654,8 +1740,9 @@ void edacs(dsd_opts * opts, dsd_state * state) 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; + if (target == 0 && source == 0) state->edacs_vc_call_type = EDACS_IS_VOICE | EDACS_IS_TEST_CALL; + else 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", ""); @@ -1719,7 +1806,7 @@ void edacs(dsd_opts * opts, dsd_state * state) fprintf (stderr, " Console "); if (is_drop == 0) fprintf (stderr, " Unkey"); else fprintf (stderr, " Drop"); - fprintf (stderr, " :: LID [%05d] LCN [%02d]%s", lid, lcn, get_lcn_status_string(lcn)); + fprintf (stderr, " :: LID [%05d] LCN [%02d]%s", lid, lcn, getLcnStatusString(lcn)); fprintf (stderr, "%s", KNRM); } //Use MT-D @@ -1743,7 +1830,7 @@ void edacs(dsd_opts * opts, dsd_state * state) int adj_site_id = (msg_1 & 0x1F0) >> 4; fprintf (stderr, "%s", KYEL); - fprintf (stderr, " Adjacent Site Control Channel :: Site ID [%02X][%03d] Index [%1d] LCN [%02d]%s", adj_site_id, adj_site_id, adj_site_index, adj_cc_lcn, get_lcn_status_string(adj_cc_lcn)); + fprintf (stderr, " Adjacent Site Control Channel :: Site ID [%02X][%03d] Index [%1d] LCN [%02d]%s", adj_site_id, adj_site_id, adj_site_index, adj_cc_lcn, getLcnStatusString(adj_cc_lcn)); if (adj_site_id == 0 && adj_site_index == 0) fprintf (stderr, " [Adjacency Table Reset]"); else if (adj_site_id != 0 && adj_site_index == 0) fprintf (stderr, " [Priority System Definition]"); else if (adj_site_id == 0 && adj_site_index != 0) fprintf (stderr, " [Adjacencies Table Length Definition]"); @@ -1824,7 +1911,7 @@ void edacs(dsd_opts * opts, dsd_state * state) int group = (msg_1 & 0x7FF); fprintf (stderr, "%s", KYEL); - fprintf (stderr, " Assignment to Auxiliary CC :: Group [%04d] Aux CC LCN [%02d]%s", group, aux_cc_lcn, get_lcn_status_string(aux_cc_lcn)); + fprintf (stderr, " Assignment to Auxiliary CC :: Group [%04d] Aux CC LCN [%02d]%s", group, aux_cc_lcn, getLcnStatusString(aux_cc_lcn)); fprintf (stderr, "%s", KNRM); } //Initiate Test Call Command (6.2.4.16) @@ -1863,7 +1950,7 @@ void edacs(dsd_opts * opts, dsd_state * state) int site_id = (msg_1 & 0x1F); fprintf (stderr, "%s", KYEL); - fprintf (stderr, " Standard/Networked :: Site ID [%02X][%03d] Priority [%1d] CC LCN [%02d]%s", site_id, site_id, priority, cc_lcn, get_lcn_status_string(cc_lcn)); + fprintf (stderr, " Standard/Networked :: Site ID [%02X][%03d] Priority [%1d] CC LCN [%02d]%s", site_id, site_id, priority, cc_lcn, getLcnStatusString(cc_lcn)); if (is_failsoft == 1) { fprintf (stderr, "%s", KRED); @@ -1932,7 +2019,7 @@ void edacs(dsd_opts * opts, dsd_state * state) fprintf (stderr, " ::"); 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)); + fprintf (stderr, " LID [%05d] LCN [%02d]%s", lid, lcn, getLcnStatusString(lcn)); if (is_tx_trunk == 0) fprintf (stderr, " [Message Trunking]"); fprintf (stderr, "%s", KNRM); @@ -2069,7 +2156,7 @@ void edacs(dsd_opts * opts, dsd_state * state) //let users know they need to select an operational mode with the switches below else { - fprintf (stderr, " Detected: Use -fh, -fH, -fe, or -fE for std, esk, ea, or ea-esk;"); + fprintf (stderr, " Detected EDACS: Use -fh, -fH, -fe, or -fE for std, esk, ea, or ea-esk to specify the type"); fprintf (stderr, "\n"); fprintf (stderr, " MSG_1 [%07llX]", msg_1); fprintf (stderr, " MSG_2 [%07llX]", msg_2); diff --git a/src/m17.c b/src/m17.c index 2fdb28e..b081967 100644 --- a/src/m17.c +++ b/src/m17.c @@ -1897,13 +1897,13 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) voice2[i] = sample; } } - + opts->rtl_rms = rtl_return_rms(); #endif } //read in RMS value for vox function; NOTE: will not work correctly SOCAT STDIO TCP due to blocking when no samples to read - if (opts->audio_in_type == 3) opts->rtl_rms = rtl_return_rms(); - else opts->rtl_rms = raw_rms(voice1, nsam, 1) / 2; //dividing by two so mic isn't so sensitive on vox + if (opts->audio_in_type != 3) + opts->rtl_rms = raw_rms(voice1, nsam, 1) / 2; //dividing by two so mic isn't so sensitive on vox //low pass filter if (opts->use_lpf == 1)