mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
4744 lines
150 KiB
C
4744 lines
150 KiB
C
/*-------------------------------------------------------------------------------
|
||
* dsd_ncurses.c
|
||
* DSD-FME ncurses terminal printer with menu system
|
||
*
|
||
* ASCII art generated by:
|
||
* https://fsymbols.com/generators/carty/
|
||
*
|
||
* LWVMOBILE
|
||
* 2022-08 DSD-FME Florida Man Edition
|
||
*
|
||
* ilyacodes
|
||
* 2024-03 EDACS-FME display improvements
|
||
*-----------------------------------------------------------------------------*/
|
||
|
||
|
||
#include "dsd.h"
|
||
#include "git_ver.h"
|
||
|
||
#ifdef USE_RTLSDR
|
||
#include <rtl-sdr.h>
|
||
//use to list out all detected RTL dongles
|
||
char vendor[256], product[256], serial[256], userdev[256];
|
||
int device_count = 0;
|
||
#endif
|
||
|
||
uint32_t temp_freq = -1;
|
||
|
||
|
||
//struct for checking existence of directory to write to
|
||
struct stat st_wav = {0};
|
||
static char alias_ch[10][50];
|
||
int reset = 0;
|
||
char * timestr;
|
||
int tg;
|
||
int tgR;
|
||
int tgn;
|
||
int rd;
|
||
int rdR;
|
||
int rn;
|
||
int nc;
|
||
int src;
|
||
int lls = -1;
|
||
int dcc = -1;
|
||
int i = 0;
|
||
char versionstr[25];
|
||
unsigned long long int call_matrix[33][6];
|
||
|
||
char * FM_bannerN[9] = {
|
||
" ",
|
||
" ██████╗ ██████╗██████╗ ███████╗███╗ ███╗███████╗ ",
|
||
" ██╔══██╗██╔════╝██╔══██╗ ██╔════╝████╗ ████║██╔════╝ ",
|
||
" ██║ ██║╚█████╗ ██║ ██║ █████╗ ██╔████╔██║█████╗ ",
|
||
" ██║ ██║ ╚═══██╗██║ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
|
||
" ██████╔╝██████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║███████╗ ",
|
||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ",
|
||
" ",
|
||
" "
|
||
};
|
||
|
||
char * SyncTypes[44] = {
|
||
"P25P1",
|
||
"P25P1",
|
||
"X2TDMA DATA",
|
||
"X2TDMA DATA",
|
||
"X2TDMA VOICE",
|
||
"X2TDMA VOICE",
|
||
"DSTAR", //voice
|
||
"DSTAR", //voice
|
||
"NXDN VOICE",
|
||
"NXDN VOICE",
|
||
"DMR", //10
|
||
"DMR",
|
||
"DMR",
|
||
"DMR",
|
||
"EDACS/PV",
|
||
"EDACS/PV",
|
||
"NXDN VOICE", //DATA
|
||
"NXDN VOICE", //DATA
|
||
"DSTAR", //header
|
||
"DSTAR", //header
|
||
"dPMR", //20
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"NXDN",
|
||
"NXDN",
|
||
"YSF", //30
|
||
"YSF", //31
|
||
"DMR",
|
||
"DMR",
|
||
"DMR",
|
||
"P25P2",
|
||
"P25P2",
|
||
"EDACS/PV", //37
|
||
"EDACS/PV", //38
|
||
"",
|
||
""
|
||
};
|
||
|
||
char * DMRBusrtTypes[32] = {
|
||
"PI ",
|
||
"VLC ",
|
||
"TLC ",
|
||
"CSBK ",
|
||
"MBCH ",
|
||
"MBCC ",
|
||
"DATA ",
|
||
"R12D ",
|
||
"R34D ",
|
||
"IDLE ",
|
||
"R1_D ",
|
||
"ERR ",
|
||
"DUID ERR ",
|
||
"R-S ERR ",
|
||
"CRC ERR ",
|
||
"NULL ",
|
||
"VOICE",
|
||
" ",
|
||
"INIT ",
|
||
"INIT ",
|
||
"PTT", //20 MAC
|
||
"VOICE", //21 MAC_ACTIVE
|
||
"HANGTIME", //22 MAC
|
||
"PTT END", //23 MAC
|
||
"IDLE", //24 MAC
|
||
"HDU",
|
||
"VOICE", //26 LDU1
|
||
"VOICE", //27 LDU2
|
||
"TDU/LC",
|
||
"TSBK",
|
||
"SIGNAL", //MAC_SIGNAL
|
||
"SIGNAL" //MAC_SIGNAL
|
||
|
||
};
|
||
|
||
//Sorry Remus :(
|
||
void beeper (dsd_opts * opts, dsd_state * state, int lr)
|
||
{
|
||
UNUSED(state);
|
||
int i, j, n;
|
||
//use lr as left or right channel designation in stereo config
|
||
float samp_f[160]; //mono float sample
|
||
float samp_fs[320]; //stereo float sample
|
||
short samp_s[160]; //mono short sample
|
||
short samp_ss[320]; //stereo short sample
|
||
short samp_su[960]; //mono short upsample
|
||
short outbuf[6]; //temp storage for upsample
|
||
|
||
n = 0; //rolling sine wave 'degree'
|
||
|
||
//each j increment is 20 ms at 160 samples / 8 kHz
|
||
for (j = 0; j < 3; j++)
|
||
{
|
||
//'zero' out stereo mix samples
|
||
memset (samp_fs, 0.1f, sizeof(samp_fs));
|
||
memset (samp_ss, 0, sizeof(samp_ss));
|
||
|
||
//generate a tone (ID=45, AD=103, rolling n value)
|
||
soft_tonef(samp_f, n, 45, 103);
|
||
|
||
//convert float to short if required
|
||
if (opts->floating_point == 0)
|
||
{
|
||
mbe_floattoshort(samp_f, samp_s);
|
||
for (i = 0; i < 160; i++)
|
||
{
|
||
samp_s[i] *= 4000; //apply gain
|
||
samp_ss[(i*2)+lr] = samp_s[i];
|
||
}
|
||
}
|
||
|
||
//load returned tone sample into appropriate channel -- left = +0; right = +1;
|
||
for (i = 0; i < 160; i++)
|
||
samp_fs[(i*2)+lr] = samp_f[i];
|
||
|
||
//play sample 3 times (20ms x 3 = 60ms)
|
||
if (opts->audio_out_type == 0) //Pulse Audio
|
||
{
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1)
|
||
pa_simple_write(opts->pulse_digi_dev_out, samp_fs, 320*4, NULL);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1)
|
||
pa_simple_write(opts->pulse_digi_dev_out, samp_f, 160*4, NULL);
|
||
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0)
|
||
pa_simple_write(opts->pulse_digi_dev_out, samp_ss, 320*2, NULL);
|
||
|
||
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
|
||
{
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1)
|
||
udp_socket_blaster (opts, state, 320*4, samp_fs);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1)
|
||
udp_socket_blaster (opts, state, 160*4, samp_f);
|
||
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0)
|
||
udp_socket_blaster (opts, state, 320*2, samp_ss);
|
||
|
||
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
|
||
{
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1)
|
||
write(opts->audio_out_fd, samp_fs, 320*4);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1)
|
||
write(opts->audio_out_fd, samp_f, 160*4);
|
||
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0)
|
||
write(opts->audio_out_fd, samp_ss, 320*2);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0)
|
||
write(opts->audio_out_fd, samp_s, 160*2);
|
||
}
|
||
|
||
else if (opts->audio_out_type == 2) //OSS Variable Output (no float)
|
||
{
|
||
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0)
|
||
write(opts->audio_out_fd, samp_ss, 320*2);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0)
|
||
write(opts->audio_out_fd, samp_s, 160*2);
|
||
}
|
||
|
||
else if (opts->audio_out_type == 5) //OSS 48k/1 configuration with upsample
|
||
{
|
||
short prev = 0;
|
||
for (i = 0; i < 160; i++)
|
||
{
|
||
upsampleS (samp_s[i], prev, outbuf);
|
||
samp_su[(i*6)+0] = outbuf[0];
|
||
samp_su[(i*6)+1] = outbuf[1];
|
||
samp_su[(i*6)+2] = outbuf[2];
|
||
samp_su[(i*6)+3] = outbuf[3];
|
||
samp_su[(i*6)+4] = outbuf[4];
|
||
samp_su[(i*6)+5] = outbuf[5];
|
||
}
|
||
|
||
write (opts->audio_out_fd, samp_su, 960*2);
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
char * getDateN(void) {
|
||
#ifdef AERO_BUILD
|
||
char datename[80];
|
||
#else
|
||
char datename[99];
|
||
#endif
|
||
char * curr2;
|
||
struct tm * to;
|
||
time_t t;
|
||
t = time(NULL);
|
||
to = localtime( & t);
|
||
strftime(datename, sizeof(datename), "%Y%m%d", to);
|
||
curr2 = strtok(datename, " ");
|
||
return curr2;
|
||
}
|
||
|
||
time_t nowN;
|
||
|
||
//fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b
|
||
char * getTimeN(void) //get pretty hhmmss timestamp
|
||
{
|
||
char * curr = (char *) malloc(9);
|
||
time_t t = time(NULL);
|
||
struct tm * ptm = localtime(& t);
|
||
sprintf(
|
||
curr,
|
||
"%02d%02d%02d",
|
||
ptm->tm_hour,
|
||
ptm->tm_min,
|
||
ptm->tm_sec
|
||
);
|
||
return curr;
|
||
}
|
||
|
||
//this version is broken now in Cygwin with the 80 value, reverted back
|
||
char * getDateC(time_t t) {
|
||
char datename[99];
|
||
char * curr2;
|
||
struct tm * to;
|
||
|
||
to = localtime( & t);
|
||
strftime(datename, sizeof(datename), "%Y-%m-%d", to);
|
||
curr2 = strtok(datename, " ");
|
||
return curr2;
|
||
}
|
||
|
||
char * getTimeC(time_t t) //get pretty hh:mm:ss timestamp
|
||
{
|
||
char * curr;
|
||
char * stamp = asctime(localtime( & t));
|
||
|
||
curr = strtok(stamp, " ");
|
||
curr = strtok(NULL, " ");
|
||
curr = strtok(NULL, " ");
|
||
curr = strtok(NULL, " ");
|
||
|
||
return curr;
|
||
}
|
||
|
||
//testing a few things, going to put this into ncursesMenu
|
||
#define WIDTH 36
|
||
#define HEIGHT 25
|
||
|
||
int startx = 0;
|
||
int starty = 0;
|
||
|
||
char *choicesc[] = {
|
||
"Return",
|
||
"Save Decoded Audio WAV (Legacy Mode)",
|
||
"Save Signal to Symbol Capture Bin",
|
||
"Toggle Muting Encrypted Traffic ",
|
||
"Save Per Call Decoded WAV",
|
||
"Setup and Start RTL Input ",
|
||
"Retune RTL Dongle ",
|
||
"Toggle C4FM/QPSK (P2 TDMA CC)",
|
||
"Toggle C4FM/QPSK (P1 FDMA CC)",
|
||
"Start TCP Direct Link Audio",
|
||
"Configure RIGCTL",
|
||
"Stop All Decoded WAV Saving",
|
||
"Read OP25/FME Symbol Capture Bin",
|
||
"Replay Last Symbol Capture Bin",
|
||
"Stop & Close Symbol Capture Bin Playback",
|
||
"Stop & Close Symbol Capture Bin Saving",
|
||
"Toggle Call Alert Beep ",
|
||
"Resume Decoding"
|
||
};
|
||
//make tweaks for TDMA and AUTO?
|
||
char *choices[] = {
|
||
"Resume Decoding",
|
||
"Decode AUTO",
|
||
"Decode TDMA",
|
||
"Decode DSTAR",
|
||
"Decode M17",
|
||
"Decode EDACS/PV",
|
||
"Decode P25p2",
|
||
"Decode dPMR",
|
||
"Decode NXDN48",
|
||
"Decode NXDN96",
|
||
"Decode DMR",
|
||
"Decode YSF",
|
||
"Toggle Signal Inversion",
|
||
"Key Entry",
|
||
"Reset Call History",
|
||
"Toggle Payloads to Console",
|
||
"Manually Set p2 Parameters", //16
|
||
"Input & Output Options",
|
||
"LRRP Data to File",
|
||
"Exit DSD-FME",
|
||
};
|
||
|
||
|
||
int n_choices = sizeof(choices) / sizeof(char *);
|
||
// int n_choicesb = sizeof(choicesb) / sizeof(char *);
|
||
int n_choicesc = sizeof(choicesc) / sizeof(char *);
|
||
|
||
void print_menu(WINDOW *menu_win, int highlight)
|
||
{
|
||
int x, y, i;
|
||
|
||
x = 2;
|
||
y = 2;
|
||
box(menu_win, 0, 0);
|
||
for(i = 0; i < n_choices; ++i)
|
||
{ if(highlight == i + 1) /* High light the present choice */
|
||
{ wattron(menu_win, A_REVERSE);
|
||
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||
wattroff(menu_win, A_REVERSE);
|
||
}
|
||
else
|
||
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||
++y;
|
||
}
|
||
wrefresh(menu_win);
|
||
}
|
||
|
||
void print_menuc(WINDOW *menu_win, int highlight)
|
||
{
|
||
int x, y, i;
|
||
|
||
x = 2;
|
||
y = 2;
|
||
box(menu_win, 0, 0);
|
||
for(i = 0; i < n_choicesc; ++i)
|
||
{ if(highlight == i + 1) /* High light the present choice */
|
||
{ wattron(menu_win, A_REVERSE);
|
||
mvwprintw(menu_win, y, x, "%s", choicesc[i]);
|
||
wattroff(menu_win, A_REVERSE);
|
||
}
|
||
else
|
||
mvwprintw(menu_win, y, x, "%s", choicesc[i]);
|
||
++y;
|
||
}
|
||
wrefresh(menu_win);
|
||
}
|
||
|
||
//end Testing
|
||
|
||
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", "");
|
||
|
||
UNUSED(opts); UNUSED(state);
|
||
|
||
// state->menuopen = 1; //flag the menu is open, stop processing getFrameSync
|
||
mbe_printVersion (versionstr);
|
||
setlocale(LC_ALL, "");
|
||
initscr(); //Initialize NCURSES screen window
|
||
start_color();
|
||
|
||
#ifdef PRETTY_COLORS
|
||
init_pair(1, COLOR_YELLOW, COLOR_BLACK); //Yellow/Amber for frame sync/control channel, NV style
|
||
init_pair(2, COLOR_RED, COLOR_BLACK); //Red for Terminated Calls
|
||
init_pair(3, COLOR_GREEN, COLOR_BLACK); //Green for Active Calls
|
||
init_pair(4, COLOR_CYAN, COLOR_BLACK); //Cyan for Site Extra and Patches
|
||
init_pair(5, COLOR_MAGENTA, COLOR_BLACK); //Magenta for no frame sync/signal
|
||
init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
#else
|
||
init_pair(1, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(2, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(3, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(4, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(5, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
#endif
|
||
|
||
noecho();
|
||
cbreak();
|
||
|
||
}
|
||
|
||
//ncursesMenu
|
||
void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||
{
|
||
|
||
//update sync time on cc sync so we don't immediately go CC hunting when exiting the menu
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
//close pulse output if not null output
|
||
if (opts->audio_out == 1 && opts->audio_out_type == 0)
|
||
{
|
||
closePulseOutput (opts);
|
||
}
|
||
|
||
//close OSS output
|
||
if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
|
||
{
|
||
close (opts->audio_out_fd);
|
||
}
|
||
|
||
if (opts->audio_in_type == 0) //close pulse input if it is the specified input method
|
||
{
|
||
closePulseInput(opts);
|
||
}
|
||
|
||
if (opts->audio_in_type == 3)
|
||
{
|
||
#ifdef USE_RTLSDR
|
||
rtl_clean_queue();
|
||
#endif
|
||
}
|
||
|
||
if (opts->audio_in_type == 8) //close TCP input SF file so we don't buffer audio while not decoding
|
||
{
|
||
sf_close(opts->tcp_file_in);
|
||
}
|
||
|
||
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
|
||
//zero out to fix call history 'scrolling' bug when changing decoding types
|
||
state->nxdn_last_tg = 0;
|
||
state->nxdn_last_ran = -1; //0
|
||
state->nxdn_last_rid = 0; //0
|
||
|
||
WINDOW *menu_win;
|
||
WINDOW *test_win;
|
||
WINDOW *entry_win;
|
||
WINDOW *info_win;
|
||
int highlight = 1;
|
||
int highlightc = 1;
|
||
int choice = 0;
|
||
int choicec = 0;
|
||
int c;
|
||
int e;
|
||
|
||
startx = 2;
|
||
starty = 1;
|
||
|
||
menu_win = newwin(HEIGHT, WIDTH, starty, startx);
|
||
keypad(menu_win, TRUE);
|
||
mvprintw(0, 0, " Use arrow keys to go up and down, Press ENTER to select a choice.");
|
||
refresh();
|
||
print_menu(menu_win, highlight);
|
||
while(1)
|
||
{ c = wgetch(menu_win);
|
||
switch(c)
|
||
{ case KEY_UP:
|
||
if(highlight == 1)
|
||
highlight = n_choices;
|
||
else
|
||
--highlight;
|
||
break;
|
||
case KEY_DOWN:
|
||
if(highlight == n_choices)
|
||
highlight = 1;
|
||
else
|
||
++highlight;
|
||
break;
|
||
case 10:
|
||
choice = highlight;
|
||
break;
|
||
default:
|
||
//mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c);
|
||
refresh();
|
||
break;
|
||
}
|
||
|
||
print_menu(menu_win, highlight);
|
||
|
||
|
||
if (highlight == 2)
|
||
{
|
||
info_win = newwin(7, WIDTH+18, starty, startx+20);
|
||
box (info_win, 0, 0);
|
||
mvwprintw(info_win, 2, 2, " AUTO Decoding Class Supports the following:");
|
||
mvwprintw(info_win, 3, 2, " P25p1, YSF, DSTAR, X2-TDMA and DMR");
|
||
mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 4800bps (no H8D-QPSK)");
|
||
wrefresh(info_win);
|
||
}
|
||
|
||
if (highlight == 3)
|
||
{
|
||
info_win = newwin(7, WIDTH+18, starty, startx+20);
|
||
box (info_win, 0, 0);
|
||
mvwprintw(info_win, 2, 2, " TDMA Trunking Class Supports the following:");
|
||
mvwprintw(info_win, 3, 2, " P25p1 Voice/Control, P25p2 Traffic, and DMR");
|
||
mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 4800 or 6000 (no H8D-QPSK)");
|
||
wrefresh(info_win);
|
||
}
|
||
|
||
if (highlight == 7)
|
||
{
|
||
info_win = newwin(7, WIDTH+18, starty, startx+20);
|
||
box (info_win, 0, 0);
|
||
mvwprintw(info_win, 2, 2, " P25p2 Control (MAC_SIGNAL) or Single Voice Freq.");
|
||
mvwprintw(info_win, 3, 2, " NOTE: Manually set WACN/SYSID/CC on Voice Only");
|
||
mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 6000 (no H8D-QPSK)");
|
||
wrefresh(info_win);
|
||
}
|
||
|
||
//Input Output Options
|
||
if (choice == 18)
|
||
{
|
||
//test making a new window while other window is open
|
||
test_win = newwin(HEIGHT-1, WIDTH+9, starty+5, startx+5);
|
||
keypad(menu_win, FALSE);
|
||
keypad(test_win, TRUE);
|
||
mvprintw(0, 0, "Input & Output Options ");
|
||
refresh();
|
||
print_menuc(test_win, highlightc);
|
||
while(1)
|
||
{ e = wgetch(test_win);
|
||
switch(e)
|
||
{ case KEY_UP:
|
||
if(highlightc == 1)
|
||
highlightc = n_choicesc;
|
||
else
|
||
--highlightc;
|
||
break;
|
||
case KEY_DOWN:
|
||
if(highlightc == n_choicesc)
|
||
highlightc = 1;
|
||
else
|
||
++highlightc;
|
||
break;
|
||
case 10:
|
||
choicec = highlightc;
|
||
break;
|
||
default:
|
||
//mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c);
|
||
refresh();
|
||
break;
|
||
}
|
||
print_menuc(test_win, highlightc);
|
||
if (choicec == 2)
|
||
{
|
||
sprintf (opts->wav_out_file, "%s %s DSD-FME-DECODED.wav", getDateN(), timestr);
|
||
openWavOutFile (opts, state);
|
||
}
|
||
if (choicec == 3)
|
||
{
|
||
//read in filename for symbol capture bin
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter FME Symbol Capture Bin Filename");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->symbol_out_file); //&opts->symbol_out_file
|
||
noecho();
|
||
|
||
openSymbolOutFile (opts, state);
|
||
}
|
||
if (choicec == 4)
|
||
{
|
||
//toggle all mutes
|
||
if (opts->unmute_encrypted_p25 == 0)
|
||
{
|
||
opts->unmute_encrypted_p25 = 1;
|
||
}
|
||
else opts->unmute_encrypted_p25 = 0;
|
||
|
||
if (opts->dmr_mute_encL == 0)
|
||
{
|
||
opts->dmr_mute_encL = 1;
|
||
}
|
||
else opts->dmr_mute_encL = 0;
|
||
|
||
if (opts->dmr_mute_encR == 0)
|
||
{
|
||
opts->dmr_mute_encR = 1;
|
||
}
|
||
else opts->dmr_mute_encR = 0;
|
||
|
||
}
|
||
if (choicec == 5)
|
||
{
|
||
char wav_file_directory[1024];
|
||
sprintf (wav_file_directory, "%s", opts->wav_out_dir);
|
||
wav_file_directory[1023] = '\0';
|
||
if (stat(wav_file_directory, &st_wav) == -1)
|
||
{
|
||
fprintf (stderr, "%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);
|
||
}
|
||
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-X1.wav", opts->wav_out_dir); //
|
||
sprintf (opts->wav_out_fileR, "./%s/DSD-FME-X2.wav", opts->wav_out_dir); //
|
||
openWavOutFileL (opts, state);
|
||
openWavOutFileR (opts, state);
|
||
|
||
}
|
||
|
||
if (choicec == 6)
|
||
{
|
||
int confirm = 0;
|
||
|
||
#ifdef USE_RTLSDR
|
||
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL Device Index or Serial Number:");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_dev_index);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL Device PPM Error:");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtlsdr_ppm_error);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Frequency in Hz (851.8 MHz is 851800000 Hz): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtlsdr_center_freq);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " BW (8, 12, 24, 48)(12 Recommended): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_bandwidth);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL Gain Value (0-49) (0 = AGC): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_gain_value);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL UDP Port - Legacy/Optional (Default = 0): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_udp_port);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL Vol Multiplier (1,2,3) (Default = 1): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_volume_multiplier);
|
||
if (opts->rtl_volume_multiplier > 3 || opts->rtl_volume_multiplier < 0)
|
||
opts->rtl_volume_multiplier = 1;
|
||
noecho();
|
||
|
||
entry_win = newwin(8, WIDTH+22, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL RMS Squelch Level (NXDN/dPMR/Analog/Raw only): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_squelch_level);
|
||
noecho();
|
||
|
||
//use to list out all detected RTL dongles
|
||
device_count = rtlsdr_get_device_count();
|
||
if (!device_count)
|
||
{
|
||
fprintf(stderr, "No supported devices found.\n");
|
||
}
|
||
else fprintf(stderr, "Found %d device(s):\n", device_count);
|
||
for (int i = 0; i < device_count; i++)
|
||
{
|
||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||
fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial);
|
||
|
||
sprintf (userdev, "%08d", opts->rtl_dev_index);
|
||
|
||
//check by index first, then by serial
|
||
if (opts->rtl_dev_index == i)
|
||
{
|
||
fprintf (stderr, "Selected Device #%d with Serial Number: %s \n", i, serial);
|
||
break;
|
||
}
|
||
else if (strcmp (userdev, serial) == 0)
|
||
{
|
||
fprintf (stderr, "Selected Device #%d with Serial Number: %s \n", i, serial);
|
||
opts->rtl_dev_index = i;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
entry_win = newwin(18, WIDTH+20, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Starting RTL Input. Cannot Release/Stop Until Exit.");
|
||
mvwprintw(entry_win, 4, 2, " RTL Frequency: %d Hz", opts->rtlsdr_center_freq);
|
||
mvwprintw(entry_win, 5, 2, " RTL Device Index Number: %d; SN:%s", opts->rtl_dev_index, serial);
|
||
mvwprintw(entry_win, 6, 2, " RTL Device Bandwidth: %d kHz", opts->rtl_bandwidth);
|
||
mvwprintw(entry_win, 7, 2, " RTL Device Gain: %d", opts->rtl_gain_value);
|
||
mvwprintw(entry_win, 8, 2, " RTL Volume Multiplier: %d", opts->rtl_volume_multiplier);
|
||
mvwprintw(entry_win, 9, 2, " RTL Device UDP Port: %d", opts->rtl_udp_port);
|
||
mvwprintw(entry_win, 10, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error);
|
||
mvwprintw(entry_win, 11, 2, " RTL RMS Squelch: %d", opts->rtl_squelch_level);
|
||
mvwprintw(entry_win, 13, 2, " Are You Sure?");
|
||
mvwprintw(entry_win, 14, 2, " 1 = Yes, 2 = No ");
|
||
mvwprintw(entry_win, 15, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &confirm);
|
||
noecho();
|
||
|
||
refresh();
|
||
|
||
//works well, but can't release dongle later, so its a one way trip until exit
|
||
//TODO: Write function to release the dongle -- call cleanup_rtlsdr_stream()
|
||
if (confirm == 1)
|
||
{
|
||
opts->audio_in_type = 3; //RTL input, only set this on confirm
|
||
choicec = 18; //exit to decoder screen only if confirmed, otherwise, just go back
|
||
}
|
||
|
||
#else
|
||
UNUSED(confirm);
|
||
|
||
#endif
|
||
|
||
}
|
||
|
||
if (choicec == 7) //RTL DEV Retune
|
||
{
|
||
//read in new rtl frequency
|
||
#ifdef USE_RTLSDR
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter Frequency in Hz (851.8 MHz is 851800000 Hz) ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtlsdr_center_freq);
|
||
noecho();
|
||
|
||
temp_freq = opts->rtlsdr_center_freq;
|
||
#endif
|
||
choicec = 18;
|
||
}
|
||
|
||
if (choicec == 8)
|
||
{
|
||
if (state->rf_mod == 0)
|
||
{
|
||
state->rf_mod = 1;
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 1;
|
||
}
|
||
else
|
||
{
|
||
state->rf_mod = 0;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
}
|
||
}
|
||
|
||
if (choicec == 9)
|
||
{
|
||
if (state->rf_mod == 0)
|
||
{
|
||
state->rf_mod = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 1;
|
||
}
|
||
else
|
||
{
|
||
state->rf_mod = 0;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
}
|
||
}
|
||
|
||
// if (choicec == 9)
|
||
// {
|
||
// if (opts->audio_out == 0)
|
||
// {
|
||
// opts->audio_out = 1;
|
||
// opts->audio_out_type = 0;
|
||
// // state->audio_out_buf_p = 0;
|
||
// // state->audio_out_buf_pR = 0;
|
||
// state->audio_out_idx = 0;
|
||
// state->audio_out_idx2 = 0;
|
||
// state->audio_out_idxR = 0;
|
||
// state->audio_out_idx2R = 0;
|
||
// }
|
||
// else
|
||
// {
|
||
// opts->audio_out = 0;
|
||
// opts->audio_out_type = 9;
|
||
// // state->audio_out_buf_p = 0;
|
||
// // state->audio_out_buf_pR = 0;
|
||
// state->audio_out_idx = 0;
|
||
// state->audio_out_idx2 = 0;
|
||
// state->audio_out_idxR = 0;
|
||
// state->audio_out_idx2R = 0;
|
||
// }
|
||
// }
|
||
|
||
//TCP Audio Input
|
||
if (choicec == 10)
|
||
{
|
||
//read in tcp hostname
|
||
sprintf (opts->tcp_hostname, "%s", "localhost");
|
||
opts->tcp_portno = 7355;
|
||
|
||
entry_win = newwin(8, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter TCP Direct Link Hostname:");
|
||
mvwprintw(entry_win, 3, 2, " (default is localhost)");
|
||
mvwprintw(entry_win, 4, 2, " ");
|
||
mvwprintw(entry_win, 5, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->tcp_hostname);
|
||
noecho();
|
||
|
||
//read in tcp port number
|
||
entry_win = newwin(8, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter TCP Direct Link Port Number:");
|
||
mvwprintw(entry_win, 3, 2, " (default is 7355)");
|
||
mvwprintw(entry_win, 4, 2, " ");
|
||
mvwprintw(entry_win, 5, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->tcp_portno);
|
||
noecho();
|
||
|
||
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
|
||
if (opts->tcp_sockfd == 0) goto TCP_END;
|
||
//successful connection, continue;
|
||
|
||
opts->audio_in_type = 8;
|
||
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
|
||
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
|
||
opts->audio_in_file_info->channels=1;
|
||
opts->audio_in_file_info->seekable=0;
|
||
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||
|
||
if(opts->tcp_file_in == NULL)
|
||
{
|
||
fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||
if (opts->audio_out_type == 0)
|
||
{
|
||
sprintf (opts->audio_in_dev, "%s", "pulse");
|
||
opts->audio_in_type = 0;
|
||
}
|
||
else opts->audio_in_type = 5;
|
||
|
||
}
|
||
|
||
|
||
|
||
TCP_END: ; //do nothing
|
||
|
||
}
|
||
|
||
//RIGCTL
|
||
if (choicec == 11)
|
||
{
|
||
//read in tcp hostname
|
||
sprintf (opts->rigctlhostname, "%s", "localhost");
|
||
opts->rigctlportno = 4532;
|
||
|
||
entry_win = newwin(8, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter RIGCTL Hostname:");
|
||
mvwprintw(entry_win, 3, 2, " (default is localhost)");
|
||
mvwprintw(entry_win, 4, 2, " ");
|
||
mvwprintw(entry_win, 5, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->rigctlhostname);
|
||
noecho();
|
||
|
||
//read in tcp port number
|
||
entry_win = newwin(8, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter RIGCTL Port Number:");
|
||
mvwprintw(entry_win, 3, 2, " (default is 4532)");
|
||
mvwprintw(entry_win, 4, 2, " ");
|
||
mvwprintw(entry_win, 5, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rigctlportno);
|
||
noecho();
|
||
|
||
opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno);
|
||
if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1;
|
||
else opts->use_rigctl = 0;
|
||
}
|
||
|
||
// if (choicec == 10)
|
||
// {
|
||
// if (opts->ncurses_compact == 0)
|
||
// {
|
||
// opts->ncurses_compact = 1;
|
||
// }
|
||
// else opts->ncurses_compact = 0;
|
||
|
||
// }
|
||
|
||
// if (choicec == 11)
|
||
// {
|
||
// if (opts->ncurses_history == 0)
|
||
// {
|
||
// opts->ncurses_history = 1;
|
||
// }
|
||
// else opts->ncurses_history = 0;
|
||
// }
|
||
|
||
if (choicec == 12)
|
||
{
|
||
//flesh out all closewavs and sprint "" wav filenames
|
||
closeWavOutFile (opts, state);
|
||
closeWavOutFileL (opts, state);
|
||
closeWavOutFileR (opts, state);
|
||
//closeWavOutFileRaw (opts, state);
|
||
sprintf (opts->wav_out_file, "%s", "");
|
||
sprintf (opts->wav_out_fileR, "%s", "");
|
||
opts->dmr_stereo_wav = 0;
|
||
}
|
||
|
||
if (choicec == 13) //lucky number 13 for OP25 Symbol Capture Bin Files
|
||
{
|
||
//read in filename for symbol capture bin
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter OP25 Symbol Capture Bin Filename");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->audio_in_dev); //&opts->audio_in_dev
|
||
noecho();
|
||
//do the thing with the thing
|
||
struct stat stat_buf;
|
||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||
{
|
||
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||
goto SKIP;
|
||
}
|
||
if (S_ISREG(stat_buf.st_mode))
|
||
{
|
||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||
opts->audio_in_type = 4; //symbol capture bin files
|
||
}
|
||
SKIP:
|
||
choicec = 18;
|
||
}
|
||
|
||
if (choicec == 14) //replay last file
|
||
{
|
||
struct stat stat_buf;
|
||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||
{
|
||
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||
goto SKIPR;
|
||
}
|
||
if (S_ISREG(stat_buf.st_mode))
|
||
{
|
||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||
opts->audio_in_type = 4; //symbol capture bin files
|
||
}
|
||
SKIPR:
|
||
choicec = 18; //exit
|
||
}
|
||
|
||
if (choicec == 15) //stop/close last file PLAYBACK
|
||
{
|
||
if (opts->symbolfile != NULL)
|
||
{
|
||
if (opts->audio_in_type == 4) //check first, or issuing a second fclose will crash the SOFTWARE
|
||
{
|
||
fclose(opts->symbolfile); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once
|
||
|
||
}
|
||
|
||
}
|
||
if (opts->audio_out_type == 0) opts->audio_in_type = 0; //set after closing to prevent above crash condition
|
||
else (opts->audio_in_type = 5);
|
||
|
||
choicec = 18; //exit
|
||
}
|
||
|
||
if (choicec == 16) //stop/close last file RECORDING
|
||
{
|
||
if (opts->symbol_out_f)
|
||
{
|
||
closeSymbolOutFile (opts, state);
|
||
sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file); //swap output bin filename to input for quick replay
|
||
}
|
||
choicec = 18; //exit
|
||
}
|
||
|
||
//toggle call alert beep
|
||
if (choicec == 17)
|
||
{
|
||
if (opts->call_alert == 0)
|
||
{
|
||
opts->call_alert = 1;
|
||
}
|
||
else opts->call_alert = 0;
|
||
}
|
||
|
||
if (choicec != 0 && choicec != 18 ) //return to last menu
|
||
{
|
||
//return
|
||
choice = 0;
|
||
choicec = 0;
|
||
|
||
keypad(test_win, FALSE);
|
||
keypad(menu_win, TRUE);
|
||
delwin(test_win);
|
||
print_menu(menu_win, highlight);
|
||
//wrefresh(menu_win);
|
||
break;
|
||
}
|
||
|
||
if (choicec == 18) //exit both menus
|
||
{
|
||
//exit
|
||
choice = 1;
|
||
choicec = 0;
|
||
|
||
keypad(test_win, FALSE);
|
||
keypad(menu_win, TRUE);
|
||
delwin(test_win);
|
||
print_menu(menu_win, highlight);
|
||
break;
|
||
}
|
||
}
|
||
clrtoeol(); //clear to end of line?
|
||
refresh();
|
||
}
|
||
|
||
//Privacy Key Entry
|
||
if (choice == 14)
|
||
{
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
short int option = 0;
|
||
entry_win = newwin(14, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, "Key Type Selection");
|
||
mvwprintw(entry_win, 3, 2, " ");
|
||
mvwprintw(entry_win, 4, 2, "1 - Basic Privacy ");
|
||
mvwprintw(entry_win, 5, 2, "2 - **tera Privacy ");
|
||
mvwprintw(entry_win, 6, 2, "3 - NXDN/dPMR Scrambler ");
|
||
mvwprintw(entry_win, 7, 2, "4 - Force BP/Scr Key Priority ");
|
||
mvwprintw(entry_win, 8, 3, "-------------------------------- ");
|
||
mvwprintw(entry_win, 9, 2, "5 - RC4 Key ");
|
||
mvwprintw(entry_win, 10, 2, "6 - Force DMR RC4 Priority/LE ");
|
||
mvwprintw(entry_win, 11, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%hd", &option); //%d
|
||
noecho();
|
||
opts->dmr_mute_encL = 0;
|
||
opts->dmr_mute_encR = 0;
|
||
if (option == 1)
|
||
{
|
||
state->K = 0;
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, "Basic Privacy Key Number (DEC):");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%lld", &state->K);
|
||
noecho();
|
||
if (state->K > 255) state->K = 255;
|
||
|
||
state->keyloader = 0; //turn off keyloader
|
||
}
|
||
if (option == 2)
|
||
{
|
||
state->K1 = 0;
|
||
state->K2 = 0;
|
||
state->K3 = 0;
|
||
state->K4 = 0;
|
||
state->H = 0;
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " 10 Char or First 16 for 32/64");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->H);
|
||
noecho();
|
||
state->K1 = state->H;
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 2 (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " Second 16 Chars or Zero");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->K2);
|
||
noecho();
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 3 (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " Third 16 Chars or Zero");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->K3);
|
||
noecho();
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 4 (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " Fourth 16 Chars or Zero");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->K4);
|
||
noecho();
|
||
|
||
state->keyloader = 0; //turn off keyloader
|
||
}
|
||
if (option == 3)
|
||
{
|
||
state->R = 0;
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, "NXDN/dPMR Scrambler Key Value (DEC):");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
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
|
||
if (option == 4)
|
||
{
|
||
if (state->M == 1 || state->M == 0x21)
|
||
{
|
||
state->M = 0;
|
||
}
|
||
else state->M = 1;
|
||
}
|
||
|
||
if (option == 5)
|
||
{
|
||
state->R = 0;
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, "RC4 Key Value (HEX):");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->R);
|
||
noecho();
|
||
if (state->R > 0xFFFFFFFFFF)
|
||
{
|
||
state->R = 0xFFFFFFFFFF;
|
||
}
|
||
state->RR = state->R; //assign for both slots
|
||
state->keyloader = 0; //turn off keyloader
|
||
}
|
||
|
||
//toggle enforcement of rc4 key over missing pi header/le on DMR
|
||
if (option == 6)
|
||
{
|
||
if (state->M == 1 || state->M == 0x21)
|
||
{
|
||
state->M = 0;
|
||
}
|
||
else state->M = 0x21;
|
||
}
|
||
|
||
if (state->K == 0 && state->K1 == 0 && state->K2 == 0 && state->K3 == 0 && state->K4 == 0)
|
||
{
|
||
opts->dmr_mute_encL = 1;
|
||
opts->dmr_mute_encR = 1;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
if (choice == 99) //UNUSED
|
||
{
|
||
//setup Auto parameters--default ones
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "Legacy Auto");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 1;
|
||
opts->frame_x2tdma = 1;
|
||
opts->frame_p25p1 = 1;
|
||
opts->frame_p25p2 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 1;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 1;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
|
||
}
|
||
if (choice == 6)
|
||
{
|
||
//ProVoice Specifics
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 5;
|
||
state->symbolCenter = 2;
|
||
sprintf (opts->output_name, "EDACS/PV");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_p25p2 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 1;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 1;
|
||
state->rf_mod = 2;
|
||
break;
|
||
}
|
||
if (choice == 4)
|
||
{
|
||
//DSTAR
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "DSTAR");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 1;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_p25p2 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
// state->rf_mod = 2;
|
||
opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
}
|
||
if (choice == 3) //was 5, changed to 3 and also made it the TDMA class
|
||
{
|
||
//TDMA -- was P25p1 only
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
// opts->use_heuristics = 1; //Causes issues with Voice Wide
|
||
if (opts->use_heuristics == 1)
|
||
{
|
||
initialize_p25_heuristics(&state->p25_heuristics);
|
||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||
}
|
||
opts->frame_p25p1 = 1;
|
||
opts->frame_p25p2 = 1;
|
||
opts->frame_dmr = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "TDMA");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 1; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 2;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
}
|
||
|
||
if (choice == 2)
|
||
{
|
||
//AUTO Stereo P25 1, 2, and DMR
|
||
// resetState (state); //use sparingly, seems to cause issue when switching back to other formats
|
||
if (opts->use_heuristics == 1)
|
||
{
|
||
initialize_p25_heuristics(&state->p25_heuristics);
|
||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||
}
|
||
// opts->use_heuristics = 0;
|
||
opts->frame_dmr = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "AUTO");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 1; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 2;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 1;
|
||
opts->frame_p25p2 = 1;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 1;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
break;
|
||
}
|
||
if (choice == 7)
|
||
{
|
||
// resetState (state); //use sparingly, seems to cause issue when switching back to other formats
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
sprintf (opts->output_name, "P25p2");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 1; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 2;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_p25p2 = 1;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
break;
|
||
}
|
||
if (choice == 8)
|
||
{
|
||
//dPMR
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 20;
|
||
state->symbolCenter = 10;
|
||
sprintf (opts->output_name, "dPMR");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 1;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
}
|
||
if (choice == 9)
|
||
{
|
||
//NXDN48
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
opts->frame_nxdn48 = 1;
|
||
state->samplesPerSymbol = 20;
|
||
state->symbolCenter = 10;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "NXDN48");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 1;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
// opts->mod_qpsk = 0;
|
||
// opts->mod_gfsk = 0;
|
||
// state->rf_mod = 0;
|
||
}
|
||
if (choice == 10)
|
||
{
|
||
//NXDN96
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "NXDN96");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 1;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
}
|
||
if (choice == 11)
|
||
{
|
||
//Decode DMR Stereo (was X2-TDMA)
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
// sprintf (opts->output_name, "X2-TDMA");
|
||
sprintf (opts->output_name, "DMR");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 1; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 2;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 1;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
}
|
||
if (choice == 12)
|
||
{
|
||
//Decode YSF Fusion
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "YSF");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 1;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
}
|
||
if (choice == 5) //was 3
|
||
{
|
||
//Decode M17
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "M17");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 1;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
}
|
||
if (choice == 13)
|
||
{
|
||
//Set all signal for inversion or uninversion
|
||
if (opts->inverted_dmr == 0)
|
||
{
|
||
opts->inverted_dmr = 1;
|
||
opts->inverted_dpmr = 1;
|
||
opts->inverted_x2tdma = 1;
|
||
opts->inverted_ysf = 1;
|
||
opts->inverted_m17 = 1;
|
||
}
|
||
else
|
||
{
|
||
opts->inverted_dmr = 0;
|
||
opts->inverted_dpmr = 0;
|
||
opts->inverted_x2tdma = 0;
|
||
opts->inverted_ysf = 0;
|
||
opts->inverted_m17 = 0;
|
||
}
|
||
|
||
}
|
||
if (choice == 15) //reset call history (usually if janky output when switching modes)
|
||
{
|
||
for (short int k = 0; k < 10; k++)
|
||
{
|
||
call_matrix[k][0] = 0;
|
||
call_matrix[k][1] = 0;
|
||
call_matrix[k][2] = 0;
|
||
call_matrix[k][3] = 0;
|
||
call_matrix[k][4] = 0;
|
||
call_matrix[k][5] = 0;
|
||
sprintf (alias_ch[k], "%s", "");
|
||
}
|
||
src = 0;
|
||
rn = 0;
|
||
tgn = 0;
|
||
dcc = -1;
|
||
tg = 0;
|
||
tgR = 0;
|
||
rd = 0;
|
||
rdR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->nxdn_last_ran = -1;
|
||
state->nxdn_last_rid = 0;
|
||
state->nxdn_last_tg = 0;
|
||
sprintf (state->str50a, "%s", "");
|
||
memset (state->str50b, 0, 50*sizeof(char));
|
||
}
|
||
|
||
if (choice == 16) //toggle payload printing
|
||
{
|
||
if (opts->payload == 0)
|
||
{
|
||
opts->payload = 1;
|
||
fprintf(stderr, "Payload on\n");
|
||
}
|
||
else
|
||
{
|
||
opts->payload = 0;
|
||
fprintf(stderr, "Payload Off\n");
|
||
}
|
||
}
|
||
if (choice == 17)
|
||
{
|
||
//hardset P2 WACN, SYSID, and NAC
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter Phase 2 WACN (HEX)");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->p2_wacn); //%X
|
||
if (state->p2_wacn > 0xFFFFF)
|
||
{
|
||
state->p2_wacn = 0xFFFFF;
|
||
}
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter Phase 2 SYSID (HEX)");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->p2_sysid); //%X
|
||
if (state->p2_sysid > 0xFFF)
|
||
{
|
||
state->p2_sysid = 0xFFF;
|
||
}
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter Phase 2 NAC/CC (HEX)");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->p2_cc); //%X
|
||
if (state->p2_cc > 0xFFF)
|
||
{
|
||
state->p2_cc = 0xFFF;
|
||
}
|
||
noecho();
|
||
|
||
//need handling to truncate larger than expected values
|
||
|
||
//set our hardset flag to 1 if values inserted, else set to 0 so we can attempt to get them from TSBK/LCCH
|
||
if (state->p2_wacn != 0 && state->p2_sysid != 0 && state->p2_cc != 0)
|
||
{
|
||
state->p2_hardset = 1;
|
||
}
|
||
else state->p2_hardset = 0;
|
||
|
||
|
||
}
|
||
if (choice == 19)
|
||
{
|
||
short int lrrpchoice = 0;
|
||
entry_win = newwin(10, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enable or Disable LRRP Data File");
|
||
mvwprintw(entry_win, 3, 2, " 1 - ~/lrrp.txt (QGis)");
|
||
mvwprintw(entry_win, 4, 2, " 2 - ./DSDPlus.LRRP (LRRP.exe)");
|
||
mvwprintw(entry_win, 5, 2, " 3 - ./Custom Filename");
|
||
mvwprintw(entry_win, 6, 2, " 4 - Cancel/Stop");
|
||
mvwprintw(entry_win, 7, 2, " ");
|
||
mvwprintw(entry_win, 8, 2, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%hd", &lrrpchoice); //%d
|
||
noecho();
|
||
|
||
if (lrrpchoice == 1)
|
||
{
|
||
//find user home directory and append directory and filename.
|
||
char * filename = "/lrrp.txt";
|
||
char * home_dir = getenv("HOME");
|
||
char * filepath = malloc(strlen(home_dir) + strlen(filename) + 1);
|
||
strncpy (filepath, home_dir, strlen(home_dir) + 1);
|
||
strncat (filepath, filename, strlen(filename) + 1);
|
||
//assign home directory/filename to lrrp_out_file
|
||
sprintf (opts->lrrp_out_file, "%s", filepath); //double check make sure this still works
|
||
opts->lrrp_file_output = 1;
|
||
}
|
||
|
||
else if (lrrpchoice == 2)
|
||
{
|
||
sprintf (opts->lrrp_out_file, "DSDPlus.LRRP");
|
||
opts->lrrp_file_output = 1;
|
||
}
|
||
|
||
else if (lrrpchoice == 3)
|
||
{
|
||
//read in filename for symbol capture bin
|
||
opts->lrrp_out_file[0] = 0;
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter LRRP Data Filename");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->lrrp_out_file); //&opts->lrrp_out_file
|
||
noecho();
|
||
if (opts->lrrp_out_file[0] != 0) //NULL
|
||
{
|
||
opts->lrrp_file_output = 1;
|
||
}
|
||
else
|
||
{
|
||
opts->lrrp_file_output = 0;
|
||
sprintf (opts->lrrp_out_file, "%s", "");
|
||
opts->lrrp_out_file[0] = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
opts->lrrp_file_output = 0;
|
||
sprintf (opts->lrrp_out_file, "%s", "");
|
||
opts->lrrp_out_file[0] = 0;
|
||
}
|
||
}
|
||
if (choice == 20)
|
||
{
|
||
exitflag = 1;
|
||
break;
|
||
}
|
||
|
||
if(choice != 0 && choice != 20) /* User did a choice come out of the infinite loop */
|
||
break;
|
||
|
||
}
|
||
|
||
clrtoeol(); //clear to end of line?
|
||
refresh();
|
||
state->menuopen = 0; //flag the menu is closed, resume processing getFrameSync
|
||
|
||
//reopen pulse output with new parameters, if not null output type
|
||
if (opts->audio_out == 1 && opts->audio_out_type == 0)
|
||
{
|
||
openPulseOutput (opts);
|
||
}
|
||
|
||
if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
|
||
{
|
||
openOSSOutput (opts);
|
||
}
|
||
|
||
|
||
if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method
|
||
{
|
||
openPulseInput(opts);
|
||
}
|
||
//fix location of this statement to inside the if statement and add conditions
|
||
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
|
||
if (opts->rtl_started == 0)
|
||
{
|
||
opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again
|
||
open_rtlsdr_stream(opts);
|
||
}
|
||
rtl_clean_queue();
|
||
reset_dibit_buffer(state); //test and observe for any random issues, disable if needed
|
||
#elif AERO_BUILD
|
||
opts->audio_out_type = 5; //hopefully the audio stream is still/already open //shouldn't this be 5? Was set to 3
|
||
#else
|
||
opts->audio_out_type = 0; //need to see if we need to open pulseoutput as well here?
|
||
openPulseOutput (opts);
|
||
#endif
|
||
}
|
||
|
||
if (opts->audio_in_type == 8) //re-open TCP input 'file'
|
||
{
|
||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||
}
|
||
|
||
|
||
//update sync time on cc sync so we don't immediately go CC hunting when exiting the menu
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
}
|
||
//end Ncurses Menu
|
||
|
||
void
|
||
ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||
{
|
||
uint8_t idas = 0;
|
||
int level = 0;
|
||
int c = 0;
|
||
timestr = getTimeN();
|
||
|
||
if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN -
|
||
{
|
||
timeout(0); //
|
||
c = getch(); //
|
||
}
|
||
|
||
//use rtl_dev_tune
|
||
#ifdef USE_RTLSDR
|
||
if (temp_freq == opts->rtlsdr_center_freq)
|
||
{
|
||
rtl_dev_tune (opts, temp_freq);
|
||
temp_freq = -1;
|
||
}
|
||
#endif
|
||
|
||
//Variable reset/set section
|
||
|
||
//set lls sync types
|
||
if (state->synctype >= 0 && state->synctype < 39)
|
||
{
|
||
lls = state->synctype;
|
||
}
|
||
|
||
//NXDN -- I really need to fix this better, but this is good enough for today
|
||
if (state->nxdn_last_rid != src)
|
||
{
|
||
src = state->nxdn_last_rid;
|
||
}
|
||
if (state->nxdn_last_ran != -1 )
|
||
{
|
||
rn = state->nxdn_last_ran;
|
||
}
|
||
if (state->nxdn_last_tg != tgn)
|
||
{
|
||
tgn = state->nxdn_last_tg;
|
||
}
|
||
|
||
//DMR CC
|
||
if (state->color_code_ok && state->dmr_color_code != -1 && (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32 || lls == 33) )
|
||
{
|
||
dcc = state->dmr_color_code;
|
||
}
|
||
|
||
//DMR SRC
|
||
if ( (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32) )
|
||
//if ( (lls == 12 || lls == 11 || lls == 32) )
|
||
{
|
||
//if (state->dmrburstL == 16 && state->lastsrc > 0) //state->currentslot == 0 &&
|
||
if (state->lastsrc > 0)
|
||
{
|
||
rd = state->lastsrc;
|
||
}
|
||
|
||
//if (state->dmrburstR == 16 && state->lastsrcR > 0) //state->currentslot == 1 &&
|
||
if (state->lastsrcR > 0)
|
||
{
|
||
rdR = state->lastsrcR;
|
||
}
|
||
|
||
}
|
||
|
||
//DMR TG
|
||
if ( (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32) )
|
||
//if ( (lls == 12 || lls == 11 || lls == 32) )
|
||
{
|
||
//if (state->dmrburstL == 16 && state->lasttg > 0) //state->currentslot == 0 &&
|
||
if (state->lasttg > 0)
|
||
{
|
||
tg = state->lasttg;
|
||
}
|
||
|
||
//if (state->dmrburstR == 16 && state->lasttgR > 0) //state->currentslot == 1 &&
|
||
if (state->lasttgR > 0)
|
||
{
|
||
tgR = state->lasttgR;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//P25 P1 and VCH0
|
||
if (state->p2_cc > 0)
|
||
{
|
||
nc = state->p2_cc;
|
||
}
|
||
if ( state->lasttg > 0 && (lls == 0 || lls == 1 || lls == 35 || lls == 36) )
|
||
{
|
||
tg = state->lasttg;
|
||
}
|
||
if ( state->lastsrc > 0 && (lls == 0 || lls == 1 || lls == 35 || lls == 36) )
|
||
{
|
||
rd = state->lastsrc;
|
||
}
|
||
//P25 P2 VCH2
|
||
if (state->lasttgR > 0 && (lls == 35 || lls == 36) )
|
||
{
|
||
tgR = state->lasttgR;
|
||
}
|
||
if (state->lastsrcR > 0 && (lls == 35 || lls == 36) )
|
||
{
|
||
rdR = state->lastsrcR;
|
||
}
|
||
//P25 P2 NAC to dcc for matrix shim
|
||
if (state->p2_cc > 0 && (lls == 35 || lls == 36) )
|
||
{
|
||
dcc = state->p2_cc;
|
||
}
|
||
|
||
//Call History Matrix Shuffling
|
||
//Edacs - ProVoice
|
||
if ( (lls == 14 || lls == 15 || lls == 37 || lls == 38) && state->carrier == 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;
|
||
//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 (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 || 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] = state->edacs_vc_call_type;
|
||
call_matrix[state->edacs_vc_lcn][5] = time(NULL);
|
||
}
|
||
|
||
}
|
||
|
||
//DSTAR
|
||
// if ( (lls == 6 || lls == 7 || lls == 18 || lls == 19) && (time(NULL) - call_matrix[9][5] > 5) && state->carrier == 1)
|
||
// {
|
||
// for (short int k = 0; k < 9; k++)
|
||
// {
|
||
// call_matrix[k][0] = call_matrix[k+1][0];
|
||
// call_matrix[k][1] = call_matrix[k+1][1];
|
||
// call_matrix[k][2] = call_matrix[k+1][2];
|
||
// call_matrix[k][3] = call_matrix[k+1][3];
|
||
// call_matrix[k][4] = call_matrix[k+1][4];
|
||
// call_matrix[k][5] = call_matrix[k+1][5];
|
||
// }
|
||
|
||
// call_matrix[9][0] = lls;
|
||
// call_matrix[9][1] = 1;
|
||
// call_matrix[9][2] = 1;
|
||
// call_matrix[9][3] = 1;
|
||
// call_matrix[9][4] = 1;
|
||
// call_matrix[9][5] = time(NULL);
|
||
|
||
// }
|
||
|
||
//NXDN -- I really need to fix this better, but this is good enough for today
|
||
if ( call_matrix[9][2] != src && src != 0 && rn != -1 )
|
||
{
|
||
for (short int k = 0; k < 9; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
sprintf (alias_ch[k], "%s", alias_ch[k+1]);
|
||
}
|
||
call_matrix[9][0] = lls;
|
||
call_matrix[9][1] = tgn; //was rn, switch to tgn so it'll show tg in call history
|
||
call_matrix[9][2] = src;
|
||
call_matrix[9][3] = 0;
|
||
call_matrix[9][4] = rn; //was tgn, switched with rn
|
||
call_matrix[9][5] = time(NULL);
|
||
sprintf (alias_ch[9], "%s", "");
|
||
sprintf (state->str50a, "%s", "");
|
||
|
||
//open wav file if enabled and both rd and tg are not 0
|
||
if (opts->dmr_stereo_wav == 1 && src != 0 ) //&& tgn != 0, some TG can be 0 on NXDN
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileL (opts, state);
|
||
sprintf (opts->wav_out_file, "./%s/%s %s NXDN - RAN %d - TGT %d - SRC %d.wav", opts->wav_out_dir, getDateN(), timestr, rn, tgn, src);
|
||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1)
|
||
{
|
||
beeper (opts, state, 0);
|
||
}
|
||
|
||
}
|
||
|
||
//TODO: Find better placement for these
|
||
if ( strcmp(state->str50a, "") != 0 )
|
||
sprintf (alias_ch[9], "%s", state->str50a);
|
||
|
||
//tdma only
|
||
// if ( strcmp(state->str50b, "") != 0 )
|
||
// sprintf (alias_ch[5], "%s", state->str50a);
|
||
|
||
//DMR MS
|
||
if ( call_matrix[9][2] != rd && lls == 32)
|
||
{
|
||
|
||
for (short int k = 0; k < 10; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
}
|
||
|
||
call_matrix[9][0] = lls;
|
||
call_matrix[9][1] = tg;
|
||
call_matrix[9][2] = rd;
|
||
call_matrix[9][3] = 1; //hard set slot number
|
||
call_matrix[9][4] = dcc;
|
||
call_matrix[9][5] = time(NULL);
|
||
|
||
//open wav file if enabled and both rd and tg are not 0
|
||
if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileL (opts, state);
|
||
sprintf (opts->wav_out_file, "./%s/%s %s MS - CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//fprintf (stderr, "BEEP 0 MS LEFT\n");
|
||
beeper (opts, state, 0);
|
||
state->dmr_end_alert[0] = 0; //new voice frame, okay to beep at the end of it
|
||
}
|
||
|
||
memset(state->dmr_alias_block_segment[0], 0, sizeof(state->dmr_alias_block_segment[0]));
|
||
sprintf (state->dmr_embedded_gps[0], "%s", "");
|
||
|
||
}
|
||
|
||
//DMR BS Slot 1 - matrix 0-4
|
||
if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) )
|
||
{
|
||
|
||
for (short int k = 0; k < 4; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
}
|
||
|
||
call_matrix[4][0] = lls;
|
||
call_matrix[4][1] = tg;
|
||
call_matrix[4][2] = rd;
|
||
call_matrix[4][3] = 1; //hard set slot number
|
||
call_matrix[4][4] = dcc;
|
||
call_matrix[4][5] = time(NULL);
|
||
|
||
//open wav file if enabled and both rd and tg are not 0
|
||
if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileL (opts, state);
|
||
|
||
sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//fprintf (stderr, "BEEP 0 BS LEFT\n");
|
||
beeper (opts, state, 0);
|
||
state->dmr_end_alert[0] = 0; //new voice frame, okay to beep at the end of it
|
||
}
|
||
|
||
memset(state->dmr_alias_block_segment[0], 0, sizeof(state->dmr_alias_block_segment[0]));
|
||
sprintf (state->dmr_embedded_gps[0], "%s", "");
|
||
|
||
}
|
||
|
||
//DMR BS Slot 2 - matrix 5-9
|
||
if ( call_matrix[9][2] != rdR && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) )
|
||
{
|
||
|
||
for (short int k = 5; k < 9; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
}
|
||
|
||
call_matrix[9][0] = lls;
|
||
call_matrix[9][1] = tgR;
|
||
call_matrix[9][2] = rdR;
|
||
call_matrix[9][3] = 2; //hard set slot number
|
||
call_matrix[9][4] = dcc;
|
||
call_matrix[9][5] = time(NULL);
|
||
|
||
//open wav file if enabled and both rdR and tgR are not 0
|
||
if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0)
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileR (opts, state);
|
||
sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tgR, rdR);
|
||
openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
||
{
|
||
//fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
||
beeper (opts, state, 1);
|
||
state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it
|
||
}
|
||
|
||
memset(state->dmr_alias_block_segment[1], 0, sizeof(state->dmr_alias_block_segment[1]));
|
||
sprintf (state->dmr_embedded_gps[1], "%s", "");
|
||
|
||
}
|
||
|
||
//P25 P1
|
||
if ( (lls == 0 || lls == 1) && call_matrix[9][2] != rd && nc > 0 && tg > 0 && state->dmrburstL == 26)
|
||
{
|
||
for (short int k = 0; k < 9; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
}
|
||
|
||
call_matrix[9][0] = lls;
|
||
call_matrix[9][1] = tg;
|
||
call_matrix[9][2] = rd;
|
||
call_matrix[9][3] = 0;
|
||
call_matrix[9][4] = nc;
|
||
call_matrix[9][5] = time(NULL);
|
||
|
||
//open wav file if enabled and both rd and tg are not 0
|
||
if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileL (opts, state);
|
||
sprintf (opts->wav_out_file, "./%s/%s %s P1 - NAC %X - TGT %d - SRC %d.wav", opts->wav_out_dir, getDateN(), timestr, nc, tg, rd);
|
||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1)
|
||
{
|
||
beeper (opts, state, 0);
|
||
}
|
||
|
||
}
|
||
|
||
//Remus DMR End Call Alert Beep
|
||
// if (opts->call_alert == 1)
|
||
// {
|
||
// if (state->dmrburstL == 2 && state->dmr_end_alert[0] == 0) //if TLC and flag not tripped
|
||
// {
|
||
// beeper (opts, state, 0);
|
||
// state->dmr_end_alert[0] = 1; //don't play again until new voice frames
|
||
// state->lasttg = 0;
|
||
// 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);
|
||
// state->dmr_end_alert[1] = 1; //don't play again until new voice frames
|
||
// state->lasttgR = 0;
|
||
// state->lastsrcR = 0;
|
||
// rdR = 0;
|
||
// tgR = 0;
|
||
// }
|
||
// }
|
||
|
||
//Start Printing Section
|
||
erase();
|
||
#ifdef AERO_BUILD
|
||
if (opts->ncurses_compact == 1)
|
||
{
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231015)");
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
}
|
||
#elif LIMAZULUTWEAKS
|
||
if (opts->ncurses_compact == 1)
|
||
{
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
printw ("| Digital Speech Decoder: LimaZulu Edition VI: Return of the Zulu \n");
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
}
|
||
#elif ZDEV_BUILD
|
||
if (opts->ncurses_compact == 1)
|
||
{
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
printw ("| Digital Speech Decoder: Florida Man Edition - zDEV %s \n", GIT_TAG);
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
}
|
||
#else
|
||
if (opts->ncurses_compact == 1)
|
||
{
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
printw ("| Digital Speech Decoder: Florida Man Edition - AW %s \n", GIT_TAG);
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
}
|
||
#endif
|
||
if (opts->ncurses_compact == 0)
|
||
{
|
||
attron(COLOR_PAIR(6));
|
||
for (short int i = 0; i < 7; i++)
|
||
{
|
||
printw("%s", FM_bannerN[i]);
|
||
if (i == 1) printw (" ESC to Menu");
|
||
if (i == 2) printw (" 'q' to Quit ");
|
||
if (i == 4 && opts->frame_m17 == 0) printw (" MBElib %s", versionstr);
|
||
#ifdef USE_CODEC2
|
||
if (i == 4 && opts->frame_m17 == 1) printw (" CODEC2");
|
||
#endif
|
||
#ifdef AERO_BUILD
|
||
if (i == 5) printw (" %s ", "Aero Build");
|
||
if (i == 6) printw (" AW (20231015) \n");
|
||
#elif ZDEV_BUILD
|
||
if (i == 5) printw (" %s ", "AW ");
|
||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||
#else
|
||
if (i == 5) printw (" %s ", "AW ");
|
||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||
#endif
|
||
else printw ("\n");
|
||
}
|
||
attroff(COLOR_PAIR(6)); //6
|
||
attron(COLOR_PAIR(4));
|
||
}
|
||
|
||
//fix color/pair issue when compact and trunking enabled
|
||
if (opts->ncurses_compact == 1 && opts->p25_trunk == 1) attron(COLOR_PAIR(4));
|
||
|
||
printw ("--Input Output----------------------------------------------------------------\n");
|
||
if (opts->audio_in_type == 0)
|
||
{
|
||
printw ("| Pulse Signal Input: %i kHz; %i Ch; ", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels);
|
||
if (opts->use_rigctl == 1)
|
||
printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno);
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->audio_in_type == 5)
|
||
{
|
||
printw ("| OSS Signal Input: %i kHz; 1 Ch;", SAMPLE_RATE_IN/1000);
|
||
if (opts->use_rigctl == 1)
|
||
printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno);
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->audio_in_type == 4)
|
||
{
|
||
printw ("| Symbol Bin Input: %s \n", opts->audio_in_dev);
|
||
}
|
||
|
||
if (opts->m17decoderip == 1 && opts->udp_sockfd)
|
||
printw ("| M17 UDP IP Frame Input: %s:%d \n", opts->m17_hostname, opts->m17_portno);
|
||
|
||
if (opts->audio_in_type == 8)
|
||
{
|
||
printw ("| TCP Signal Input: %s:%d; %d kHz; 1 Ch; ", opts->tcp_hostname, opts->tcp_portno, opts->wav_sample_rate/1000);
|
||
if (opts->use_rigctl == 1)
|
||
printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno);
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->audio_in_type == 2)
|
||
{
|
||
printw ("| WAV Audio Input: %s; %d kHz; \n", opts->audio_in_dev, opts->wav_sample_rate);
|
||
}
|
||
|
||
if (opts->audio_in_type == 1)
|
||
{
|
||
printw ("| STDIN Standard Input: - Menu Disabled when using STDIN!\n");
|
||
// printw ("| NCURSES Menu Disabled when using STDIN! - Use CTRL + C to Close. \n");
|
||
}
|
||
|
||
if (opts->audio_in_type == 3)
|
||
{
|
||
printw ("| RTL: %d;", opts->rtl_dev_index);
|
||
if (opts->rtl_gain_value == 0)
|
||
printw (" G: AGC;");
|
||
else
|
||
printw (" G: %idB;", opts->rtl_gain_value);
|
||
printw (" V: %iX;", opts->rtl_volume_multiplier);
|
||
printw (" PPM: %i;", opts->rtlsdr_ppm_error);
|
||
printw (" SQ: %i;", opts->rtl_squelch_level);
|
||
printw (" RMS: %04li;", opts->rtl_rms);
|
||
printw (" BW: %i;", opts->rtl_bandwidth);
|
||
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");
|
||
}
|
||
|
||
if (opts->audio_out_type == 0)
|
||
{
|
||
printw ("| Pulse Digital Output: %i kHz; %i Ch; G: %02.0f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2);
|
||
if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2);
|
||
if (opts->floating_point == 1) printw (" FLOAT: %02.0f%%;", opts->audio_gain*2);
|
||
if (opts->audio_gain == 0) printw (" (+|-) Auto ");
|
||
if (opts->audio_gain > 0) printw (" (+|-) Manual");
|
||
if (opts->use_hpf_d == 1) printw (" HPF");
|
||
if (opts->call_alert == 1) printw (" *CA!"); //Call Alert
|
||
|
||
printw (" \n");
|
||
}
|
||
|
||
if ( opts->audio_out_type == 0 && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||
{
|
||
printw ("| Pulse Analog Output: %i kHz; %i Ch; G: %02.0f%% (/|*) ", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->audio_gainA);
|
||
if (opts->audio_gainA == 0.0f) printw ("Auto ");
|
||
else printw ("Manual ");
|
||
if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms);
|
||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||
printw (" \n");
|
||
}
|
||
|
||
if (opts->audio_out_type == 5 || opts->audio_out_type == 2)
|
||
{
|
||
printw ("| OSS Audio Output: %i kHz; %i Ch; G: %02.0f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2);
|
||
if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2);
|
||
if (opts->audio_gain == 0) printw (" (+/-) Auto ");
|
||
if (opts->audio_gain > 0) printw (" (+/-) Manual");
|
||
if (opts->use_hpf_d == 1) printw (" HPF");
|
||
if (opts->call_alert == 1) printw (" *CA!"); //Call Alert
|
||
|
||
if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||
{
|
||
printw ("\n| Analog Monitor RMS: %04ld; G: %02.0f%% (/|*) ", opts->rtl_rms, opts->audio_gainA);
|
||
if (opts->audio_gainA == 0.0f) printw ("Auto ");
|
||
else printw ("Manual ");
|
||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||
}
|
||
printw (" \n");
|
||
}
|
||
|
||
if (opts->audio_out_type == 8)
|
||
{
|
||
printw ("| UDP Digital Output: %s:%d; %d kHz %d Ch; %02.0f%%", opts->udp_hostname, opts->udp_portno, opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2);
|
||
if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2);
|
||
if (opts->audio_gain == 0) printw (" (+/-) Auto ");
|
||
if (opts->audio_gain > 0) printw (" (+/-) Manual");
|
||
if (opts->use_hpf_d == 1) printw (" HPF");
|
||
if (opts->call_alert == 1) printw (" *CA!"); //Call Alert
|
||
if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||
printw (" - Monitor RMS: %04ld ", opts->rtl_rms);
|
||
printw (" \n");
|
||
if (opts->udp_sockfdA != 0) //Analog Output on udp port +2
|
||
{
|
||
printw ("| UDP Analog Output: %s:%d; 48 kHz 1 Ch; G: %02.0f%% (/|*) ", opts->udp_hostname, opts->udp_portno+2, opts->audio_gainA);
|
||
if (opts->audio_gainA == 0.0f) printw ("A ");
|
||
else printw ("M ");
|
||
if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms);
|
||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||
printw (" \n");
|
||
}
|
||
}
|
||
|
||
if (opts->m17encoder == 1)
|
||
{
|
||
printw ("| M17 Encoder:");
|
||
if (state->m17encoder_tx == 1 && state->m17_vox == 0) printw (" Toggle TX (\\) ON ;");
|
||
if (state->m17encoder_tx == 0 && state->m17_vox == 0) printw (" Toggle TX (\\) OFF;");
|
||
if (state->m17_vox == 1) printw (" Vox Mode;");
|
||
printw (" Input Gain (/|*): %02.0f%% ", opts->audio_gainA);
|
||
|
||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||
if (opts->audio_in_type != 3 && state->m17_vox == 1) printw ( " SQL: %04ld : %04d;", opts->rtl_rms, opts->rtl_squelch_level);
|
||
printw ("\n");
|
||
|
||
}
|
||
|
||
if (opts->m17_use_ip == 1)
|
||
printw ("| M17 UDP IP Frame Output: %s:%d \n", opts->m17_hostname, opts->m17_portno);
|
||
|
||
if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0)
|
||
{
|
||
printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir);
|
||
}
|
||
|
||
if (opts->wav_out_raw)
|
||
{
|
||
printw ("| Raw Audio Output: %s\n", opts->wav_out_file_raw);
|
||
}
|
||
|
||
if (opts->symbol_out_f) //don't display when not actively capturing
|
||
{
|
||
printw ("| Symbol Bin Output: %s\n", opts->symbol_out_file);
|
||
}
|
||
|
||
if (opts->dmr_stereo_wav == 0 && opts->wav_out_file[0] != 0)
|
||
{
|
||
printw ("| Decoded WAV Output: %s\n", opts->wav_out_file);
|
||
}
|
||
|
||
if (opts->dmr_stereo_wav == 1) //opts->wav_out_file[0] != 0 &&
|
||
{
|
||
printw ("| Per Call - %s\n", opts->wav_out_file);
|
||
if (opts->dmr_stereo == 1) printw ("| Per Call - %s\n", opts->wav_out_fileR);
|
||
}
|
||
|
||
#ifdef PRETTY_COLORS
|
||
if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) )
|
||
{
|
||
printw ("| Trunking -");
|
||
if (opts->trunk_tune_group_calls == 0) attron(COLOR_PAIR(2));
|
||
printw (" Group(g)");
|
||
attron(COLOR_PAIR(4));
|
||
if (opts->trunk_tune_private_calls == 0) attron(COLOR_PAIR(2));
|
||
printw (" Private(u)");
|
||
attron(COLOR_PAIR(4));
|
||
if (opts->trunk_tune_data_calls == 0) attron(COLOR_PAIR(2));
|
||
printw (" Data(d)");
|
||
attron(COLOR_PAIR(4));
|
||
if (opts->trunk_tune_enc_calls == 0) attron(COLOR_PAIR(2));
|
||
printw (" Encrypted(e)");
|
||
attron(COLOR_PAIR(4));
|
||
printw (" Calls");
|
||
if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n");
|
||
else printw (" - Black List Mode\n");
|
||
}
|
||
#else //set on to UPPER CASE, off to lower case
|
||
if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) )
|
||
{
|
||
printw ("| Trunking -");
|
||
if (opts->trunk_tune_group_calls == 0) printw (" group(g)");
|
||
else printw (" GROUP(g)");
|
||
if (opts->trunk_tune_private_calls == 0) printw (" private(u)");
|
||
else printw (" PRIVATE(u)");
|
||
if (opts->trunk_tune_data_calls == 0) printw (" data(d)");
|
||
else printw (" DATA(d)");
|
||
if (opts->trunk_tune_enc_calls == 0) printw (" encrypted(e)");
|
||
else printw (" ENCRYPTED(e)");
|
||
printw (" Calls");
|
||
if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n");
|
||
else printw (" - Black List Mode\n");
|
||
}
|
||
#endif
|
||
//print additional information for EDACS modes and toggles
|
||
#ifdef PRETTY_COLORS
|
||
if (opts->p25_trunk == 1 && opts->frame_provoice == 1)
|
||
{
|
||
printw ("| \\--EDACS -");
|
||
if (state->ea_mode == -1)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Standard/Network");
|
||
printw (" Extended Address");
|
||
attron(COLOR_PAIR(4));
|
||
}
|
||
else if (state->ea_mode == 0)
|
||
{
|
||
printw (" Standard/Network");
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Extended Address");
|
||
attron(COLOR_PAIR(4));
|
||
}
|
||
else if (state->ea_mode == 1)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Standard/Network");
|
||
attron(COLOR_PAIR(4));
|
||
printw (" Extended Address");
|
||
}
|
||
printw (" Mode (S);");
|
||
|
||
printw(" ESK: %02X", state->esk_mask);
|
||
printw (" (A);");
|
||
|
||
if (state->ea_mode == 0)
|
||
printw (" AFS: %d:%d:%d;", state->edacs_a_bits, state->edacs_f_bits, state->edacs_s_bits);
|
||
|
||
//TG Hold on EDACS, if specified by user
|
||
if (state->tg_hold != 0)
|
||
{
|
||
// Compute AFS for display purposes only
|
||
int a = (state->tg_hold >> state->edacs_a_shift) & state->edacs_a_mask;
|
||
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);
|
||
}
|
||
|
||
attron(COLOR_PAIR(4));
|
||
printw ("\n");
|
||
}
|
||
#else //set on to UPPER CASE, off to lower case
|
||
if (opts->p25_trunk == 1 && opts->frame_provoice == 1)
|
||
{
|
||
printw ("| \\--EDACS -");
|
||
if (state->ea_mode == -1)
|
||
{
|
||
printw (" standard/network");
|
||
printw (" extended address");
|
||
}
|
||
else if (state->ea_mode == 0)
|
||
{
|
||
printw (" STANDARD/NETWORK");
|
||
printw (" extended address");
|
||
}
|
||
else if (state->ea_mode == 1)
|
||
{
|
||
printw (" standard/network");
|
||
printw (" EXTENDED ADDRESS");
|
||
}
|
||
printw (" Mode (S);");
|
||
|
||
printw(" ESK: %02X", state->esk_mask);
|
||
printw (" (A) Toggle; ");
|
||
|
||
if (state->ea_mode == 0)
|
||
printw (" AFS: %d:%d:%d;", state->edacs_a_bits, state->edacs_f_bits, state->edacs_s_bits);
|
||
|
||
//TG Hold on EDACS, if specified by user
|
||
if (state->tg_hold != 0)
|
||
{
|
||
// Compute AFS for display purposes only
|
||
int a = (state->tg_hold >> state->edacs_a_shift) & state->edacs_a_mask;
|
||
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);
|
||
}
|
||
|
||
printw ("\n");
|
||
}
|
||
#endif
|
||
// if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n");
|
||
if (state->M == 1)
|
||
{
|
||
if (state->R != 0) printw ("| Forcing Key Priority -- NXDN Sc Key: %05lld \n", state->R);
|
||
if (state->K != 0) printw ("| Forcing Key Priority -- Moto BP Key: %03lld \n", state->K);
|
||
if (state->K1 != 0) printw ("| Forcing Key Priority -- tera BP Key: %016llX \n", state->K1);
|
||
if (state->K != 0 && state->K1 != 0) printw ("| Warning! Multiple DMR Key Types Loaded! \n"); //warning may not be required
|
||
}
|
||
if (state->M == 0x21)
|
||
{
|
||
if (state->R != 0) printw ("| Forcing Key Priority -- RC4 Key: %010llX \n", state->R);
|
||
}
|
||
|
||
if (opts->scanner_mode == 1)
|
||
{
|
||
printw ("| Scan Mode: ");
|
||
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
|
||
}
|
||
|
||
if (opts->reverse_mute == 1) printw ("| Reverse Mute - Muting Unencrypted Voice\n");
|
||
// if (opts->call_alert == 1) printw ("| Call Alert Tone Enabled\n");
|
||
|
||
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
attroff(COLOR_PAIR(4));
|
||
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
level = (int) state->max / 164; //only update on carrier present
|
||
if (opts->mod_qpsk == 1) level = (int) state->max / 328; //test values here
|
||
if (opts->audio_in_type == 4) level = 50; //hard set when reading symbol bin files, otherwise, it will just be near zero
|
||
if (level > 100) level = 100; //cap max at 100 to prevent it going over
|
||
reset = 1;
|
||
}
|
||
else level = 0;
|
||
|
||
printw ("--Audio Decode----------------------------------------------------------------\n");
|
||
printw ("| Demod/Rate: ");
|
||
if (opts->mod_qpsk == 1) printw ("[QPSK]");
|
||
if (opts->mod_c4fm == 1) printw ("[C4FM]");
|
||
if (opts->mod_gfsk == 1) printw ("[GFSK]");
|
||
printw ( "[%d] \n", (48000*opts->wav_interpolator)/state->samplesPerSymbol);
|
||
if (opts->m17encoder == 1) printw ("| Encoding: [%s] \n", opts->output_name);
|
||
printw ("| Decoding: [%s] ", opts->output_name);
|
||
if (opts->aggressive_framesync == 0) printw ("CRC/(RAS) ");
|
||
//debug -- troubleshoot voice tuning after grant on DMR CC, subsequent grant may not tune because tuner isn't available
|
||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1) printw ("Tuner Locked ");
|
||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) printw ("Tuner Available ");
|
||
printw ("\n");
|
||
printw ("| In Level: [%02d%%] \n", level);
|
||
|
||
if (opts->dmr_stereo == 0)
|
||
{
|
||
printw ("| Voice Error: [%X][%X]", state->errs&0xF, state->errs2&0xF);
|
||
if (opts->slot1_on == 0) printw (" OFF");
|
||
if (opts->slot1_on == 1) printw (" ON");
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->dmr_stereo == 1)
|
||
{
|
||
printw ("| Voice Error: [%X][%X] Slot 1 (1)", state->errs&0xF, state->errs2&0xF);
|
||
if (opts->slot1_on == 0) printw (" OFF");
|
||
if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred");
|
||
printw ("\n");
|
||
printw ("| Voice Error: [%X][%X] Slot 2 (2)", state->errsR&0xF, state->errs2R&0xF);
|
||
if (opts->slot2_on == 0) printw (" OFF");
|
||
if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred");
|
||
printw ("\n");
|
||
}
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
|
||
printw ("--Call Info-------------------------------------------------------------------\n");
|
||
|
||
//DSTAR
|
||
if (lls == 6 || lls == 7 || lls == 18 || lls == 19)
|
||
{
|
||
printw ("| %s ", SyncTypes[lls]);
|
||
printw ("\n");
|
||
printw ("| RPT2: %s", state->dstar_rpt2);
|
||
printw (" RPT1: %s", state->dstar_rpt1);
|
||
printw ("\n");
|
||
printw ("| DEST: %s", state->dstar_dst);
|
||
printw (" SRC: %s", state->dstar_src);
|
||
printw ("\n");
|
||
printw ("| TEXT: %s", state->dstar_txt);
|
||
printw ("\n");
|
||
printw ("| DATA: %s", state->dstar_gps);
|
||
printw ("\n");
|
||
}
|
||
|
||
//M17
|
||
if (lls == 8 || lls == 9 || lls == 16 || lls == 17)
|
||
{
|
||
|
||
printw ("| ");
|
||
printw ("M17: ");
|
||
|
||
//insert data type and frame information
|
||
if (state->m17_str_dt == 0) printw("Reserved");
|
||
if (state->m17_str_dt == 1) printw("Data ");
|
||
if (state->m17_str_dt == 2) printw("Voice (3200) ");
|
||
if (state->m17_str_dt == 3) printw("Voice (1600) + Data");
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
printw ("DST: ");
|
||
if (state->m17_dst == 0xFFFFFFFFFFFF)
|
||
printw("BROADCAST ");
|
||
else if (state->m17_dst != 0 && state->m17_dst >= 0xEE6B28000000)
|
||
printw("RESERVED (%012llx) ", state->m17_dst);
|
||
else
|
||
printw("%s", state->m17_dst_str);
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
printw ("SRC: ");
|
||
if (state->m17_src != 0 && state->m17_src >= 0xEE6B28000000)
|
||
printw("RESERVED (%012llx)", state->m17_src);
|
||
else
|
||
printw("%s", state->m17_src_str);
|
||
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
printw ("CAN: %02d ", state->m17_can);
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
|
||
//fill in any extra info, like Meta (IV, etc)
|
||
if (state->m17_enc == 1)
|
||
{
|
||
printw (" Scrambler - Type: %d", state->m17_enc_st);
|
||
}
|
||
|
||
if (state->m17_enc == 2)
|
||
{
|
||
printw (" AES-CTR - IV: ");
|
||
//display packed meta as IV
|
||
for (i = 0; i < 14; i++)
|
||
printw ("%02X", state->m17_meta[i]);
|
||
}
|
||
|
||
if (state->m17_enc == 3)
|
||
{
|
||
printw (" Reserved Enc - Type: %d", state->m17_enc_st);
|
||
}
|
||
|
||
printw ("\n");
|
||
|
||
}
|
||
|
||
//YSF
|
||
if (lls == 30 || lls == 31)
|
||
{
|
||
// printw ("\n");
|
||
printw ("| ");
|
||
printw ("Fusion - ");
|
||
//insert data type and frame information
|
||
if (state->ysf_dt == 0) printw("V/D1 ");
|
||
if (state->ysf_dt == 1) printw("DATA ");
|
||
if (state->ysf_dt == 2) printw("V/D2 ");
|
||
if (state->ysf_dt == 3) printw("VWFR ");
|
||
printw (" ");
|
||
if (state->ysf_cm == 0) printw("Group/CQ ");
|
||
if (state->ysf_cm == 3) printw("Private ");
|
||
if (state->ysf_cm == 1) printw("Radio ID ");
|
||
if (state->ysf_cm == 2) printw("Reserved ");
|
||
|
||
if (state->ysf_fi == 0) printw("HC ");
|
||
if (state->ysf_fi == 1) printw("CC ");
|
||
if (state->ysf_fi == 2) printw("TC ");
|
||
if (state->ysf_fi == 3) printw("XX ");
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
//NOTE: In Radio ID Mode, the DST will be split on Destination and Source Radio ID values
|
||
printw ("DST: %s ", state->ysf_tgt);
|
||
printw ("SRC: %s ", state->ysf_src);
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("UPL: %s ", state->ysf_upl);
|
||
printw ("DNL: %s ", state->ysf_dnl);
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("RM1: %s ", state->ysf_rm1);
|
||
printw ("RM2: %s ", state->ysf_rm2);
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("RM3: %s ", state->ysf_rm3);
|
||
printw ("RM4: %s ", state->ysf_rm4);
|
||
|
||
//these texts can get pretty long and out of sorts, and lots of 0x20 spaces
|
||
//just going to leave these to only be in the console output
|
||
|
||
// printw ("\n");
|
||
// printw ("| ");
|
||
// printw ("TXT: ");
|
||
// for (i = 4; i < 8; i++)
|
||
// {
|
||
// for (int j = 0; j < 20; j++)
|
||
// {
|
||
// //no spaces and no asterisks
|
||
// if (state->ysf_txt[i][j] != 0x2A)
|
||
// printw ("%c", state->ysf_txt[i][j]);
|
||
// }
|
||
// // printw (" "); //just a single space between each 'block'
|
||
// }
|
||
|
||
printw ("\n");
|
||
|
||
}
|
||
|
||
//NXDN
|
||
if (lls == 28 || lls == 29)
|
||
{
|
||
if (strcmp (state->nxdn_location_category, "Type-D") == 0) idas = 1;
|
||
|
||
if (opts->p25_trunk == 1)
|
||
{
|
||
|
||
printw ("| ");
|
||
if (opts->p25_is_tuned == 0)
|
||
{
|
||
if (idas == 0) printw ("Monitoring RCCH Channel"); //Control Channel
|
||
if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2 Channel
|
||
if (state->p25_cc_freq != 0)
|
||
{
|
||
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
|
||
if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2
|
||
if (state->p25_vc_freq[0] != 0)
|
||
{
|
||
printw (" - Frequency: %.06lf Mhz ", (double)state->p25_vc_freq[0]/1000000);
|
||
}
|
||
}
|
||
|
||
printw ("\n");
|
||
}
|
||
|
||
|
||
|
||
printw ("| ");
|
||
// #ifdef LIMAZULUTWEAKS
|
||
if (idas == 0) printw ("NXDN - RAN: %02d; ", state->nxdn_last_ran);
|
||
if (idas == 1) printw ("IDAS - Area: %02d; ", state->nxdn_last_ran);
|
||
// #else
|
||
// if (idas == 0) printw ("NXDN - RAN: [%02d] ", rn);
|
||
// if (idas == 1) printw ("IDAS - Area: [%02d] ", rn);
|
||
// #endif
|
||
if (state->nxdn_location_site_code != 0)
|
||
{
|
||
printw ("Cat: %s; ", state->nxdn_location_category);
|
||
printw ("Sys Code: %d; ", state->nxdn_location_sys_code);
|
||
printw ("Site Code: %d; ", state->nxdn_location_site_code);
|
||
}
|
||
|
||
//if system supports Direct Frequency Assignment
|
||
if (state->nxdn_rcn == 1) printw ("DFA ");
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("TGT: [%5d] ", tgn);
|
||
printw ("SRC: [%5d] ", src);
|
||
// if (state->nxdn_alias_block_segment[0][0] > 0) //consider disabling this
|
||
printw ("Alias: [%s]", alias_ch[9]);
|
||
|
||
//Group Name Labels from CSV import
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == tgn)
|
||
{
|
||
printw ("TG: ");
|
||
attron(COLOR_PAIR(4));
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s] ", state->group_array[k].groupMode);
|
||
}
|
||
else if (state->group_array[k].groupNumber == src)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
}
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
|
||
if (state->carrier == 1)
|
||
{
|
||
printw(" %s ", state->nxdn_call_type);
|
||
}
|
||
printw ("\n|");
|
||
if (state->nxdn_cipher_type > 0)
|
||
{
|
||
printw (" ALG: [0x%02X] KEY: [0x%02X] ", state->nxdn_cipher_type, state->nxdn_key);
|
||
}
|
||
if (state->nxdn_cipher_type == 0x1 && state->carrier == 1)
|
||
{
|
||
if (state->R == 0) attron(COLOR_PAIR(2));
|
||
printw ("Scrambler ");
|
||
if (state->R == 0) attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
if (state->R != 0)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("KEY VALUE: [%05lld] ", state->R );
|
||
printw ("SEED: [%04llX]", state->payload_miN);
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
if (state->nxdn_cipher_type == 0x2 && state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("IV: [%016llX] ", state->payload_miN);
|
||
attron(COLOR_PAIR(2));
|
||
printw ("DES1 ");
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->nxdn_cipher_type == 0x3 && state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("IV: [%016llX] ", state->payload_miN);
|
||
attron(COLOR_PAIR(2));
|
||
printw ("AES-256 ");
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->nxdn_cipher_type > 0x3 && state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw ("Unknown Encryption ");
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//Active Trunking Channels (NXDN and IDAS)
|
||
if (1 == 1) //opts->p25_trunk
|
||
{
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
//active channel display
|
||
attron(COLOR_PAIR(4));
|
||
for (int i = 0; i < 16; i++)
|
||
{
|
||
if (state->active_channel[i] != 0) printw ("%s", state->active_channel[i]);
|
||
}
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
}
|
||
|
||
//TG Hold, if specified by user
|
||
if (state->tg_hold != 0) printw ("TG HOLD: %d", state->tg_hold);
|
||
|
||
printw("\n");
|
||
}
|
||
|
||
//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)
|
||
{
|
||
printw ("| ");
|
||
if (lls > 1 && lls < 30)
|
||
{
|
||
printw ("DMR BS - DCC: %02i; ", dcc);
|
||
// 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
|
||
if (state->dmr_rest_channel > 0)
|
||
{
|
||
printw ("Rest LSN: %02d; ", state->dmr_rest_channel);
|
||
if (state->trunk_chan_map[state->dmr_rest_channel] != 0)
|
||
{
|
||
printw ("Freq: %.06lf Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000);
|
||
}
|
||
}
|
||
else if (state->p25_cc_freq != 0)
|
||
{
|
||
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||
}
|
||
|
||
}
|
||
else if (lls == 32 || lls == 33 || lls == 34)
|
||
{
|
||
printw ("DMR MS - DCC: %02i; ", dcc);
|
||
}
|
||
else if (lls == 0 || lls == 1) //P1
|
||
{
|
||
printw ("P25p1 - %05llX:%03llX:%03llX; RFSS: %lld SITE: %lld ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
|
||
if (state->p25_cc_freq != 0)
|
||
{
|
||
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||
}
|
||
}
|
||
else if (lls == 35 || lls == 36) //P2
|
||
{
|
||
printw ("P25p2 - %05llX:%03llX:%03llX; RFSS: %lld SITE: %lld ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
|
||
if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Phase 2 Missing Parameters ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
else if (state->p2_wacn == 0xFFFFF || state->p2_sysid == 0xFFF || state->p2_cc == 0xFFF)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Phase 2 Invalid Parameters ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
else
|
||
{
|
||
if (state->p25_cc_freq != 0)
|
||
{
|
||
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||
}
|
||
}
|
||
}
|
||
|
||
printw ("\n");
|
||
//Slot 1 [0]
|
||
printw ("| SLOT 1 - ");
|
||
if (state->dmrburstL < 16 && state->carrier == 1 && state->lasttg > 0 && state->lastsrc > 0)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
}
|
||
printw ("TGT: [%8i] SRC: [%8i] ", state->lasttg, state->lastsrc);
|
||
if (state->dmrburstL != 16 && state->carrier == 1 && state->lasttg > 0 && state->lastsrc > 0)
|
||
{
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
printw ("%s | ", state->call_string[0]);
|
||
printw ("%s ", DMRBusrtTypes[state->dmrburstL]);
|
||
|
||
if (opts->slot_preference == 1 && 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->dmrburstL == 16 && state->payload_algid == 0 && (state->dmr_so & 0xCF) == 0x40) //4F or CF mask? & 0xCF currently
|
||
{
|
||
attron(COLOR_PAIR(5));
|
||
printw (" **Pr** ");
|
||
attroff(COLOR_PAIR(5));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
if(state->dmrburstL == 16 && state->payload_algid == 0 && state->K > 0 && state->dmr_fid == 0x10 && (state->dmr_so & 0xCF) == 0x40)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("Pr Key [%3lld] ", state->K);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
if(state->dmrburstL == 16 && state->payload_algid == 0 && state->H > 0 && state->dmr_fid == 0x68 && ((state->dmr_so & 0xCF) == 0x40) )
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("**tera Pr Key [%010llX] ", state->H);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//ALG, KeyID, MI //was key_id
|
||
if(state->dmrburstL == 16 && state->payload_algid > 0 && (state->dmr_so & 0xCF) == 0x40)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("ALG: 0x%02X KEY: 0x%02X MI: 0x%08X ", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//P25 FDMA/TDMA
|
||
if(state->dmrburstL > 19 && state->payload_algid > 0 && state->payload_algid != 0x80)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("ALG: 0x%02X KEY: 0x%04X MI: 0x%016llX ", state->payload_algid, state->payload_keyid, state->payload_miP);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//Anytone 0x01 will never show here since its converted to 0x21 for handling
|
||
if (state->payload_algid == 0xAA || state->payload_algid == 0x21 || state->payload_algid == 0x01)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("RC4 ");
|
||
if (state->R != 0) { printw("Key: %010llX ", state->R); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x81 || state->payload_algid == 0x22)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES1 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x82)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES2 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x83)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES3 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x85 || state->payload_algid == 0x24)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("AES-128");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x84 || state->payload_algid == 0x25 || state->payload_algid == 0x05)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("AES-256");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x02)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("Hytera Full Encrypt");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//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));
|
||
// printw (" **ENC** ");
|
||
// attroff(COLOR_PAIR(2));
|
||
// attron(COLOR_PAIR(3));
|
||
// }
|
||
// if(state->dmrburstL == 16 && state->dmr_so == 0x80)
|
||
// {
|
||
// attron(COLOR_PAIR(2));
|
||
// printw (" **Emergency** ");
|
||
// attroff(COLOR_PAIR(2));
|
||
// attron(COLOR_PAIR(3));
|
||
// }
|
||
// if(state->dmrburstL == 16 && state->dmr_so == 0x30) //0010 0000
|
||
// {
|
||
// attron(COLOR_PAIR(2));
|
||
// printw (" **Private Call** ");
|
||
// attroff(COLOR_PAIR(2));
|
||
// attron(COLOR_PAIR(3));
|
||
// }
|
||
|
||
printw ("\n");
|
||
|
||
//printw ("| | "); //10 spaces
|
||
printw ("| D XTRA | ");
|
||
|
||
attron(COLOR_PAIR(4));
|
||
|
||
if(state->dmrburstL == 16 || state->dmrburstL == 21 || state->dmrburstL == 26 || state->dmrburstL == 27 || state->dmrburstL == 32) //only during call
|
||
{
|
||
|
||
attron(COLOR_PAIR(4));
|
||
|
||
//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]);
|
||
}
|
||
}
|
||
|
||
attroff(COLOR_PAIR(5));
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
|
||
//LRRP
|
||
if(state->dmrburstL != 16) //only during data and no trunking
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("%s", state->dmr_lrrp_gps[0]);
|
||
}
|
||
|
||
//Group Name Labels from CSV import
|
||
if (state->dmrburstL == 16 || state->dmrburstL > 19)
|
||
{
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == state->lasttg)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s] ", state->group_array[k].groupMode);
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
|
||
printw ("\n");
|
||
|
||
//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)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
}
|
||
printw ("TGT: [%8i] SRC: [%8i] ", state->lasttgR, state->lastsrcR);
|
||
if (state->dmrburstR != 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0)
|
||
{
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
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*");
|
||
|
||
printw ("\n");
|
||
|
||
printw ("| V XTRA | "); //10 spaces
|
||
|
||
if(state->dmrburstR == 16 && state->payload_algidR == 0 && (state->dmr_soR & 0xCF) == 0x40) //4F or CF mask?
|
||
{
|
||
attron(COLOR_PAIR(5));
|
||
printw (" **Pr** ");
|
||
attroff(COLOR_PAIR(5));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->K > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x10)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("Pr Key [%3lld] ", state->K);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->H > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x68)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("**tera Pr Key [%010llX] ", state->H);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
//ALG, KeyID, MI 2 //was keyidR
|
||
if(state->dmrburstR == 16 && state->payload_algidR > 0 && (state->dmr_soR & 0xCF) == 0x40)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("ALG: 0x%02X KEY: 0x%02X MI: 0x%08X ", state->payload_algidR, state->payload_keyidR, state->payload_miR);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
//P25-P1 and P2
|
||
if(state->dmrburstR > 19 && state->payload_algidR > 0 && state->payload_algidR != 0x80)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("ALG: 0x%02X KEY: 0x%04X MI: 0x%016llX ", state->payload_algidR, state->payload_keyidR, state->payload_miN);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//Anytone 0x01 will never show here since its converted to 0x21 for handling
|
||
if (state->payload_algidR == 0xAA || state->payload_algidR == 0x21 || state->payload_algidR == 0x01)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("RC4 ");
|
||
if (state->RR != 0) { printw("Key: %010llX ", state->RR); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x81 || state->payload_algidR == 0x22)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES1 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x82)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES2 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x83)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES3 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x85 || state->payload_algidR == 0x24)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("AES-128");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x84 || state->payload_algidR == 0x25 || state->payload_algidR == 0x05)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("AES-256");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x02)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("Hytera Full Encrypt");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//Not always correct, or correct at all, depends on context
|
||
//this is already in the call_string anyways
|
||
|
||
// if(state->dmrburstR == 16 && state->dmr_soR == 0x40 && state->R == 0) //0100 0000
|
||
// {
|
||
// attron(COLOR_PAIR(2));
|
||
// printw (" **ENC** ");
|
||
// attroff(COLOR_PAIR(2));
|
||
// attron(COLOR_PAIR(3));
|
||
// }
|
||
// if(state->dmrburstR == 16 && state->dmr_soR == 0x80)
|
||
// {
|
||
// attron(COLOR_PAIR(2));
|
||
// printw (" **Emergency** ");
|
||
// attroff(COLOR_PAIR(2));
|
||
// attron(COLOR_PAIR(3));
|
||
// }
|
||
// if(state->dmrburstR == 16 && state->dmr_soR == 0x30) //0010 0000
|
||
// {
|
||
// attron(COLOR_PAIR(2));
|
||
// printw (" **Private Call** ");
|
||
// attroff(COLOR_PAIR(2));
|
||
// attron(COLOR_PAIR(3));
|
||
// }
|
||
|
||
printw ("\n");
|
||
|
||
//printw ("| | ");
|
||
printw ("| D XTRA | ");
|
||
|
||
attron(COLOR_PAIR(4));
|
||
|
||
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]);
|
||
|
||
//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[1][i][j]);
|
||
}
|
||
}
|
||
|
||
attroff(COLOR_PAIR(5));
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
}
|
||
|
||
//LRRP
|
||
if(state->dmrburstR != 16) //only during data and no trunking
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("%s", state->dmr_lrrp_gps[1]);
|
||
}
|
||
|
||
//Group Name Labels from CSV import
|
||
if (state->dmrburstR == 16 || state->dmrburstR > 19)
|
||
{
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == state->lasttgR)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s] ", state->group_array[k].groupMode);
|
||
}
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
}
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
|
||
printw ("\n");
|
||
|
||
if (1 == 1) //opts->p25_trunk == 1
|
||
{
|
||
printw ("| | "); //Active Trunking Channels
|
||
|
||
//active channel display
|
||
attron(COLOR_PAIR(4));
|
||
for (int i = 0; i < 31; i++) //up to 31 idas channels
|
||
{
|
||
if (state->active_channel[i] != 0) printw ("%s", state->active_channel[i]);
|
||
}
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
printw ("\n");
|
||
}
|
||
|
||
if (1 == 1) //opts->p25_trunk == 1
|
||
{
|
||
printw ("| | "); //Currently Tuned Frequency
|
||
|
||
// Tuned Frequency Display
|
||
if (state->p25_vc_freq[0] != 0)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("Frequency: %.06lf MHz ", (double)state->p25_vc_freq[0]/1000000);
|
||
}
|
||
|
||
//TG Hold, if specified by user
|
||
if (state->tg_hold != 0) printw ("TG HOLD: %d", state->tg_hold);
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
printw ("\n");
|
||
}
|
||
|
||
} // end if not MS
|
||
} //end DMR BS Types
|
||
|
||
//dPMR
|
||
if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27)
|
||
{
|
||
printw ("| DCC: [%i] ", state->dpmr_color_code);
|
||
printw ("TGT: [%s] SRC: [%s] ", state->dpmr_target_id, state->dpmr_caller_id);
|
||
printw ("\n| ");
|
||
if (state->dPMRVoiceFS2Frame.Version[0] == 3)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw ("Scrambler ");
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
if (state->R != 0)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("KEY VALUE: [%05lld] ", state->R );
|
||
//printw ("SEED: [%04llX]", state->payload_miN);
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
printw ("\n");
|
||
}
|
||
|
||
//EDACS and ProVoice
|
||
if (lls == 14 || lls == 15 || lls == 37 || lls == 38)
|
||
{
|
||
attroff (COLOR_PAIR(3)); //colors off for EDACS
|
||
if (state->edacs_site_id != 0)
|
||
{
|
||
if (opts->p25_is_tuned == 0)
|
||
{
|
||
printw ("| Monitoring Control Channel\n");
|
||
}
|
||
else
|
||
{
|
||
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);
|
||
}
|
||
printw ("| SITE [%03lld][%02llX]", state->edacs_site_id, state->edacs_site_id);
|
||
|
||
if (state->ea_mode == 1)
|
||
{
|
||
printw (" Extended Addressing");
|
||
}
|
||
else printw (" Standard/Networked");
|
||
if (state->esk_mask == 0xA0)
|
||
{
|
||
printw (" w/ ESK");
|
||
}
|
||
else printw (" w/o ESK");
|
||
printw ("\n");
|
||
}
|
||
for (i = 1; i <= state->edacs_lcn_count; i++)
|
||
{
|
||
// Compute AFS for display purposes only
|
||
int a = (call_matrix[i][2] >> state->edacs_a_shift) & state->edacs_a_mask;
|
||
int f = (call_matrix[i][2] >> state->edacs_f_shift) & state->edacs_f_mask;
|
||
int s = call_matrix[i][2] & state->edacs_s_mask;
|
||
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)
|
||
{
|
||
attron (COLOR_PAIR(1)); //yellow
|
||
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));
|
||
}
|
||
//print dying or dead calls in red for x seconds longer
|
||
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)
|
||
{
|
||
// Voice call
|
||
if ((call_matrix[i][4] & EDACS_IS_VOICE) != 0)
|
||
{
|
||
// System all-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
|
||
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] );
|
||
// 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_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]");
|
||
}
|
||
else
|
||
// Data call
|
||
printw (" TGT [ DATA ] SRC [%8lld] Data", call_matrix[i][3] );
|
||
}
|
||
else
|
||
{
|
||
// Voice call
|
||
if ((call_matrix[i][4] & EDACS_IS_VOICE) != 0)
|
||
{
|
||
// 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] );
|
||
// 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] );
|
||
// Test call
|
||
else if ((call_matrix[i][4] & EDACS_IS_TEST_CALL) != 0)
|
||
printw (" TGT [ SYSTEM ] SRC [ SYS ] Test Call");
|
||
// Unknown call
|
||
else
|
||
printw (" Unknown call type" );
|
||
|
||
// Call flags
|
||
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]");
|
||
}
|
||
else
|
||
// Data call
|
||
printw (" TGT [ DATA ] SRC [%8lld] Data", 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;
|
||
}
|
||
}
|
||
|
||
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 tuned
|
||
printw ("\n");
|
||
}
|
||
if (state->carrier == 1)
|
||
{
|
||
attron (COLOR_PAIR(3));
|
||
}
|
||
}
|
||
|
||
//fence bottom
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
//colors off
|
||
if (state->carrier == 1){ //same as above
|
||
attroff(COLOR_PAIR(3));
|
||
}
|
||
//only print call history if enabled
|
||
if (opts->ncurses_history == 1)
|
||
{
|
||
attron(COLOR_PAIR(4)); //cyan for history
|
||
printw ("--Call History----------------------------------------------------------------\n");
|
||
for (short int j = 0; j < 10; j++)
|
||
{
|
||
//only print if a valid time was assigned to the matrix, and not EDACS/PV, and source is not zero
|
||
if ( ((time(NULL) - call_matrix[9-j][5]) < 999999) && call_matrix[9-j][0] != 14 && call_matrix[9-j][0] != 15 && call_matrix[9-j][0] != 37 && call_matrix[9-j][0] != 38 && call_matrix[9-j][2] != 0) //
|
||
{
|
||
// printw ("| %s ", SyncTypes[call_matrix[9-j][0]]); //sync type
|
||
|
||
printw ("| ");
|
||
printw ("%s ", getDateC(call_matrix[9-j][5]) );
|
||
printw ("%s ", getTimeC(call_matrix[9-j][5]) );
|
||
|
||
if (lls == 28 || lls == 29)
|
||
{
|
||
if (idas == 0) printw ("RAN [%02lld] ", call_matrix[9-j][4]);
|
||
if (idas == 1) printw ("Area [%02lld] ", call_matrix[9-j][4]);
|
||
printw ("TG [%5lld] ", call_matrix[9-j][1]);
|
||
printw ("RID [%5lld] ", call_matrix[9-j][2]);
|
||
}
|
||
//dPMR
|
||
if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27)
|
||
{
|
||
printw ("TGT [%8lld] ", call_matrix[9-j][1]);
|
||
printw ("SRC [%8lld] ", call_matrix[9-j][2]);
|
||
printw ("DCC [%2lld] ", call_matrix[9-j][4]);
|
||
}
|
||
//P25
|
||
if (call_matrix[9-j][0] == 0 || call_matrix[9-j][0] == 1 || call_matrix[9-j][0] == 35 || call_matrix[9-j][0] == 36)
|
||
{
|
||
printw ("TGT [%8lld] ", call_matrix[9-j][1]);
|
||
printw ("SRC [%8lld] ", call_matrix[9-j][2]);
|
||
printw ("NAC [0x%03llX] ", call_matrix[9-j][4]);
|
||
}
|
||
//DMR BS Types
|
||
if (call_matrix[9-j][0] == 12 || call_matrix[9-j][0] == 13 || call_matrix[9-j][0] == 10 || call_matrix[9-j][0] == 11 )
|
||
{
|
||
// printw ("S[%lld] ", call_matrix[9-j][3]); //%d
|
||
printw ("TGT [%8lld] ", call_matrix[9-j][1]);
|
||
printw ("SRC [%8lld] ", call_matrix[9-j][2]);
|
||
printw ("DCC [%02lld] ", call_matrix[9-j][4]);
|
||
}
|
||
//DMR MS Types
|
||
if (call_matrix[9-j][0] == 32 || call_matrix[9-j][0] == 33 || call_matrix[9-j][0] == 34 )
|
||
{
|
||
// printw ("S[%lld] ", call_matrix[9-j][3]);
|
||
printw ("TGT [%8lld] ", call_matrix[9-j][1]);
|
||
printw ("SRC [%8lld] ", call_matrix[9-j][2]);
|
||
printw ("DCC [%02lld] ", call_matrix[9-j][4]);
|
||
}
|
||
|
||
// #ifdef LIMAZULUTWEAKS
|
||
//Group Name Labels from CSV import
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == call_matrix[9-j][1])
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("[%s]", state->group_array[k].groupName);
|
||
printw ("[%s] ", state->group_array[k].groupMode);
|
||
}
|
||
else if (state->group_array[k].groupNumber == call_matrix[9-j][2])
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("[%s]", state->group_array[k].groupName);
|
||
printw ("[%s] ", state->group_array[k].groupMode);
|
||
}
|
||
}
|
||
|
||
//alias values here
|
||
printw ("%s", alias_ch[9-j]);
|
||
|
||
// #endif
|
||
printw ("\n");
|
||
}
|
||
|
||
//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)
|
||
{
|
||
printw ("| ");
|
||
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)
|
||
{
|
||
// Voice call
|
||
if ((call_matrix[j][4] & EDACS_IS_VOICE) != 0)
|
||
{
|
||
// Group call
|
||
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]);
|
||
// 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_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]");
|
||
}
|
||
else
|
||
// Data call
|
||
printw ("Target [ DATA ] Source [%8lld] Data", call_matrix[j][3]);
|
||
}
|
||
else
|
||
{
|
||
// Voice call
|
||
if ((call_matrix[j][4] & EDACS_IS_VOICE) != 0)
|
||
{
|
||
// Compute AFS for display purposes only
|
||
int a = (call_matrix[j][2] >> state->edacs_a_shift) & state->edacs_a_mask;
|
||
int f = (call_matrix[j][2] >> state->edacs_f_shift) & state->edacs_f_mask;
|
||
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]);
|
||
// 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]);
|
||
// Test call
|
||
else if ((call_matrix[j][4] & EDACS_IS_TEST_CALL) != 0)
|
||
printw ("Target [ SYSTEM ] Source [ SYS ] Test Call");
|
||
// Unknown call
|
||
else
|
||
printw ("Unknown call type");
|
||
|
||
// Call flags
|
||
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]");
|
||
}
|
||
else
|
||
// Data call
|
||
printw ("Target [ DATA ] Source [%5lld] Data", call_matrix[j][3]);
|
||
}
|
||
//test
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == call_matrix[j][2] && call_matrix[j][2] != 0)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("[%s] ", state->group_array[k].groupName);
|
||
break;
|
||
}
|
||
else if (state->group_array[k].groupNumber == call_matrix[j][3] && call_matrix[j][3] != 0)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("[%s] ", state->group_array[k].groupName);
|
||
break;
|
||
}
|
||
}
|
||
//end test
|
||
printw ("\n");
|
||
}
|
||
|
||
}
|
||
} //end Call History
|
||
//fence bottom
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
attroff(COLOR_PAIR(4)); //cyan for history
|
||
}
|
||
|
||
refresh();
|
||
|
||
//keyboard shortcuts - codes same as ascii codes
|
||
if (c == 27) //esc key, open menu
|
||
{
|
||
if (opts->m17encoder == 0) //don't allow menu if using M17 encoder
|
||
ncursesMenu (opts, state);
|
||
}
|
||
|
||
//use k and l keys to test tg hold toggles on slots 1 and slots 2
|
||
if (c == 107) //'k' key, hold tg on slot 1 for trunking purposes, or toggle clear
|
||
{
|
||
if (state->tg_hold == 0)
|
||
state->tg_hold = state->lasttg;
|
||
else state->tg_hold = 0;
|
||
|
||
if ( (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1) && (state->tg_hold == 0) )
|
||
state->tg_hold = state->nxdn_last_tg;
|
||
|
||
else if (opts->frame_provoice == 1 && state->ea_mode == 0)
|
||
state->tg_hold = state->lastsrc;
|
||
}
|
||
|
||
if (c == 108) //'l' key, hold tg on slot 2 for trunking purposes, or toggle clear
|
||
{
|
||
if (state->tg_hold == 0)
|
||
state->tg_hold = state->lasttgR;
|
||
else state->tg_hold = 0;
|
||
}
|
||
|
||
//toggling when 48k/1 OSS still has some lag -- needed to clear out the buffer when switching
|
||
if (c == 49) // '1' key, toggle slot1 on
|
||
{
|
||
//switching, but want to control each seperately plz
|
||
if (opts->slot1_on == 1)
|
||
{
|
||
opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
||
// opts->slot_preference = 1; //slot 2
|
||
//clear any previously buffered audio
|
||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||
state->audio_out_idx2 = 0;
|
||
state->audio_out_idx = 0;
|
||
}
|
||
else if (opts->slot1_on == 0)
|
||
{
|
||
opts->slot1_on = 1;
|
||
if (opts->audio_out_type == 5) //OSS 48k/1
|
||
{
|
||
opts->slot_preference = 0; //slot 1
|
||
// opts->slot2_on = 0; //turn off slot 2
|
||
}
|
||
}
|
||
}
|
||
|
||
if (c == 50) // '2' key, toggle slot2 on
|
||
{
|
||
//switching, but want to control each seperately plz
|
||
if (opts->slot2_on == 1)
|
||
{
|
||
opts->slot2_on = 0;
|
||
opts->slot_preference = 0; //slot 1
|
||
//clear any previously buffered audio
|
||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||
memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
||
memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
||
state->audio_out_idx2R = 0;
|
||
state->audio_out_idxR = 0;
|
||
}
|
||
else if (opts->slot2_on == 0)
|
||
{
|
||
opts->slot2_on = 1;
|
||
if (opts->audio_out_type == 5) //OSS 48k/1
|
||
{
|
||
opts->slot_preference = 1; //slot 2
|
||
// opts->slot1_on = 0; //turn off slot 1
|
||
}
|
||
}
|
||
}
|
||
|
||
// if (c == 51) //'3' key, toggle slot preference on 48k/1
|
||
// {
|
||
// if (opts->slot_preference == 1) opts->slot_preference = 0;
|
||
// else opts->slot_preference = 1;
|
||
// }
|
||
|
||
if (c == 51) //'3' key, cycle slot preference
|
||
{
|
||
if (opts->slot_preference == 0 || opts->slot_preference == 1) opts->slot_preference++;
|
||
else opts->slot_preference = 0;
|
||
}
|
||
|
||
if (c == 43) //+ key, increment audio_gain
|
||
{
|
||
|
||
if (opts->audio_gain < 50)
|
||
opts->audio_gain++;
|
||
|
||
state->aout_gain = opts->audio_gain;
|
||
state->aout_gainR = opts->audio_gain;
|
||
|
||
opts->audio_gainR = opts->audio_gain;
|
||
|
||
}
|
||
|
||
if (c == 45) //- key, decrement audio_gain
|
||
{
|
||
|
||
if (opts->audio_gain > 0)
|
||
opts->audio_gain--;
|
||
|
||
state->aout_gain = opts->audio_gain;
|
||
state->aout_gainR = opts->audio_gain;
|
||
|
||
//reset to default on 0 for auto
|
||
if (opts->audio_gain == 0)
|
||
{
|
||
state->aout_gain = 25;
|
||
state->aout_gainR = 25;
|
||
}
|
||
|
||
opts->audio_gainR = opts->audio_gain;
|
||
|
||
}
|
||
|
||
if (c == 42) // * key, increment audio_gainA
|
||
{
|
||
if (opts->audio_gainA < 100)
|
||
opts->audio_gainA++;
|
||
}
|
||
|
||
if (c == 47) // / key, decrement audio_gainA
|
||
{
|
||
if (opts->audio_gainA > 0)
|
||
opts->audio_gainA--;
|
||
}
|
||
|
||
if (c == 122) //'z' key, toggle payload to console
|
||
{
|
||
if (opts->payload == 1) opts->payload = 0;
|
||
else opts->payload = 1;
|
||
}
|
||
|
||
if (c == 99) //'c' key, toggle compact mode
|
||
{
|
||
if (opts->ncurses_compact == 1) opts->ncurses_compact = 0;
|
||
else opts->ncurses_compact = 1;
|
||
}
|
||
|
||
if (c == 116) //'t' key, toggle trunking
|
||
{
|
||
if (opts->p25_trunk == 1) opts->p25_trunk = 0;
|
||
else opts->p25_trunk = 1;
|
||
}
|
||
|
||
if (c == 121) //'y' key, toggle scanner mode
|
||
{
|
||
if (opts->scanner_mode == 1) opts->scanner_mode = 0;
|
||
else opts->scanner_mode = 1;
|
||
opts->p25_trunk = 0; //turn off trunking mode
|
||
}
|
||
|
||
if (c == 97) //'a' key, toggle call alert beep
|
||
{
|
||
if (opts->call_alert == 1) opts->call_alert = 0;
|
||
else opts->call_alert = 1;
|
||
}
|
||
|
||
if (c == 104) //'h' key, toggle history
|
||
{
|
||
if (opts->ncurses_history == 1) opts->ncurses_history = 0;
|
||
else opts->ncurses_history = 1;
|
||
}
|
||
|
||
if (c == 113) //'q' key, quit
|
||
{
|
||
exitflag = 1;
|
||
}
|
||
|
||
if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr)
|
||
{
|
||
if (state->M == 1 || state->M == 0x21) state->M = 0;
|
||
else state->M = 1;
|
||
}
|
||
|
||
if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry
|
||
{
|
||
if (state->M == 1 || state->M == 0x21) state->M = 0;
|
||
else state->M = 0x21;
|
||
}
|
||
|
||
if (c == 105) //'i' key, toggle signal inversion on inverted types
|
||
{
|
||
//Set all signal for inversion or uninversion
|
||
if (opts->inverted_dmr == 0)
|
||
{
|
||
opts->inverted_dmr = 1;
|
||
opts->inverted_dpmr = 1;
|
||
opts->inverted_x2tdma = 1;
|
||
opts->inverted_ysf = 1;
|
||
opts->inverted_m17 = 1;
|
||
}
|
||
else
|
||
{
|
||
opts->inverted_dmr = 0;
|
||
opts->inverted_dpmr = 0;
|
||
opts->inverted_x2tdma = 0;
|
||
opts->inverted_ysf = 0;
|
||
opts->inverted_m17 = 0;
|
||
}
|
||
}
|
||
|
||
if (c == 109) //'m' key, toggle qpsk/c4fm - everything but phase 2
|
||
{
|
||
if (state->rf_mod == 0)
|
||
{
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 1;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
else
|
||
{
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
}
|
||
|
||
if (c == 77) //'M' key, toggle qpsk - phase 2 6000 sps
|
||
{
|
||
if (state->rf_mod == 0)
|
||
{
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 1;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 1;
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
}
|
||
else
|
||
{
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
}
|
||
}
|
||
|
||
if (c == 82) //'R', save symbol capture bin with date/time string as name
|
||
{
|
||
sprintf (opts->symbol_out_file, "%s %s.bin", getDateN(), timestr);
|
||
openSymbolOutFile (opts, state);
|
||
}
|
||
|
||
if (c == 114) //'r' key, stop capturing symbol capture bin file
|
||
{
|
||
if (opts->symbol_out_f)
|
||
{
|
||
closeSymbolOutFile (opts, state);
|
||
sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file);
|
||
}
|
||
}
|
||
|
||
#ifdef AERO_BUILD
|
||
//do nothing
|
||
#else
|
||
if (c == 32) //'space bar' replay last bin file (rework to do wav files too?)
|
||
{
|
||
struct stat stat_buf;
|
||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||
{
|
||
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||
goto SKIPR;
|
||
}
|
||
if (S_ISREG(stat_buf.st_mode))
|
||
{
|
||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||
opts->audio_in_type = 4; //symbol capture bin files
|
||
}
|
||
SKIPR: ; //do nothing
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
if (c == 80) //'P' key - start per call wav files
|
||
{
|
||
char wav_file_directory[1024];
|
||
sprintf (wav_file_directory, "./%s", opts->wav_out_dir);
|
||
wav_file_directory[1023] = '\0';
|
||
if (stat(wav_file_directory, &st_wav) == -1)
|
||
{
|
||
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);
|
||
}
|
||
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);
|
||
}
|
||
|
||
//this one could cause issues, but seems okay
|
||
if (c == 112) //'p' key - stop all per call wav files
|
||
{
|
||
//hope this one doesn't cause random crashing or garbage writing
|
||
closeWavOutFile (opts, state);
|
||
closeWavOutFileL (opts, state);
|
||
closeWavOutFileR (opts, state);
|
||
sprintf (opts->wav_out_file, "%s", "");
|
||
sprintf (opts->wav_out_fileR, "%s", "");
|
||
opts->dmr_stereo_wav = 0;
|
||
}
|
||
|
||
//
|
||
#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)
|
||
{
|
||
fclose(opts->symbolfile);
|
||
}
|
||
}
|
||
|
||
if (opts->audio_in_type == 2) //wav input file
|
||
{
|
||
sf_close(opts->audio_in_file);
|
||
}
|
||
|
||
if (opts->audio_out_type == 0)
|
||
{
|
||
opts->audio_in_type = 0;
|
||
openPulseInput(opts);
|
||
}
|
||
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
|
||
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;
|
||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
|
||
state->group_tally++;
|
||
|
||
//if we have an opened group file, let's write a group lock out into it to make it permanent
|
||
if (opts->group_in_file[0] != 0) //file is available
|
||
{
|
||
FILE * pFile; //file pointer
|
||
//open file by name that is supplied in the ncurses terminal, or cli
|
||
pFile = fopen (opts->group_in_file, "a");
|
||
fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttg, state->payload_algid);
|
||
fclose (pFile);
|
||
}
|
||
|
||
//extra safeguards due to sync issues with NXDN
|
||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||
|
||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||
|
||
//reset dmr blocks
|
||
dmr_reset_blocks (opts, state);
|
||
|
||
//zero out additional items
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->payload_algid = 0;
|
||
state->payload_algidR = 0;
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
state->payload_mi = 0;
|
||
state->payload_miR = 0;
|
||
state->payload_miP = 0;
|
||
state->payload_miN = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||
|
||
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||
//RIGCTL
|
||
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||
{
|
||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||
}
|
||
|
||
//rtl
|
||
#ifdef USE_RTLSDR
|
||
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq);
|
||
#endif
|
||
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 0)
|
||
{
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
|
||
}
|
||
|
||
if (state->lasttgR != 0 && opts->frame_provoice != 1 && c == 64) //SHIFT+'2' key (@ at sign), lockout slot 2 tdma tgR from tuning/playback during session
|
||
{
|
||
state->group_array[state->group_tally].groupNumber = state->lasttgR;
|
||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
|
||
state->group_tally++;
|
||
|
||
//if we have an opened group file, let's write a group lock out into it to make it permanent
|
||
if (opts->group_in_file[0] != 0) //file is available
|
||
{
|
||
FILE * pFile; //file pointer
|
||
//open file by name that is supplied in the ncurses terminal, or cli
|
||
pFile = fopen (opts->group_in_file, "a");
|
||
fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttgR, state->payload_algidR);
|
||
fclose (pFile);
|
||
}
|
||
|
||
//extra safeguards due to sync issues with NXDN
|
||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||
|
||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||
|
||
//reset dmr blocks
|
||
dmr_reset_blocks (opts, state);
|
||
|
||
//zero out additional items
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->payload_algid = 0;
|
||
state->payload_algidR = 0;
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
state->payload_mi = 0;
|
||
state->payload_miR = 0;
|
||
state->payload_miP = 0;
|
||
state->payload_miN = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||
|
||
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||
//RIGCTL
|
||
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||
{
|
||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||
}
|
||
|
||
//rtl
|
||
#ifdef USE_RTLSDR
|
||
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq);
|
||
#endif
|
||
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 0)
|
||
{
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc.
|
||
{
|
||
//dmr trunking/ncurses stuff
|
||
state->dmr_rest_channel = -1; //init on -1
|
||
state->dmr_mfid = -1; //
|
||
|
||
//dmr mfid branding and site parms
|
||
sprintf(state->dmr_branding_sub, "%s", "");
|
||
sprintf(state->dmr_branding, "%s", "");
|
||
sprintf (state->dmr_site_parms, "%s", "");
|
||
|
||
//DMR Location Area - DMRLA B***S***
|
||
opts->dmr_dmrla_is_set = 0;
|
||
opts->dmr_dmrla_n = 0;
|
||
|
||
//reset NXDN info
|
||
state->nxdn_location_site_code = 0;
|
||
state->nxdn_location_sys_code = 0;
|
||
sprintf (state->nxdn_location_category, "%s", " ");
|
||
|
||
state->nxdn_last_ran = -1; //0
|
||
state->nxdn_ran = 0; //0
|
||
|
||
state->nxdn_rcn = 0;
|
||
state->nxdn_base_freq = 0;
|
||
state->nxdn_step = 0;
|
||
state->nxdn_bw = 0;
|
||
|
||
}
|
||
|
||
//Debug/Troubleshooting Option
|
||
if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z)
|
||
{
|
||
// opts->p25_is_tuned = 0;
|
||
state->last_cc_sync_time = 0;
|
||
state->last_vc_sync_time = 0;
|
||
noCarrier(opts, state);
|
||
}
|
||
|
||
//attempt retry to TCP Audio server
|
||
if (c == 56) // '8' key, try audio in type 8 (TCP Audio Server connection) using defaults OR whatever the user last specified
|
||
{
|
||
|
||
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
|
||
if (opts->tcp_sockfd != 0)
|
||
{
|
||
//reset audio input stream
|
||
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
|
||
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
|
||
opts->audio_in_file_info->channels=1;
|
||
opts->audio_in_file_info->seekable=0;
|
||
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||
|
||
if(opts->tcp_file_in == NULL)
|
||
{
|
||
fprintf(stderr, "Error, couldn't Connect to TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||
}
|
||
else
|
||
{
|
||
//close pulse input if it is currently open
|
||
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");
|
||
}
|
||
|
||
if (c == 57) //'9' key, try rigctl connection with default values
|
||
{
|
||
//use same or last specified host for TCP audio sink for connection
|
||
memcpy (opts->rigctlhostname, opts->tcp_hostname, sizeof (opts->rigctlhostname) );
|
||
opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno);
|
||
if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1;
|
||
else opts->use_rigctl = 0;
|
||
}
|
||
|
||
//if trunking and user wants to just go back to the control channel and skip this call
|
||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && c == 67) //Capital C key - Return to CC
|
||
{
|
||
|
||
//extra safeguards due to sync issues with NXDN
|
||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||
|
||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||
|
||
//reset dmr blocks
|
||
dmr_reset_blocks (opts, state);
|
||
|
||
//zero out additional items
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->payload_algid = 0;
|
||
state->payload_algidR = 0;
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
state->payload_mi = 0;
|
||
state->payload_miR = 0;
|
||
state->payload_miP = 0;
|
||
state->payload_miN = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||
|
||
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||
//RIGCTL
|
||
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||
{
|
||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||
}
|
||
|
||
//rtl
|
||
#ifdef USE_RTLSDR
|
||
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq);
|
||
#endif
|
||
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 0)
|
||
{
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
|
||
//if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 1)
|
||
{
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
}
|
||
|
||
fprintf (stderr, "\n User Activated Return to CC; \n ");
|
||
|
||
}
|
||
|
||
//if trunking or scanning, manually cycle forward through channels loaded (can be run without trunking or scanning enabled)
|
||
if ( (opts->use_rigctl == 1 || opts->audio_in_type == 3) && c == 76) //Capital L key - Cycle Channels Forward
|
||
{
|
||
|
||
//extra safeguards due to sync issues with NXDN
|
||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||
|
||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||
|
||
//reset dmr blocks
|
||
dmr_reset_blocks (opts, state);
|
||
|
||
//zero out additional items
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->payload_algid = 0;
|
||
state->payload_algidR = 0;
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
state->payload_mi = 0;
|
||
state->payload_miR = 0;
|
||
state->payload_miP = 0;
|
||
state->payload_miN = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||
|
||
//just copy and pasted the cycle logic for CC/signal hunting on no sync
|
||
if (state->lcn_freq_roll >= state->lcn_freq_count) //fixed this to skip the extra wait out at the end of the list
|
||
{
|
||
state->lcn_freq_roll = 0; //reset to zero
|
||
}
|
||
|
||
//roll an extra value up if the current is the same as what's already loaded -- faster hunting on Cap+, etc
|
||
if (state->lcn_freq_roll != 0)
|
||
{
|
||
if (state->trunk_lcn_freq[state->lcn_freq_roll-1] == state->trunk_lcn_freq[state->lcn_freq_roll])
|
||
{
|
||
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)
|
||
{
|
||
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)
|
||
{
|
||
//rigctl
|
||
if (opts->use_rigctl == 1)
|
||
{
|
||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||
}
|
||
//rtl
|
||
if (opts->audio_in_type == 3)
|
||
{
|
||
#ifdef USE_RTLSDR
|
||
rtl_dev_tune (opts, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||
#endif
|
||
}
|
||
|
||
fprintf (stderr, "\n User Activated Channel Cycle;");
|
||
fprintf (stderr, " Tuning to Frequency: %.06lf MHz\n",
|
||
(double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000);
|
||
|
||
}
|
||
state->lcn_freq_roll++;
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
|
||
//may need to test to see if we want to do the conditional below or not for symbol rate flipping
|
||
|
||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 0)
|
||
{
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
|
||
//if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 1)
|
||
{
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
}
|
||
|
||
}
|
||
|
||
if (c == 118 && opts->audio_in_type == 3) //'v' key, cycle rtl volume multiplier, when active
|
||
{
|
||
if (opts->rtl_volume_multiplier == 1 || opts->rtl_volume_multiplier == 2) opts->rtl_volume_multiplier++;
|
||
else opts->rtl_volume_multiplier = 1;
|
||
}
|
||
|
||
if (c == 86) // 'V' Key, toggle LPF
|
||
{
|
||
if (opts->use_lpf == 0) opts->use_lpf = 1;
|
||
else opts->use_lpf = 0;
|
||
}
|
||
|
||
if (c == 66) // 'B' Key, toggle HPF
|
||
{
|
||
if (opts->use_hpf == 0) opts->use_hpf = 1;
|
||
else opts->use_hpf = 0;
|
||
}
|
||
|
||
if (c == 78) // 'N' Key, toggle PBF
|
||
{
|
||
if (opts->use_pbf == 0) opts->use_pbf = 1;
|
||
else opts->use_pbf = 0;
|
||
}
|
||
|
||
if (c == 72) // 'H' Key, toggle HPF on digital
|
||
{
|
||
if (opts->use_hpf_d == 0) opts->use_hpf_d = 1;
|
||
else opts->use_hpf_d = 0;
|
||
}
|
||
|
||
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
|
||
{
|
||
if (state->esk_mask == 0) state->esk_mask = 0xA0;
|
||
else state->esk_mask = 0;
|
||
}
|
||
|
||
if(opts->frame_provoice == 1 && c == 83) //'S' Key, toggle STD or EA mode and reset
|
||
{
|
||
if (state->ea_mode == -1) state->ea_mode = 0;
|
||
else if (state->ea_mode == 0) state->ea_mode = 1;
|
||
else state->ea_mode = 0;
|
||
|
||
//reset -- test to make sure these don't do weird things when reset
|
||
state->edacs_site_id = 0;
|
||
state->edacs_lcn_count = 0;
|
||
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;
|
||
state->lastsrc = 0;
|
||
|
||
}
|
||
|
||
//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
|
||
//needing an entry box, then stop all of those
|
||
|
||
//allocated memory pointer needs to be free'd each time
|
||
//if issues arise, just delete this line.
|
||
//TODO: Redo this in edacs and file, making a seperate char * timestr instead of calling GetTime
|
||
//directly from the sprintf command
|
||
free (timestr);
|
||
|
||
} //end ncursesPrinter
|
||
|
||
void ncursesClose ()
|
||
{
|
||
endwin();
|
||
|
||
}
|