Files
dsd-fme/src/dsd_ncurses.c

4962 lines
157 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*-------------------------------------------------------------------------------
* 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;
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);
}
}
}
time_t nowN;
int isCustomAfsString(dsd_state * state) {
return state->edacs_a_bits != 4 || state->edacs_f_bits != 4 || state->edacs_s_bits != 3;
}
//Get the string length we need for an AFS string, math-style
int getAfsStringLength(dsd_state * state) {
if (!isCustomAfsString(state))
return 6;
int length = 0;
length += (state->edacs_a_bits + 2) / 3;
length += (state->edacs_f_bits + 2) / 3;
length += (state->edacs_s_bits + 2) / 3;
length += 2; //colon separators
// This will be either 6 or 7
return length;
}
//Format the AFS string, Florida-style
int getAfsString(dsd_state * state, char * buffer, int a, int f, int s) {
if (!isCustomAfsString(state))
{
sprintf(buffer, "%02d-%02d%01d", a, f, s);
return 6;
}
int printed_chars = 0;
switch (state->edacs_a_bits)
{
case 1:
case 2:
case 3:
sprintf(buffer, "%01d:", a);
printed_chars += 1;
break;
case 4:
case 5:
case 6:
sprintf(buffer, "%02d:", a);
printed_chars += 2;
break;
case 7:
case 8:
case 9:
sprintf(buffer, "%03d:", a);
printed_chars += 3;
break;
}
sprintf(buffer + printed_chars, ":");
printed_chars++;
switch (state->edacs_f_bits) {
case 1:
case 2:
case 3:
sprintf(buffer + printed_chars, "%01d", f);
printed_chars += 1;
break;
case 4:
case 5:
case 6:
sprintf(buffer + printed_chars, "%02d", f);
printed_chars += 2;
break;
case 7:
case 8:
case 9:
sprintf(buffer + printed_chars, "%03d", f);
printed_chars += 3;
break;
}
sprintf(buffer + printed_chars, ":");
printed_chars++;
switch (state->edacs_s_bits) {
case 1:
case 2:
case 3:
sprintf(buffer + printed_chars, "%01d", s);
printed_chars += 1;
break;
case 4:
case 5:
case 6:
sprintf(buffer + printed_chars, "%02d", s);
printed_chars += 2;
break;
case 7:
case 8:
case 9:
sprintf(buffer + printed_chars, "%03d", s);
printed_chars += 3;
break;
}
return printed_chars;
}
//testing a few things, going to put this into ncursesMenu
#define WIDTH 36
#define HEIGHT 25
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)
{
char * timestr = getTime();
char * datestr = getDate();
sprintf (opts->wav_out_file, "%s %s DSD-FME-DECODED.wav", datestr, timestr);
if (timestr != NULL)
{
free (timestr);
timestr = NULL;
}
if (datestr != NULL)
{
free (datestr);
datestr = NULL;
}
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;
//for filenames (no colons, etc)
char * timestr = getTime();
char * datestr = getDate();
//NOTE: Any times associates with call history are stored
//in the array and need to be set by passing those values into
//getTimeN and getDateN
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 != 16 && (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
{
//setup a call string for the per call (group/private and/or emergency)
//No Space Skips / Truncates Needed on NXDN string variant
char cs[200]; memcpy (cs, state->call_string[0], 200*sizeof(char));
//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 - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, rn, tgn, src); //original
sprintf (opts->wav_out_file, "%s/%s %s NXDN - RAN %d - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, rn, cs, tgn, src); //with call string
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)
{
//setup a call string for the per call (group/private and/or emergency)
char cs[200]; memset (cs, 0, 200*sizeof(char));
int x = 0;
for (int i = 0; i < 200; i++)
{
//copy over non space and non termination values from call string
if (i != 0 && state->call_string[0][i] != ' ' && state->call_string[0][i] != 0)
cs[x++] = state->call_string[0][i];
}
cs[x] = 0; //terminate
//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, datestr, timestr, dcc, tg, rd); //original
sprintf (opts->wav_out_file, "%s/%s %s MS - CC %d - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, dcc, cs, tg, rd); //with cs call string
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)
{
//setup a call string for the per call (group/private and/or emergency)
char cs[200]; memset (cs, 0, 200*sizeof(char));
int x = 0;
for (int i = 0; i < 200; i++)
{
//copy over non space and non termination values from call string
if (i != 0 && state->call_string[0][i] != ' ' && state->call_string[0][i] != 0)
cs[x++] = state->call_string[0][i];
}
cs[x] = 0; //terminate
//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, datestr, timestr, dcc, tg, rd); //original
sprintf (opts->wav_out_file, "%s/%s %s CC %d - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, dcc, cs, tg, rd); //with call string
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)
{
//setup a call string for the per call (group/private and/or emergency)
char cs[200]; memset (cs, 0, 200*sizeof(char));
int x = 0;
for (int i = 0; i < 200; i++)
{
//copy over non space and non termination values from call string
if (i != 0 && state->call_string[1][i] != ' ' && state->call_string[1][i] != 0)
cs[x++] = state->call_string[1][i];
}
cs[x] = 0; //terminate
//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, datestr, timestr, dcc, tgR, rdR); //original
sprintf (opts->wav_out_fileR, "%s/%s %s CC %d - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, dcc, cs, tgR, rdR); //with call string
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)
{
//setup a call string for the per call (group/private and/or emergency)
char cs[200]; memset (cs, 0, 200*sizeof(char));
int x = 0;
for (int i = 0; i < 200; i++)
{
//copy over non space and non termination values from call string
if (i != 0 && state->call_string[0][i] != ' ' && state->call_string[0][i] != 0)
cs[x++] = state->call_string[0][i];
}
cs[x] = 0; //terminate
//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, datestr, timestr, nc, tg, rd); //original
sprintf (opts->wav_out_file, "%s/%s %s P1 - NAC %X - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, nc, cs, tg, rd); //with call string
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 == 3 && state->debug_mode == 1) printw (" DEBUG MODE!");
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->pa_input_idx[0] != 0)
printw (" D: %s;", opts->pa_input_idx);
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
if (opts->pa_output_idx[0] != 0)
printw (" D: %s;", opts->pa_output_idx);
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 (" |");
if (opts->pa_output_idx[0] != 0)
printw (" D: %s;", opts->pa_output_idx);
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
{
char afs_str[8];
getAfsString(state, afs_str, a, f, s);
printw ("\n| \\TG HOLD: %d [%s]; ", state->tg_hold, afs_str);
}
}
attron(COLOR_PAIR(4));
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
{
char afs_str[8];
getAfsString(state, afs_str, a, f, s);
printw ("\n| \\TG HOLD: %d [%s]; ", state->tg_hold, afs_str);
}
}
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)
{
// Group call
if ((call_matrix[i][4] & EDACS_IS_GROUP) != 0)
printw (" TGT [%8lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] );
// I-Call
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)
{
char afs_str[8];
getAfsString(state, afs_str, a, f, s);
printw (" TGT [%6lld][%s] SRC [%5lld]", call_matrix[i][2], afs_str, call_matrix[i][3] );
}
// I-Call
else if ((call_matrix[i][4] & EDACS_IS_INDIVIDUAL) != 0)
if (getAfsStringLength(state) == 6)
printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", call_matrix[i][2], call_matrix[i][3] );
else
printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", call_matrix[i][2], call_matrix[i][3] );
// System all-call
else if ((call_matrix[i][4] & EDACS_IS_ALL_CALL) != 0)
if (getAfsStringLength(state) == 6)
printw (" TGT [ SYSTEM ] SRC [%5lld] All-Call", call_matrix[i][3] );
else
printw (" TGT [ SYSTEM ] SRC [%5lld] All-Call", call_matrix[i][3] );
// Interconnect call
else if ((call_matrix[i][4] & EDACS_IS_INTERCONNECT) != 0)
if (getAfsStringLength(state) == 6)
printw (" TGT [ SYSTEM ] SRC [%5lld] Interconnect", call_matrix[i][3] );
else
printw (" TGT [ SYSTEM ] SRC [%5lld] Interconnect", call_matrix[i][3] );
// Test call
else if ((call_matrix[i][4] & EDACS_IS_TEST_CALL) != 0)
if (getAfsStringLength(state) == 6)
printw (" TGT [ SYSTEM ] SRC [ SYS ] Test Call");
else
printw (" TGT [ SYSTEM ] SRC [ SYS ] Test Call");
// Unknown call
else
printw (" Unknown call type" );
// Call flags
if ((call_matrix[i][4] & EDACS_IS_TEST_CALL) != 0) {}
else if ((call_matrix[i][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]");
else printw (" [Dig]");
if ((call_matrix[i][4] & EDACS_IS_AGENCY_CALL) != 0) printw ("[A]");
if ((call_matrix[i][4] & EDACS_IS_FLEET_CALL) != 0) printw ("[F]");
if ((call_matrix[i][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]");
}
// Data call
else
if (getAfsStringLength(state) == 6)
printw (" TGT [ DATA ] SRC [%5lld] Data", call_matrix[i][3] );
else
printw (" TGT [ DATA ] SRC [%5lld] Data", call_matrix[i][3] );
}
for (int k = 0; k < state->group_tally; k++)
{
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) //
{
char * timestrCH = getTimeN(call_matrix[9-j][5]);
char * datestrCH = getDateN(call_matrix[9-j][5]);
printw ("| ");
printw ("%s ", datestrCH);
printw ("%s ", timestrCH);
if (datestrCH != NULL)
{
free (datestrCH);
datestrCH = NULL;
}
if (timestrCH != NULL)
{
free (timestrCH);
timestrCH = NULL;
}
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 ("| ");
char * timestrCHE = getTimeN(call_matrix[j][5]);
char * datestrCHE = getDateN(call_matrix[j][5]);
printw ("%s ", datestrCHE);
printw ("%s ", timestrCHE);
if (datestrCHE != NULL)
{
free (datestrCHE);
datestrCHE = NULL;
}
if (timestrCHE != NULL)
{
free (timestrCHE);
timestrCHE = NULL;
}
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) {
char afs_str[8];
getAfsString(state, afs_str, a, f, s);
printw ("Target [%6lld][%s] Source [%5lld]", call_matrix[j][2], afs_str, call_matrix[j][3]);
}
// I-Call
else if ((call_matrix[j][4] & EDACS_IS_INDIVIDUAL) != 0)
if (getAfsStringLength(state) == 6)
printw ("Target [%6lld][ UNIT ] Source [%5lld] I-Call", call_matrix[j][2], call_matrix[j][3]);
else
printw ("Target [%6lld][ UNIT ] Source [%5lld] I-Call", call_matrix[j][2], call_matrix[j][3]);
// System all-call
else if ((call_matrix[j][4] & EDACS_IS_ALL_CALL) != 0)
if (getAfsStringLength(state) == 6)
printw ("Target [ SYSTEM ] Source [%5lld] All-Call", call_matrix[j][3]);
else
printw ("Target [ SYSTEM ] Source [%5lld] All-Call", call_matrix[j][3]);
// Interconnect
else if ((call_matrix[j][4] & EDACS_IS_INTERCONNECT) != 0)
if (getAfsStringLength(state) == 6)
printw ("Target [ SYSTEM ] Source [%5lld] Interconnect", call_matrix[j][3]);
else
printw ("Target [ SYSTEM ] Source [%5lld] Interconnect", call_matrix[j][3]);
// Test call
else if ((call_matrix[j][4] & EDACS_IS_TEST_CALL) != 0)
if (getAfsStringLength(state) == 6)
printw ("Target [ SYSTEM ] Source [ SYS ] Test Call");
else
printw ("Target [ SYSTEM ] Source [ SYS ] Test Call");
// Unknown call
else
printw ("Unknown call type");
// Call flags
if ((call_matrix[j][4] & EDACS_IS_TEST_CALL) != 0) {}
else if ((call_matrix[j][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]");
else printw (" [Dig]");
if ((call_matrix[j][4] & EDACS_IS_AGENCY_CALL) != 0) printw ("[A]");
if ((call_matrix[j][4] & EDACS_IS_FLEET_CALL) != 0) printw ("[F]");
if ((call_matrix[j][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]");
}
// Data call
else
if (getAfsStringLength(state) == 6)
printw ("Target [ DATA ] Source [%5lld] Data", call_matrix[j][3]);
else
printw ("Target [ DATA ] Source [%5lld] Data", call_matrix[j][3]);
}
//test
for (int k = 0; k < state->group_tally; k++)
{
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", datestr, 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
if (timestr != NULL)
{
free (timestr);
timestr = NULL;
}
if (datestr != NULL)
{
free (datestr);
datestr = NULL;
}
} //end ncursesPrinter
void ncursesClose ()
{
endwin();
}