EDACS: Display cached call source on Standard, tune group calls on assignment (#241)

* Trim trailing whitespace

* EDACS: Display cached call source on Standard

The logic in `edacs-fme.c` didn't work, in retrospect, because it would have depended on getting back-to-back messages for the same call. In practice, that is unlikely even on an idle system as system state gets displayed.

Instead, cache on the display end, for a "better" user experience.

* EDACS: Pad channel freq to "000.000000 MHz"

* EDACS: Process/tune group calls on assignment
This commit is contained in:
ilyacodes 2024-03-24 17:48:46 -04:00 committed by GitHub
parent 8d432e8b3e
commit c8d00846b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 246 additions and 178 deletions

View File

@ -210,8 +210,8 @@ typedef struct
SF_INFO *audio_in_file_info;
uint32_t rtlsdr_center_freq;
int rtlsdr_ppm_error;
int audio_in_type;
int rtlsdr_ppm_error;
int audio_in_type;
char audio_out_dev[1024];
int audio_out_fd;
int audio_out_fdR; //right channel audio for OSS hack
@ -367,7 +367,7 @@ typedef struct
char group_in_file[1024];
char lcn_in_file[1024];
char chan_in_file[1024];
char key_in_file[1024];
char key_in_file[1024];
//end import filenames
//reverse mute
@ -454,7 +454,7 @@ typedef struct
short s_ru[160*6]; //single sample right
short s_l4u[4][160*6]; //quad sample for up to a P25p2 4V
short s_r4u[4][160*6]; //quad sample for up to a P25p2 4V
//end
//end
int audio_out_idx;
int audio_out_idx2;
int audio_out_idxR;
@ -616,7 +616,7 @@ typedef struct
char dmr_cach_fragment[4][17]; //unsure of size, will need to check/verify
int dmr_cach_counter; //counter for dmr_cach_fragments 0-3; not sure if needed yet.
//dmr talker alias new/fixed stuff
uint8_t dmr_alias_format[2]; //per slot
uint8_t dmr_alias_len[2]; //per slot
@ -1188,7 +1188,7 @@ bool crc8_ok(uint8_t bits[], unsigned int len);
//modified CRC functions for SB/RC
uint8_t crc7(uint8_t bits[], unsigned int len);
uint8_t crc3(uint8_t bits[], unsigned int len);
uint8_t crc4(uint8_t bits[], unsigned int len);
uint8_t crc4(uint8_t bits[], unsigned int len);
//LFSR and LFSRP code courtesy of https://github.com/mattames/LFSR/
void LFSR(dsd_state * state);

View File

@ -7,6 +7,9 @@
*
* LWVMOBILE
* 2022-08 DSD-FME Florida Man Edition
*
* ilyacodes
* 2024-03 EDACS-FME display improvements
*-----------------------------------------------------------------------------*/
@ -110,13 +113,13 @@ char * DMRBusrtTypes[32] = {
"R34D ",
"IDLE ",
"R1_D ",
"ERR ",
"ERR ",
"DUID ERR ",
"R-S ERR ",
"CRC ERR ",
"NULL ",
"VOICE",
" ",
"VOICE",
" ",
"INIT ",
"INIT ",
"PTT", //20 MAC
@ -188,7 +191,7 @@ void beeper (dsd_opts * opts, dsd_state * state, int lr)
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0)
pa_simple_write(opts->pulse_digi_dev_out, samp_s, 160*2, NULL);
}
else if (opts->audio_out_type == 8) //UDP Audio
@ -204,7 +207,7 @@ void beeper (dsd_opts * opts, dsd_state * state, int lr)
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0)
udp_socket_blaster (opts, state, 160*2, samp_s);
}
else if (opts->audio_out_type == 1) //STDOUT
@ -245,10 +248,10 @@ void beeper (dsd_opts * opts, dsd_state * state, int lr)
samp_su[(i*6)+4] = outbuf[4];
samp_su[(i*6)+5] = outbuf[5];
}
write (opts->audio_out_fd, samp_su, 960*2);
}
}
}
@ -328,7 +331,7 @@ char *choicesc[] = {
"Setup and Start RTL Input ",
"Retune RTL Dongle ",
"Toggle C4FM/QPSK (P2 TDMA CC)",
"Toggle C4FM/QPSK (P1 FDMA CC)",
"Toggle C4FM/QPSK (P1 FDMA CC)",
"Start TCP Direct Link Audio",
"Configure RIGCTL",
"Stop All Decoded WAV Saving",
@ -415,7 +418,7 @@ void ncursesOpen (dsd_opts * opts, dsd_state * state)
//this is primarily used to push a quick audio blip through OSS so it will show up in the mixer immediately
// if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
// beeper (opts, state, 0); //causes crash in Cygwin when mixed input/output
//terminate all values
for (int i = 0; i < 10; i++)
sprintf (alias_ch[i], "%s", "");
@ -462,7 +465,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
closePulseOutput (opts);
}
//close OSS output
//close OSS output
if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
{
close (opts->audio_out_fd);
@ -760,7 +763,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->rtl_dev_index = i;
break;
}
}
entry_win = newwin(17, WIDTH+20, starty+10, startx+10);
@ -861,7 +864,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
// if (opts->audio_out == 0)
// {
// opts->audio_out = 1;
// opts->audio_out_type = 0;
// opts->audio_out_type = 0;
// // state->audio_out_buf_p = 0;
// // state->audio_out_buf_pR = 0;
// state->audio_out_idx = 0;
@ -933,7 +936,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->audio_in_type = 0;
}
else opts->audio_in_type = 5;
}
state->audio_smoothing = 0; //disable smoothing to prevent random crackling/buzzing
@ -1222,7 +1225,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
wscanw(entry_win, "%lld", &state->R);
noecho();
if (state->R > 0x7FFF) state->R = 0x7FFF;
state->keyloader = 0; //turn off keyloader
}
//toggle enforcement of basic privacy key over enc bit set on traffic
@ -1844,7 +1847,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
{
openOSSOutput (opts);
}
if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method
{
@ -1854,7 +1857,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
if (opts->audio_in_type == 3) //open rtl input if it is the specified input method
{
// ncursesPrinter (opts, state); //not sure why this was placed here originally, but causes a double free core dump when calling free(timestr)
#ifdef USE_RTLSDR
#ifdef USE_RTLSDR
if (opts->rtl_started == 0)
{
opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again
@ -1892,7 +1895,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN -
{
timeout(0); //
timeout(0); //
c = getch(); //
}
@ -1908,7 +1911,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//Variable reset/set section
//set lls sync types
if (state->synctype >= 0 && state->synctype < 39)
if (state->synctype >= 0 && state->synctype < 39)
{
lls = state->synctype;
}
@ -2002,16 +2005,22 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//Edacs - ProVoice
if ( (lls == 14 || lls == 15 || lls == 37 || lls == 38) && state->carrier == 1)
{
if (state->edacs_vc_lcn != -1)
if (state->edacs_vc_lcn != -1)
{
call_matrix[state->edacs_vc_lcn][0] = lls;
call_matrix[state->edacs_vc_lcn][1] = state->edacs_vc_lcn;
call_matrix[state->edacs_vc_lcn][2] = state->lasttg;
call_matrix[state->edacs_vc_lcn][3] = state->lastsrc;
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.
//
//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)
call_matrix[state->edacs_vc_lcn][3] = state->lastsrc;
call_matrix[state->edacs_vc_lcn][4] = 1;
call_matrix[state->edacs_vc_lcn][5] = time(NULL);
}
}
}
@ -2074,7 +2083,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
}
//TODO: Find better placement for these
if ( strcmp(state->str50a, "") != 0 )
sprintf (alias_ch[9], "%s", state->str50a);
@ -2257,7 +2266,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
// state->lastsrc = 0;
// rd = 0;
// tg = 0;
// }
// }
// if (state->dmrburstR == 2 && state->dmr_end_alert[1] == 0) //if TLC and flag not tripped
// {
// beeper (opts, state, 1);
@ -2266,7 +2275,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
// state->lastsrcR = 0;
// rdR = 0;
// tgR = 0;
// }
// }
// }
//Start Printing Section
@ -2276,7 +2285,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
printw ("------------------------------------------------------------------------------\n");
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231015)");
printw ("------------------------------------------------------------------------------\n");
printw ("------------------------------------------------------------------------------\n");
}
#elif LIMAZULUTWEAKS
if (opts->ncurses_compact == 1)
@ -2318,7 +2327,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
#elif ZDEV_BUILD
if (i == 5) printw (" %s ", "AW ");
if (i == 6) printw (" %s \n", GIT_TAG);
#else
#else
if (i == 5) printw (" %s ", "AW ");
if (i == 6) printw (" %s \n", GIT_TAG);
#endif
@ -2383,7 +2392,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw (" SQ: %i;", opts->rtl_squelch_level);
printw (" RMS: %04li;", opts->rtl_rms);
printw (" BW: %i kHz;", opts->rtl_bandwidth);
printw (" FRQ: %i;", opts->rtlsdr_center_freq);
printw (" FRQ: %i;", opts->rtlsdr_center_freq);
if (opts->rtl_udp_port != 0) printw ("\n| External RTL Tuning on UDP Port: %i", opts->rtl_udp_port);
printw ("\n");
}
@ -2529,7 +2538,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
attron(COLOR_PAIR(2));
printw (" Standard/Network");
attron(COLOR_PAIR(4));
printw (" Extended Address");
printw (" Extended Address");
}
printw (" Mode (S);");
@ -2556,7 +2565,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
else if (state->ea_mode == 1)
{
printw (" standard/network");
printw (" EXTENDED ADDRESS");
printw (" EXTENDED ADDRESS");
}
printw (" Mode (S);");
@ -2581,9 +2590,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (opts->scanner_mode == 1)
{
printw ("| Scan Mode: ");
if (state->lcn_freq_roll != 0)
if (state->lcn_freq_roll != 0)
printw (" Frequency: %.06lf Mhz", (double)state->trunk_lcn_freq[state->lcn_freq_roll-1]/1000000);
printw (" Speed: %.02lf sec \n", opts->trunk_hangtime); //not sure values less than 1 make a difference, may be system/environment dependent
printw (" Speed: %.02lf sec \n", opts->trunk_hangtime); //not sure values less than 1 make a difference, may be system/environment dependent
}
if (opts->reverse_mute == 1) printw ("| Reverse Mute - Muting Unencrypted Voice\n");
@ -2625,7 +2634,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
printw ("\n");
printw ("| In Level: [%02d%%] \n", level);
if (opts->dmr_stereo == 0)
{
printw ("| Voice Error: [%i][%i]", state->errs, state->errs2);
@ -2648,7 +2657,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("------------------------------------------------------------------------------\n");
printw ("--Call Info-------------------------------------------------------------------\n");
//DSTAR
if (lls == 6 || lls == 7 || lls == 18 || lls == 19)
{
@ -2689,7 +2698,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("RESERVED (%012llx) ", state->m17_dst);
else
printw("%s", state->m17_dst_str);
printw ("\n");
printw ("| ");
@ -2699,7 +2708,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
else
printw("%s", state->m17_src_str);
printw ("\n");
printw ("| ");
@ -2726,7 +2735,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (state->m17_enc == 3)
{
printw (" Reserved Enc - Type: %d", state->m17_enc_st);
}
}
printw ("\n");
@ -2787,7 +2796,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
// printw ("%c", state->ysf_txt[i][j]);
// }
// // printw (" "); //just a single space between each 'block'
// }
// }
printw ("\n");
@ -2810,7 +2819,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
printw (" - Frequency: %.06lf Mhz ", (double)state->p25_cc_freq/1000000);
}
}
}
else if (opts->p25_is_tuned == 1)
{
if (idas == 0) printw ("Monitoring RTCH Channel"); //Traffic Channel
@ -2823,8 +2832,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("\n");
}
printw ("| ");
// #ifdef LIMAZULUTWEAKS
@ -2922,10 +2931,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
//Active Trunking Channels (NXDN and IDAS)
if (1 == 1) //opts->p25_trunk
if (1 == 1) //opts->p25_trunk
{
printw ("\n");
printw ("| ");
printw ("| ");
//active channel display
attron(COLOR_PAIR(4));
@ -2943,8 +2952,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("\n");
}
//P25 and DMR BS/MS
//P25 and DMR BS/MS
if ( lls == 0 || lls == 1 || lls == 12 || lls == 13 || lls == 10 ||
lls == 11 || lls == 32 || lls == 33 || lls == 34 || lls == 35 || lls == 36)
{
@ -2955,7 +2964,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
// printw ("%s %s", state->dmr_branding, state->dmr_branding_sub);
printw ("%s ", state->dmr_branding);
printw ("%s", state->dmr_branding_sub);
printw ("%s", state->dmr_site_parms); //site id, net id, etc
printw ("%s", state->dmr_site_parms); //site id, net id, etc
if (state->dmr_rest_channel > 0)
{
printw ("Rest LSN: %02d; ", state->dmr_rest_channel);
@ -2968,7 +2977,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
}
}
else if (lls == 32 || lls == 33 || lls == 34)
{
@ -2997,7 +3006,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw (" Phase 2 Invalid Parameters ");
attron(COLOR_PAIR(3));
}
else
else
{
if (state->p25_cc_freq != 0)
{
@ -3119,7 +3128,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//Not always correct, or correct at all, depends on context
//this is already in the call_string anyways
// if(state->dmrburstL == 16 && state->dmr_so == 0x40 && state->R == 0) //0100 0000
// {
// attron(COLOR_PAIR(2));
@ -3156,13 +3165,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//Embedded GPS (not LRRP)
printw ("%s ", state->dmr_embedded_gps[0]);
//Embedded Talker Alias Blocks
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 7; j++)
{
printw ("%s", state->dmr_alias_block_segment[0][i][j]);
printw ("%s", state->dmr_alias_block_segment[0][i][j]);
}
}
@ -3205,7 +3214,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//Slot 2 [1] -- Also Including DMR MS now to keep the display more 'uniform' in nature
// if (lls < 30 || lls == 35 || lls == 36)
{
{
printw ("| SLOT 2 - ");
if (state->dmrburstR < 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0)
{
@ -3221,10 +3230,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("%s | ", state->call_string[1]);
printw ("%s ", DMRBusrtTypes[state->dmrburstR]);
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*");
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*");
printw ("\n");
printw ("| V XTRA | "); //10 spaces
if(state->dmrburstR == 16 && state->payload_algidR == 0 && (state->dmr_soR & 0xCF) == 0x40) //4F or CF mask?
@ -3345,7 +3354,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if(state->dmrburstR == 16 || state->dmrburstR == 21) //only during call
{
//Embedded GPS (not LRRP)
attron(COLOR_PAIR(4));
printw ("%s ", state->dmr_embedded_gps[1]);
@ -3355,7 +3364,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
for (int j = 0; j < 7; j++)
{
printw ("%s", state->dmr_alias_block_segment[1][i][j]);
printw ("%s", state->dmr_alias_block_segment[1][i][j]);
}
}
@ -3373,7 +3382,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
attron(COLOR_PAIR(4));
printw ("%s", state->dmr_lrrp_gps[1]);
}
//Group Name Labels from CSV import
if (state->dmrburstR == 16 || state->dmrburstR > 19)
{
@ -3461,7 +3470,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//EDACS and ProVoice
if (lls == 14 || lls == 15 || lls == 37 || lls == 38)
{
attroff (COLOR_PAIR(3)); //colors off for EDACS
attroff (COLOR_PAIR(3)); //colors off for EDACS
if (state->edacs_site_id != 0)
{
if (opts->p25_is_tuned == 0)
@ -3472,8 +3481,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
printw ("| Monitoring Voice Channel - LCN [%02d]\n", state->edacs_tuned_lcn);
//since we are tuned, keep updating the time so it doesn't disappear during call
call_matrix[state->edacs_tuned_lcn][5] = time(NULL);
}
call_matrix[state->edacs_tuned_lcn][5] = time(NULL);
}
printw ("| SITE [%03lld][%02llX]", state->edacs_site_id, state->edacs_site_id);
if (state->ea_mode == 1)
@ -3493,8 +3502,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
// Compute 4:4:3 AFS for display purposes only
int a = (call_matrix[i][2] >> 7) & 0xF;
int fs = call_matrix[i][2] & 0x7F;
printw ("| - LCN [%02d][%.06lf] MHz", i, (double)state->trunk_lcn_freq[i-1]/1000000);
printw ("| - LCN [%02d][%010.06lf] MHz", i, (double)state->trunk_lcn_freq[i-1]/1000000);
//print Control Channel on LCN line with the current Control Channel
if ( (i) == state->edacs_cc_lcn)
{
@ -3503,9 +3512,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
attroff (COLOR_PAIR(1));
}
//print active calls on corresponding LCN line
if ((i != state->edacs_cc_lcn) && time(NULL) - call_matrix[i][5] < 2)
if ((i != state->edacs_cc_lcn) && time(NULL) - call_matrix[i][5] < 2)
{
attron (COLOR_PAIR(3));
attron (COLOR_PAIR(3));
if (state->ea_mode == 1) {
if (call_matrix[i][2] + 1 == 0)
// System all-call
@ -3544,12 +3553,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
break;
}
}
attroff (COLOR_PAIR(3));
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) )
//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) )
{
attron (COLOR_PAIR(2));
attron (COLOR_PAIR(2));
if (state->ea_mode == 1) {
if (call_matrix[i][2] + 1 == 0)
// System all-call
@ -3588,14 +3597,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
break;
}
}
attroff (COLOR_PAIR(2));
attroff (COLOR_PAIR(2));
}
if (i == state->edacs_tuned_lcn && opts->p25_is_tuned == 1) printw (" **T**"); //asterisk which lcn is opened
printw ("\n");
}
if (state->carrier == 1)
{
attron (COLOR_PAIR(3));
attron (COLOR_PAIR(3));
}
}
@ -3687,10 +3696,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//EDACS and ProVoice, outside of timestamp loop
if (call_matrix[j][0] == 14 || call_matrix[j][0] == 15 || call_matrix[j][0] == 37 || call_matrix[j][0] == 38 )
{
if (call_matrix[j][2] != 0)
if (call_matrix[j][2] != 0)
{
printw ("| ");
printw ("%s ", getDateC(call_matrix[j][5]) );
printw ("%s ", getDateC(call_matrix[j][5]) );
printw ("%s ", getTimeC(call_matrix[j][5]) );
printw ("LCN [%2lld] ", call_matrix[j][1]);
if (state->ea_mode == 1)
@ -3705,10 +3714,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
// Group call
printw ("Target [%8lld] Source [%8lld]", call_matrix[j][2], call_matrix[j][3]);
}
else
else
{
// Compute 4:4:3 AFS for display purposes only
int a = (call_matrix[j][2] >> 7) & 0xF;
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
@ -3719,7 +3728,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
else
// Group call
printw ("Target [%6lld][%02d-%03d] Source [%5lld]", call_matrix[j][2], a, fs, call_matrix[j][3]);
}
}
//test
for (int k = 0; k < state->group_tally; k++)
{
@ -3739,7 +3748,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//end test
printw ("\n");
}
}
} //end Call History
//fence bottom
@ -3796,7 +3805,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
else if (opts->slot1_on == 0)
{
opts->slot1_on = 1;
if (opts->audio_out_type == 5) //OSS 48k/1
if (opts->audio_out_type == 5) //OSS 48k/1
{
opts->slot_preference = 0; //slot 1
// opts->slot2_on = 0; //turn off slot 2
@ -3822,7 +3831,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
else if (opts->slot2_on == 0)
{
opts->slot2_on = 1;
if (opts->audio_out_type == 5) //OSS 48k/1
if (opts->audio_out_type == 5) //OSS 48k/1
{
opts->slot_preference = 1; //slot 2
// opts->slot1_on = 0; //turn off slot 1
@ -4028,14 +4037,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
fprintf (stderr, "-T %s wav file directory does not exist\n", wav_file_directory);
fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory);
mkdir(wav_file_directory, 0700);
mkdir(wav_file_directory, 0700);
}
opts->dmr_stereo_wav = 1;
//catch all in case of no file name set, won't crash or something
sprintf (opts->wav_out_file, "./%s/DSD-FME-T1.wav", opts->wav_out_dir);
sprintf (opts->wav_out_fileR, "./%s/DSD-FME-T2.wav", opts->wav_out_dir);
openWavOutFileL (opts, state);
openWavOutFileR (opts, state);
openWavOutFileL (opts, state);
openWavOutFileR (opts, state);
}
//this one could cause issues, but seems okay
@ -4052,15 +4061,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//
#ifdef AERO_BUILD //this might be okay on Aero as well, will need to look into and/or test
//
//
#else
if (c == 115) //'s' key, stop playing wav or symbol in files
{
if (opts->symbolfile != NULL)
{
if (opts->audio_in_type == 4)
if (opts->audio_in_type == 4)
{
fclose(opts->symbolfile);
fclose(opts->symbolfile);
}
}
@ -4074,12 +4083,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
opts->audio_in_type = 0;
openPulseInput(opts);
}
else opts->audio_in_type = 5; //exitflag = 1;
else opts->audio_in_type = 5; //exitflag = 1;
}
#endif
//makes buzzing sound when locked out in new audio config and short, probably something to do with processaudio running or not running
//makes buzzing sound when locked out in new audio config and short, probably something to do with processaudio running or not running
if (state->lasttg != 0 && opts->frame_provoice != 1 && c == 33) //SHIFT+'1' key (exclamation point), lockout slot 1 or conventional tg from tuning/playback during session
{
state->group_array[state->group_tally].groupNumber = state->lasttg;
@ -4215,40 +4224,40 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
// if (c == 48) //'0' key, toggle upsampled audio smoothing
// {
// if (state->audio_smoothing == 1) state->audio_smoothing = 0;
// else state->audio_smoothing = 1;
// else state->audio_smoothing = 1;
// }
if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode
if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode
{
if (opts->trunk_use_allow_list == 1) opts->trunk_use_allow_list = 0;
else opts->trunk_use_allow_list = 1;
else opts->trunk_use_allow_list = 1;
}
if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls
{
if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0;
else opts->trunk_tune_private_calls = 1;
else opts->trunk_tune_private_calls = 1;
}
if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls
{
if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0;
else opts->trunk_tune_data_calls = 1;
else opts->trunk_tune_data_calls = 1;
}
if (opts->p25_trunk == 1 && c == 101) //'e' key, toggle tune enc calls (P25 only on certain grants)
{
if (opts->trunk_tune_enc_calls == 1) opts->trunk_tune_enc_calls = 0;
else opts->trunk_tune_enc_calls = 1;
else opts->trunk_tune_enc_calls = 1;
}
if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls
{
if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0;
else opts->trunk_tune_group_calls = 1;
else opts->trunk_tune_group_calls = 1;
}
if (c == 70) //'F' key - toggle agressive sync/crc failure/ras
if (c == 70) //'F' key - toggle agressive sync/crc failure/ras
{
if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1;
else opts->aggressive_framesync = 0;
@ -4256,7 +4265,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc.
{
//dmr trunking/ncurses stuff
//dmr trunking/ncurses stuff
state->dmr_rest_channel = -1; //init on -1
state->dmr_mfid = -1; //
@ -4318,7 +4327,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (opts->audio_in_type == 0) closePulseInput(opts);
fprintf (stderr, "TCP Socket Connected Successfully.\n");
opts->audio_in_type = 8;
}
}
}
else fprintf (stderr, "TCP Socket Connection Error.\n");
}
@ -4390,7 +4399,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
state->symbolCenter = 3;
}
fprintf (stderr, "\n User Activated Return to CC; \n ");
fprintf (stderr, "\n User Activated Return to CC; \n ");
}
@ -4436,15 +4445,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
state->lcn_freq_roll++;
//check roll again if greater than expected, then go back to zero
if (state->lcn_freq_roll >= state->lcn_freq_count)
if (state->lcn_freq_roll >= state->lcn_freq_count)
{
state->lcn_freq_roll = 0; //reset to zero
}
}
}
}
//check that we have a non zero value first, then tune next frequency
if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
{
//rigctl
if (opts->use_rigctl == 1)
@ -4461,7 +4470,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
fprintf (stderr, "\n User Activated Channel Cycle;");
fprintf (stderr, " Tuning to Frequency: %.06lf MHz\n",
fprintf (stderr, " Tuning to Frequency: %.06lf MHz\n",
(double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000);
}
@ -4483,18 +4492,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
if (opts->m17encoder == 1 && c == 92) //'\' key - toggle M17 encoder Encode + TX
if (opts->m17encoder == 1 && c == 92) //'\' key - toggle M17 encoder Encode + TX
{
if (state->m17encoder_tx == 0) state->m17encoder_tx = 1;
else state->m17encoder_tx = 0;
//flag on the EOT marker to send last frame after toggling encoder to zero
if (state->m17encoder_tx == 0) state->m17encoder_eot = 1;
}
if(opts->frame_provoice == 1 && c == 65) //'A' Key, toggle ESK mask 0xA0
@ -4523,7 +4532,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
//anything with an entry box will need the inputs and outputs stopped first
//so probably just write a function to handle c input, and when c = certain values
//so probably just write a function to handle c input, and when c = certain values
//needing an entry box, then stop all of those
//allocated memory pointer needs to be free'd each time

View File

@ -1,5 +1,5 @@
/*-------------------------------------------------------------------------------
* EDACS-FME
* EDACS-FME
* A program for decoding EDACS (ported to DSD-FME)
* https://github.com/lwvmobile/edacs-fm
*
@ -15,9 +15,9 @@
*
* LWVMOBILE
* 2023-11 Version EDACS-FM Florida Man Edition
*
*
* ilyacodes
* 2024-03 added EA i-call and login message decoding
* 2024-03 rewrite EDACS standard parsing to spec, add reverse-engineered EA messages
*-----------------------------------------------------------------------------*/
#include "dsd.h"
@ -88,7 +88,7 @@ void openWavOutFile48k (dsd_opts * opts, dsd_state * state)
//generic rms type function
long int gen_rms(short *samples, int len, int step)
{
int i;
long int rms;
long p, t, s;
@ -184,7 +184,7 @@ void analog_dc_block_filter(short * input, int len)
avg = sum / len;
avg = (avg + dc_avg * 9) / 10;
for (i=0; i < len; i++)
input[i] -= (short)avg;
input[i] -= (short)avg;
dc_avg = avg;
}
@ -202,7 +202,7 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
short analog1[960];
short analog2[960];
short analog3[960];
short sample = 0;
short sample = 0;
state->last_cc_sync_time = time(NULL);
state->last_vc_sync_time = time(NULL);
@ -217,7 +217,7 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
fprintf (stderr, "\n");
while (!exitflag && count > 0)
{
{
//this will only work on 48k/1 short output
if (opts->audio_in_type == 0)
{
@ -243,7 +243,7 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
}
//NOTE: The core dumps observed previously were due to SDR++ Remote Server connection dropping due to Internet/Other issues
//and unlike in the main livescanner loop where it just hangs, this loop will cause a core dump. The observed issue
//and unlike in the main livescanner loop where it just hangs, this loop will cause a core dump. The observed issue
//has not occurred when using SDR++ on local hardware, just the remote server software over the Internet.
//NOTE: The fix below does not apply to above observed issue, as the TCP connection will not drop, there will just
@ -291,7 +291,7 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
}
analog3[i] = sample;
}
//this rms will only work properly (for now) with squelch enabled in SDR++
rms = gen_rms(analog3, 960, 1);
}
@ -427,7 +427,7 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
fprintf (stderr, "%s", KNRM);
if (count > 0) fprintf (stderr, "\n");
}
}
@ -437,7 +437,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
unsigned long long int fr_1 = 0xFFFFFFFFFF; //40-bit frames
unsigned long long int fr_2 = 0; //each is a 40 bit frame that repeats 3 times
unsigned long long int fr_3 = 0; //two messages per frame
unsigned long long int fr_4 = 0xFFFFFFFFFF;
unsigned long long int fr_4 = 0xFFFFFFFFFF;
unsigned long long int fr_5 = 0;
unsigned long long int fr_6 = 0;
@ -473,18 +473,18 @@ void edacs(dsd_opts * opts, dsd_state * state)
{
//only fr_1 and fr4 are going to matter
fr_1 = fr_1 << 1;
fr_1 = fr_1 | edacs_bit[i];
fr_1 = fr_1 | edacs_bit[i];
fr_2 = fr_2 << 1;
fr_2 = fr_2 | edacs_bit[i+40];
fr_3 = fr_3 << 1;
fr_3 = fr_3 | edacs_bit[i+80];
fr_4 = fr_4 << 1;
fr_4 = fr_4 | edacs_bit[i+120];
fr_4 = fr_4 << 1;
fr_4 = fr_4 | edacs_bit[i+120];
fr_5 = fr_5 << 1;
fr_5 = fr_5 | edacs_bit[i+160];
fr_6 = fr_6 << 1;
fr_6 = fr_6 | edacs_bit[i+200];
fr_6 = fr_6 | edacs_bit[i+200];
}
@ -508,7 +508,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
else //BCH Pass, continue from here.
{
//Auto Detection Modes Have Been Removed due to reliability issues,
//Auto Detection Modes Have Been Removed due to reliability issues,
//users will now need to manually specify these options:
/*
-fh Decode only EDACS Standard/ProVoice*\n");
@ -521,7 +521,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
//TODO: Consider re-adding the auto code to make a suggestion to users
//as to which mode to proceed in?
//Color scheme:
// - KRED - critical information (emergency, failsoft, etc)
// - KYEL - system data
@ -536,7 +536,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
fr_1t = fr_1t ^ fr_esk_mask;
fr_4t = fr_4t ^ fr_esk_mask;
//Start Extended Addressing Mode
//Start Extended Addressing Mode
if (state->ea_mode == 1)
{
unsigned char mt1 = (fr_1t & 0xF800000000) >> 35;
@ -555,7 +555,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
// MT2 is meaningless if MT1 is not 0x1F
if (mt1 == 0x1F)
fprintf (stderr, "; MT2: %X) ", mt2);
else
else
fprintf (stderr, ") ");
}
@ -601,7 +601,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
if (((fr_4t >> 12) & 0x1F) != 0)
{
state->edacs_cc_lcn = ((fr_4t >> 12) & 0x1F);
if (state->edacs_cc_lcn > state->edacs_lcn_count && lcn < 26) //26, or 27. shouldn't matter don't think cc lcn will give a status lcn val
if (state->edacs_cc_lcn > state->edacs_lcn_count && lcn < 26) //26, or 27. shouldn't matter don't think cc lcn will give a status lcn val
{
state->edacs_lcn_count = state->edacs_cc_lcn;
}
@ -682,7 +682,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
fprintf (stderr, " FR_4 [%010llX]", fr_4t);
}
}
}
//TDMA Group Grant Update (never observed, unknown if ever used on any EDACS system)
else if (mt1 == 0x1)
@ -713,7 +713,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
lcn = (fr_1t & 0x3E0000000) >> 29;
//LCNs greater than 26 are considered status values, "Busy, Queue, Deny, etc"
if (lcn > state->edacs_lcn_count && lcn < 26)
if (lcn > state->edacs_lcn_count && lcn < 26)
{
state->edacs_lcn_count = lcn;
}
@ -768,7 +768,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
if (state->tg_hold != 0 && state->tg_hold == group) sprintf (mode, "%s", "A");
//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 (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)
{
@ -781,11 +781,11 @@ void edacs(dsd_opts * opts, dsd_state * state)
else
openWavOutFile48k (opts, state);
}
//do condition here, in future, will allow us to use tuning methods as well, or rtl_udp as well
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
@ -805,7 +805,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
}
}
}
}
//I-Call Grant Update
@ -814,7 +814,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
lcn = (fr_4t & 0x1F00000000) >> 32;
//LCNs greater than 26 are considered status values, "Busy, Queue, Deny, etc"
if (lcn > state->edacs_lcn_count && lcn < 26)
if (lcn > state->edacs_lcn_count && lcn < 26)
{
state->edacs_lcn_count = lcn;
}
@ -843,7 +843,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
//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 (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)
{
@ -856,11 +856,11 @@ void edacs(dsd_opts * opts, dsd_state * state)
else
openWavOutFile48k (opts, state);
}
//do condition here, in future, will allow us to use tuning methods as well, or rtl_udp as well
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
@ -897,7 +897,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
lcn = (fr_1t & 0x3E0000000) >> 29;
//LCNs greater than 26 are considered status values, "Busy, Queue, Deny, etc"
if (lcn > state->edacs_lcn_count && lcn < 26)
if (lcn > state->edacs_lcn_count && lcn < 26)
{
state->edacs_lcn_count = lcn;
}
@ -914,7 +914,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
else fprintf (stderr, " Digital System All-Call");
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, "%s", KNRM);
@ -925,7 +925,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "A");
//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 (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)
{
@ -938,11 +938,11 @@ void edacs(dsd_opts * opts, dsd_state * state)
else
openWavOutFile48k (opts, state);
}
//do condition here, in future, will allow us to use tuning methods as well, or rtl_udp as well
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
@ -962,7 +962,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
}
}
}
}
//Login
@ -1055,7 +1055,78 @@ void edacs(dsd_opts * opts, dsd_state * state)
}
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;
}
state->edacs_vc_lcn = lcn;
state->lasttg = group;
state->lastsrc = lid;
char mode[8]; //allow, block, digital enc
sprintf (mode, "%s", "");
//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");
//Get group mode for calls that are in the allow/whitelist
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == group)
{
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
//TG hold on EDACS Standard/Net -- block non-matching target, allow matching group
if (state->tg_hold != 0 && state->tg_hold != group) sprintf (mode, "%s", "B");
if (state->tg_hold != 0 && state->tg_hold == group) 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 TG %04d SRC %05d.wav", getDateE(), timestr, state->edacs_site_id, group, lid);
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, group, 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, group, lcn);
#endif
}
}
}
}
//Data Call Channel Assignment (6.2.4.3)
else if (mt_a == 0x5)
@ -1114,7 +1185,7 @@ 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;
fprintf (stderr, "%s", KMAG);
fprintf (stderr, " Interconnect Channel Assignment :: Type");
if (mt_c == 0x2) fprintf (stderr, " [Voice]");
@ -1138,7 +1209,7 @@ 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 == 0) ? group : lid;
//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;
@ -1173,23 +1244,12 @@ void edacs(dsd_opts * opts, dsd_state * state)
}
state->edacs_vc_lcn = lcn;
//If we have the same target already in progress, we can keep the source ID since we know it (and don't get
//it in this CC message). But if we have a different target, we should clear out to a source ID of 0.
if (is_individual == 0)
{
if (state->lasttg != target) {
state->lasttg = target;
state->lastsrc = 0;
}
}
else
{
//Use IDs > 10000 to represent i-call targets to differentiate from TGs
if (state->lasttg != target + 10000) {
state->lasttg = target + 10000;
state->lastsrc = 0;
}
}
//Use IDs > 10000 to represent i-call targets to differentiate from TGs
if (is_individual == 0) state->lasttg = target;
else state->lasttg = target + 10000;
//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;
char mode[8]; //allow, block, digital enc
sprintf (mode, "%s", "");
@ -1259,7 +1319,6 @@ void edacs(dsd_opts * opts, dsd_state * state)
#endif
}
}
}
}
//System Assigned ID (6.2.4.8)
@ -1455,7 +1514,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
state->edacs_site_id = site_id;
//LCNs >= 26 are reserved to indicate status (queued, busy, denied, etc)
if (state->edacs_cc_lcn > state->edacs_lcn_count && cc_lcn < 26)
if (state->edacs_cc_lcn > state->edacs_lcn_count && cc_lcn < 26)
{
state->edacs_lcn_count = state->edacs_cc_lcn;
}
@ -1580,7 +1639,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
} //end Standard or Networked
//let users know they need to select an operational mode with the switches below
else
else
{
fprintf (stderr, " Detected: Use -fh, -fH, -fe, or -fE for std, esk, ea, or ea-esk;");
fprintf (stderr, "\n");
@ -1608,13 +1667,13 @@ void eot_cc(dsd_opts * opts, dsd_state * state)
//jump back to CC here
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
{
//rigctl
if (opts->use_rigctl == 1)
{
state->lasttg = 0;
state->lastsrc = 0;
state->payload_algid = 0;
state->payload_algid = 0;
state->payload_keyid = 0;
state->payload_miP = 0;
//reset some strings
@ -1625,7 +1684,7 @@ void eot_cc(dsd_opts * opts, dsd_state * state)
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
}
//rtl
@ -1651,4 +1710,4 @@ void eot_cc(dsd_opts * opts, dsd_state * state)
}
}