3292 lines
100 KiB
C
3292 lines
100 KiB
C
/*-------------------------------------------------------------------------------
|
||
* dsd_ncurses.c
|
||
* DSD-FME ncurses terminal printer with menu system
|
||
*
|
||
* ASCII art generated by:
|
||
* https://fsymbols.com/generators/carty/
|
||
*
|
||
* LWVMOBILE
|
||
* 2022-08 DSD-FME Florida Man Edition
|
||
*-----------------------------------------------------------------------------*/
|
||
|
||
#include "dsd.h"
|
||
#include "git_ver.h"
|
||
|
||
//UDP Remote
|
||
#include <arpa/inet.h>
|
||
// #include <sys/socket.h>
|
||
#include <netinet/in.h>
|
||
|
||
#define BSIZE 999
|
||
#define UDP_BUFLEN 5 //maximum UDP buffer length
|
||
#define SRV_IP "127.0.0.1" //IP
|
||
#define UDP_PORT 6020 //UDP port
|
||
|
||
int handle; //for UDP
|
||
unsigned short udp_port = UDP_PORT;
|
||
char data[UDP_BUFLEN] = {0};
|
||
struct sockaddr_in address;
|
||
|
||
uint32_t temp_freq = -1;
|
||
//
|
||
|
||
//struct for checking existence of directory to write to
|
||
struct stat st_wav = {0};
|
||
|
||
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",
|
||
"DSTAR",
|
||
"NXDN VOICE",
|
||
"NXDN VOICE",
|
||
"DMR ", //10
|
||
"DMR ",
|
||
"DMR ",
|
||
"DMR ",
|
||
"EDACS/PV",
|
||
"EDACS/PV",
|
||
"NXDN VOICE", //DATA
|
||
"NXDN VOICE", //DATA
|
||
"DSTAR HD",
|
||
"DSTAR HD",
|
||
"dPMR", //20
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"NXDN",
|
||
"NXDN",
|
||
"YSF", //30
|
||
"YSF",
|
||
"DMR MS VOICE",
|
||
"DMR MS DATA",
|
||
"DMR RC DATA",
|
||
"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 ",
|
||
"MAC PTT", //20
|
||
"MAC ACTIVE", //21
|
||
"MAC HANGTIME", //22
|
||
"MAC PTT END", //23
|
||
"MAC IDLE", //24
|
||
"HDU",
|
||
"VOICE LDU", //26
|
||
"VOICE LDU",
|
||
"TDU/TDULC",
|
||
"TSBK",
|
||
"MAC SIGNAL",
|
||
"MAC SIGNAL"
|
||
|
||
};
|
||
|
||
|
||
void beeper (dsd_opts * opts, dsd_state * state, int type)
|
||
{
|
||
FILE *beep;
|
||
char wav_name[1024] = {0};
|
||
|
||
if (opts->pulse_digi_rate_out == 8000) strncpy(wav_name, "/usr/share/tone8.wav", 1023);
|
||
if (opts->pulse_digi_rate_out == 48000) strncpy(wav_name, "/usr/share/tone48.wav", 1023);
|
||
if (opts->pulse_digi_rate_out == 24000) strncpy(wav_name, "/usr/share/tone24.wav", 1023);
|
||
wav_name[1023] = '\0';
|
||
struct stat stat_buf;
|
||
if (stat(wav_name, &stat_buf) == 0)
|
||
{
|
||
beep = fopen (wav_name, "ro");
|
||
uint8_t buf[1024];
|
||
memset (buf, 0, sizeof(buf));
|
||
short blip = 0;
|
||
int loop = 1;
|
||
while (loop == 1)
|
||
{
|
||
fread(buf, sizeof(buf), 1, beep);
|
||
if ( feof (beep) )
|
||
{
|
||
loop = 0;
|
||
}
|
||
if (loop == 1)
|
||
{
|
||
//only beep on R if dmr_stereo is active and slot 2, else beep on L
|
||
if (type == 0 && opts->dmr_stereo == 1 && opts->audio_out == 1)
|
||
{
|
||
pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||
//fprintf (stderr, "BEEP 0 24\n");
|
||
}
|
||
if (type == 1 && opts->dmr_stereo == 1 && opts->audio_out == 1)
|
||
{
|
||
pa_simple_write(opts->pulse_digi_dev_outR, buf, sizeof(buf), NULL);
|
||
//fprintf (stderr, "BEEP 1 24\n");
|
||
}
|
||
if (opts->dmr_stereo == 0 && opts->audio_out == 1)
|
||
{
|
||
pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||
//fprintf (stderr, "BEEP 0 8\n");
|
||
}
|
||
|
||
|
||
}
|
||
|
||
}
|
||
|
||
fclose (beep);
|
||
}
|
||
|
||
}
|
||
|
||
char * getDateN(void) {
|
||
char datename[99]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
|
||
char * curr2;
|
||
struct tm * to;
|
||
time_t t;
|
||
t = time(NULL);
|
||
to = localtime( & t);
|
||
strftime(datename, sizeof(datename), "%Y-%m-%d", to);
|
||
curr2 = strtok(datename, " ");
|
||
return curr2;
|
||
}
|
||
|
||
time_t nowN;
|
||
char * getTimeN(void) //get pretty hh:mm:ss timestamp
|
||
{
|
||
time_t t = time(NULL);
|
||
|
||
char * curr;
|
||
char * stamp = asctime(localtime( & t));
|
||
|
||
curr = strtok(stamp, " ");
|
||
curr = strtok(NULL, " ");
|
||
curr = strtok(NULL, " ");
|
||
curr = strtok(NULL, " ");
|
||
|
||
return curr;
|
||
}
|
||
|
||
char * getDateC(time_t t) {
|
||
char datename[99]; //Ubuntu 32-bit, use 80; everything else, use 99
|
||
char * curr2;
|
||
struct tm * to;
|
||
|
||
to = localtime( & t);
|
||
strftime(datename, sizeof(datename), "%Y-%m-%d", to);
|
||
curr2 = strtok(datename, " ");
|
||
return curr2;
|
||
}
|
||
|
||
char * getTimeC(time_t t) //get pretty hh:mm:ss timestamp
|
||
{
|
||
char * curr;
|
||
char * stamp = asctime(localtime( & t));
|
||
|
||
curr = strtok(stamp, " ");
|
||
curr = strtok(NULL, " ");
|
||
curr = strtok(NULL, " ");
|
||
curr = strtok(NULL, " ");
|
||
|
||
return curr;
|
||
}
|
||
|
||
//testing a few things, going to put this into ncursesMenu
|
||
#define WIDTH 36
|
||
#define HEIGHT 23
|
||
|
||
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 (XDMA and NXDN)",
|
||
"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"
|
||
};
|
||
|
||
char *choices[] = {
|
||
"Resume Decoding",
|
||
"Decode Legacy Auto**",
|
||
"Decode XDMA (P25 and DMR BS/MS)",
|
||
"Decode D-STAR*",
|
||
"Decode P25-P1*",
|
||
"Decode EDACS/PV",
|
||
"Decode DMR Mono*",
|
||
"Decode dPMR",
|
||
"Decode NXDN48",
|
||
"Decode NXDN96",
|
||
"Decode DMR Stereo", //was X2-TDMA*
|
||
"Toggle Signal Inversion",
|
||
"Privacy 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_menub(WINDOW *menu_win, int highlight)
|
||
// {
|
||
// int x, y, i;
|
||
//
|
||
// x = 2;
|
||
// y = 2;
|
||
// box(menu_win, 0, 0);
|
||
// for(i = 0; i < n_choicesb; ++i)
|
||
// { if(highlight == i + 1) /* High light the present choice */
|
||
// { wattron(menu_win, A_REVERSE);
|
||
// mvwprintw(menu_win, y, x, "%s", choicesb[i]);
|
||
// wattroff(menu_win, A_REVERSE);
|
||
// }
|
||
// else
|
||
// mvwprintw(menu_win, y, x, "%s", choicesb[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)
|
||
{
|
||
// state->menuopen = 1; //flag the menu is open, stop processing getFrameSync
|
||
mbe_printVersion (versionstr);
|
||
setlocale(LC_ALL, "");
|
||
initscr(); //Initialize NCURSES screen window
|
||
start_color();
|
||
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
|
||
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);
|
||
}
|
||
|
||
if (opts->audio_in_type == 0) //close pulse input if it is the specified input method
|
||
{
|
||
closePulseInput(opts);
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
if (opts->audio_in_type == 5) //close UDP input SF file so we don't buffer audio while not decoding
|
||
{
|
||
sf_close(opts->udp_file_in); //disable for testing
|
||
}
|
||
|
||
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 = 0;
|
||
state->nxdn_last_rid = 0;
|
||
|
||
WINDOW *menu_win;
|
||
WINDOW *test_win;
|
||
WINDOW *entry_win;
|
||
WINDOW *info_win;
|
||
int highlight = 1;
|
||
int highlightb = 1;
|
||
int highlightc = 1;
|
||
int choice = 0;
|
||
int choiceb = 0;
|
||
int choicec = 0;
|
||
int c;
|
||
int d;
|
||
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);
|
||
|
||
//test print info boxes on side of certain options
|
||
if (highlight == 2)
|
||
{
|
||
info_win = newwin(6, WIDTH+18, starty, startx+20);
|
||
box (info_win, 0, 0);
|
||
mvwprintw(info_win, 2, 2, " Legacy Auto can only detect the following:");
|
||
mvwprintw(info_win, 3, 2, " P25-P1, D-STAR, DMR Mono, and X2-TDMA");
|
||
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, " XDMA Decoding Class Supports the following:");
|
||
mvwprintw(info_win, 3, 2, " P25-P1, P25-P2, and DMR Stereo BS/MS");
|
||
mvwprintw(info_win, 4, 2, " --C4FM / FSK4 only, and OP25 P2 Capture Bins");
|
||
wrefresh(info_win);
|
||
}
|
||
|
||
//Input Output Options
|
||
if (choice == 17)
|
||
{
|
||
//test making a new window while other window is open
|
||
test_win = newwin(HEIGHT-1, WIDTH+9, starty+5, startx+5);
|
||
keypad(menu_win, FALSE);
|
||
keypad(test_win, TRUE);
|
||
mvprintw(0, 0, "Input & Output Options ");
|
||
refresh();
|
||
print_menuc(test_win, highlightc);
|
||
while(1)
|
||
{ e = wgetch(test_win);
|
||
switch(e)
|
||
{ case KEY_UP:
|
||
if(highlightc == 1)
|
||
highlightc = n_choicesc;
|
||
else
|
||
--highlightc;
|
||
break;
|
||
case KEY_DOWN:
|
||
if(highlightc == n_choicesc)
|
||
highlightc = 1;
|
||
else
|
||
++highlightc;
|
||
break;
|
||
case 10:
|
||
choicec = highlightc;
|
||
break;
|
||
default:
|
||
//mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c);
|
||
refresh();
|
||
break;
|
||
}
|
||
print_menuc(test_win, highlightc);
|
||
if (choicec == 2)
|
||
{
|
||
sprintf (opts->wav_out_file, "%s %s DSD-FME-DECODED.wav", getDateN(), getTimeN());
|
||
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();
|
||
|
||
if (opts->symbol_out_file[0] != 0) //NULL
|
||
{
|
||
opts->symbol_out = 1; //set flag to 1
|
||
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, "./WAV");
|
||
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, "./WAV/DSD-FME-X1.wav");
|
||
sprintf (opts->wav_out_fileR, "./WAV/DSD-FME-X2.wav");
|
||
openWavOutFileL (opts, state);
|
||
openWavOutFileR (opts, state);
|
||
|
||
}
|
||
|
||
if (choicec == 6)
|
||
{
|
||
int confirm = 0;
|
||
|
||
#ifdef USE_RTLSDR
|
||
|
||
//could also benefit from having some control aside from UDP remote
|
||
//BUG: When squelch enabled, all processing halts, no more ncursesprinter until squelch broken
|
||
//make another submenu to control these values if tests go well
|
||
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter RTL Device Index Number");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_dev_index);
|
||
noecho();
|
||
|
||
//this is NOT scanning (or printing) in the variable for some reason...why?
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter RTL Device PPM Error");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtlsdr_ppm_error);
|
||
noecho();
|
||
//opts->rtlsdr_ppm_error = -1; //hard set override for testing
|
||
|
||
//apparently, scanning in an lld nukes later box entries for some reason
|
||
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); //ld, or lld?
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter VFO Bandwidth (6, 8, 12, 16, 24, 48)");
|
||
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, " Enter RTL Gain Value (0-49) (0 = Auto Gain)");
|
||
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, " Enter RTL UDP Remote Port (Default = 6020)");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_udp_port);
|
||
noecho();
|
||
if (opts->rtl_udp_port == 0)
|
||
{
|
||
opts->rtl_udp_port = 6020;
|
||
}
|
||
|
||
entry_win = newwin(8, WIDTH+22, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter RTL Device Squelch Level or Enter 0");
|
||
mvwprintw(entry_win, 3, 2, " WARNING! Renders Terminal Unresponsive When No Signal!");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_squelch_level);
|
||
noecho();
|
||
|
||
entry_win = newwin(17, 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", opts->rtl_dev_index);
|
||
mvwprintw(entry_win, 6, 2, " RTL Device VFO 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 Device UDP Port: %d", opts->rtl_udp_port);
|
||
mvwprintw(entry_win, 9, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error);
|
||
mvwprintw(entry_win, 10, 2, " RTL Device Squelch: %d", opts->rtl_squelch_level);
|
||
mvwprintw(entry_win, 12, 2, " Are You Sure?");
|
||
mvwprintw(entry_win, 13, 2, " 1 = Yes, 2 = No ");
|
||
mvwprintw(entry_win, 14, 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
|
||
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
|
||
}
|
||
|
||
#endif
|
||
|
||
}
|
||
|
||
if (choicec == 7) //RTL UDP 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); //ld, or lld?
|
||
noecho();
|
||
//do the thing with the thing
|
||
data[0] = 0;
|
||
data[1] = opts->rtlsdr_center_freq & 0xFF;
|
||
data[2] = (opts->rtlsdr_center_freq >> 8) & 0xFF;
|
||
data[3] = (opts->rtlsdr_center_freq >> 16) & 0xFF;
|
||
data[4] = (opts->rtlsdr_center_freq >> 24) & 0xFF;
|
||
|
||
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));
|
||
sprintf (opts->audio_in_dev, "%s", "pulse");
|
||
opts->audio_in_type = 0;
|
||
}
|
||
|
||
state->audio_smoothing = 0; //disable smoothing to prevent random crackling/buzzing
|
||
|
||
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
|
||
|
||
}
|
||
|
||
}
|
||
opts->audio_in_type = 0; //set after closing to prevent above crash condition
|
||
|
||
choicec = 18; //exit
|
||
}
|
||
|
||
if (choicec == 16) //stop/close last file RECORDING
|
||
{
|
||
if (opts->symbol_out == 1)
|
||
{
|
||
if (opts->symbol_out_file[0] != 0) //NULL
|
||
{
|
||
fclose(opts->symbol_out_f); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once
|
||
sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file); //swap output bin filename to input for quick replay
|
||
}
|
||
|
||
opts->symbol_out = 0; //set flag to 1
|
||
|
||
}
|
||
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 == 13)
|
||
{
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
short int option = 0;
|
||
entry_win = newwin(11, 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 Key Priority ");
|
||
mvwprintw(entry_win, 8, 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, "DMRA 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;
|
||
}
|
||
}
|
||
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();
|
||
|
||
}
|
||
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->K > 0x7FFF)
|
||
{
|
||
state->K = 0x7FFF;
|
||
}
|
||
}
|
||
//toggle enforcement of privacy key over enc bit set on traffic
|
||
if (option == 4)
|
||
{
|
||
if (state->M == 0)
|
||
{
|
||
state->M = 1;
|
||
}
|
||
else state->M = 0;
|
||
}
|
||
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 == 2)
|
||
{
|
||
//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 = 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 = 48000;
|
||
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->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, "D-STAR");
|
||
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 = 48000;
|
||
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->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 == 5)
|
||
{
|
||
//P25 P1
|
||
resetState (state); //use sparingly, may cause memory leak
|
||
opts->frame_p25p1 = 1;
|
||
opts->frame_p25p2 = 0;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "P25P1");
|
||
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 = 48000;
|
||
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->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
// state->rf_mod = 0;
|
||
opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
}
|
||
|
||
if (choice == 3)
|
||
{
|
||
//XDMA Stereo P25 1, 2, and DMR
|
||
resetState (state); //use sparingly, seems to cause issue when switching back to other formats
|
||
opts->frame_dmr = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "XDMA");
|
||
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 = 24000;
|
||
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 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
break;
|
||
}
|
||
if (choice == 7)
|
||
{
|
||
//set legacy DMR settings
|
||
resetState (state); //use sparingly, seems to cause issue when switching back to other formats
|
||
opts->frame_dmr = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "DMR Mono");
|
||
opts->dmr_mono = 1;
|
||
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 = 48000;
|
||
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->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 = 48000;
|
||
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->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 = 48000;
|
||
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->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 = 48000;
|
||
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->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 Stereo");
|
||
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 = 24000;
|
||
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->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
}
|
||
if (choice == 12)
|
||
{
|
||
//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;
|
||
}
|
||
else
|
||
{
|
||
opts->inverted_dmr = 0;
|
||
opts->inverted_dpmr = 0;
|
||
opts->inverted_x2tdma = 0;
|
||
opts->inverted_ysf = 0;
|
||
}
|
||
|
||
}
|
||
if (choice == 14) //reset call history (usually if janky output when switching modes)
|
||
{
|
||
for (short int k = 0; k <= 9; 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;
|
||
}
|
||
src = 0;
|
||
rn = 0;
|
||
tgn = 0;
|
||
dcc = 0;
|
||
tg = 0;
|
||
tgR = 0;
|
||
rd = 0;
|
||
rdR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
}
|
||
|
||
if (choice == 15) //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 == 16)
|
||
{
|
||
//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 == 18)
|
||
{
|
||
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 == 19)
|
||
{
|
||
ncursesClose();
|
||
//cleanup_rtlsdr_stream();
|
||
cleanupAndExit (opts, state);
|
||
}
|
||
|
||
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_in_type == 0) //reopen pulse input if it is the specified input method
|
||
{
|
||
openPulseInput(opts);
|
||
}
|
||
#ifdef USE_RTLSDR
|
||
if (opts->audio_in_type == 3) //open rtl input if it is the specified input method
|
||
{
|
||
ncursesPrinter (opts, state); //run one rep to clear menu boxes out
|
||
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);
|
||
}
|
||
|
||
}
|
||
#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);
|
||
}
|
||
|
||
if (opts->audio_in_type == 5) //re-open UDP input 'file'
|
||
{
|
||
opts->udp_file_in = sf_open_fd(opts->udp_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)
|
||
{
|
||
int level = 0;
|
||
int c = 0;
|
||
|
||
if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN -
|
||
{
|
||
timeout(0);
|
||
c = getch();
|
||
}
|
||
|
||
//use rtl_udp_tune
|
||
#ifdef USE_RTLSDR
|
||
if (temp_freq == opts->rtlsdr_center_freq)
|
||
{
|
||
rtl_udp_tune (opts, state, 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
|
||
if (state->nxdn_last_rid > 0 && state->nxdn_last_rid != src);
|
||
{
|
||
src = state->nxdn_last_rid;
|
||
}
|
||
if (state->nxdn_last_ran > -1 && state->nxdn_last_ran != rn);
|
||
{
|
||
rn = state->nxdn_last_ran;
|
||
}
|
||
if (state->nxdn_last_tg > 0 && state->nxdn_last_tg != tgn);
|
||
{
|
||
tgn = state->nxdn_last_tg;
|
||
}
|
||
|
||
//DMR CC
|
||
if (state->color_code_ok && state->dmr_color_code != -1 && (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32 || lls == 33) )
|
||
{
|
||
dcc = state->dmr_color_code;
|
||
}
|
||
|
||
//DMR SRC
|
||
if ( (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32) )
|
||
//if ( (lls == 12 || lls == 11 || lls == 32) )
|
||
{
|
||
//if (state->dmrburstL == 16 && state->lastsrc > 0) //state->currentslot == 0 &&
|
||
if (state->lastsrc > 0)
|
||
{
|
||
rd = state->lastsrc;
|
||
}
|
||
|
||
//if (state->dmrburstR == 16 && state->lastsrcR > 0) //state->currentslot == 1 &&
|
||
if (state->lastsrcR > 0)
|
||
{
|
||
rdR = state->lastsrcR;
|
||
}
|
||
|
||
}
|
||
|
||
//DMR TG
|
||
if ( (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32) )
|
||
//if ( (lls == 12 || lls == 11 || lls == 32) )
|
||
{
|
||
//if (state->dmrburstL == 16 && state->lasttg > 0) //state->currentslot == 0 &&
|
||
if (state->lasttg > 0)
|
||
{
|
||
tg = state->lasttg;
|
||
}
|
||
|
||
//if (state->dmrburstR == 16 && state->lasttgR > 0) //state->currentslot == 1 &&
|
||
if (state->lasttgR > 0)
|
||
{
|
||
tgR = state->lasttgR;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//P25 P1 and VCH0
|
||
if (state->p2_cc > 0)
|
||
{
|
||
nc = state->p2_cc;
|
||
}
|
||
if ( state->lasttg > 0 && (lls == 0 || lls == 1 || lls == 35 || lls == 36) )
|
||
{
|
||
tg = state->lasttg;
|
||
}
|
||
if ( state->lastsrc > 0 && (lls == 0 || lls == 1 || lls == 35 || lls == 36) )
|
||
{
|
||
rd = state->lastsrc;
|
||
}
|
||
//P25 P2 VCH2
|
||
if (state->lasttgR > 0 && (lls == 35 || lls == 36) )
|
||
{
|
||
tgR = state->lasttgR;
|
||
}
|
||
if (state->lastsrcR > 0 && (lls == 35 || lls == 36) )
|
||
{
|
||
rdR = state->lastsrcR;
|
||
}
|
||
//P25 P2 NAC to dcc for matrix shim
|
||
if (state->p2_cc > 0 && (lls == 35 || lls == 36) )
|
||
{
|
||
dcc = state->p2_cc;
|
||
}
|
||
|
||
//Call History Matrix Shuffling
|
||
//Edacs - ProVoice
|
||
if ( (lls == 14 || lls == 15 || lls == 37 || lls == 38) && state->carrier == 1)
|
||
{
|
||
|
||
if (state->edacs_vc_lcn != -1)
|
||
{
|
||
call_matrix[state->edacs_vc_lcn][0] = lls;
|
||
call_matrix[state->edacs_vc_lcn][1] = state->edacs_vc_lcn;
|
||
call_matrix[state->edacs_vc_lcn][2] = state->lasttg;
|
||
call_matrix[state->edacs_vc_lcn][3] = state->lastsrc;
|
||
call_matrix[state->edacs_vc_lcn][4] = 1;
|
||
call_matrix[state->edacs_vc_lcn][5] = time(NULL);
|
||
}
|
||
|
||
}
|
||
|
||
//D-STAR, work on adding the headers later
|
||
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
|
||
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];
|
||
}
|
||
call_matrix[9][0] = lls;
|
||
call_matrix[9][1] = rn;
|
||
call_matrix[9][2] = src;
|
||
call_matrix[9][3] = 0;
|
||
call_matrix[9][4] = tgn;
|
||
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 && src != 0 ) //&& tgn != 0, some TG can be 0 on NXDN
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileL (opts, state);
|
||
sprintf (opts->wav_out_file, "./WAV/%s %s NXDN - RAN %d - TGT %d - SRC %d.wav", getDateN(), getTimeN(), rn, tgn, src);
|
||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1)
|
||
{
|
||
beeper (opts, state, 0);
|
||
}
|
||
|
||
}
|
||
|
||
//DMR MS
|
||
if ( call_matrix[9][2] != rd && lls == 32)
|
||
{
|
||
|
||
for (short int k = 0; k < 10; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
}
|
||
|
||
call_matrix[9][0] = lls;
|
||
call_matrix[9][1] = tg;
|
||
call_matrix[9][2] = rd;
|
||
call_matrix[9][3] = 1; //hard set slot number
|
||
call_matrix[9][4] = dcc;
|
||
call_matrix[9][5] = time(NULL);
|
||
|
||
//open wav file if enabled and both rd and tg are not 0
|
||
if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileL (opts, state);
|
||
sprintf (opts->wav_out_file, "./WAV/%s %s MS - CC %d - TG %d - RD %d.wav", getDateN(), getTimeN(), dcc, tg, rd);
|
||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//fprintf (stderr, "BEEP 0 MS LEFT\n");
|
||
beeper (opts, state, 0);
|
||
state->dmr_end_alert[0] = 0; //new voice frame, okay to beep at the end of it
|
||
}
|
||
|
||
memset(state->dmr_alias_block_segment[0], 0, sizeof(state->dmr_alias_block_segment[0]));
|
||
sprintf (state->dmr_embedded_gps[0], "%s", "");
|
||
|
||
}
|
||
|
||
//DMR BS Slot 1 - matrix 0-4
|
||
if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) )
|
||
{
|
||
|
||
for (short int k = 0; k < 4; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
}
|
||
|
||
call_matrix[4][0] = lls;
|
||
call_matrix[4][1] = tg;
|
||
call_matrix[4][2] = rd;
|
||
call_matrix[4][3] = 1; //hard set slot number
|
||
call_matrix[4][4] = dcc;
|
||
call_matrix[4][5] = time(NULL);
|
||
|
||
//open wav file if enabled and both rd and tg are not 0
|
||
if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileL (opts, state);
|
||
|
||
sprintf (opts->wav_out_file, "./WAV/%s %s CC %d - TG %d - RD %d.wav", getDateN(), getTimeN(), dcc, tg, rd);
|
||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//fprintf (stderr, "BEEP 0 BS LEFT\n");
|
||
beeper (opts, state, 0);
|
||
state->dmr_end_alert[0] = 0; //new voice frame, okay to beep at the end of it
|
||
}
|
||
|
||
memset(state->dmr_alias_block_segment[0], 0, sizeof(state->dmr_alias_block_segment[0]));
|
||
sprintf (state->dmr_embedded_gps[0], "%s", "");
|
||
|
||
}
|
||
|
||
//DMR BS Slot 2 - matrix 5-9
|
||
if ( call_matrix[9][2] != rdR && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) )
|
||
{
|
||
|
||
for (short int k = 5; k < 9; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
}
|
||
|
||
call_matrix[9][0] = lls;
|
||
call_matrix[9][1] = tgR;
|
||
call_matrix[9][2] = rdR;
|
||
call_matrix[9][3] = 2; //hard set slot number
|
||
call_matrix[9][4] = dcc;
|
||
call_matrix[9][5] = time(NULL);
|
||
|
||
//open wav file if enabled and both rdR and tgR are not 0
|
||
if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0)
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileR (opts, state);
|
||
sprintf (opts->wav_out_fileR, "./WAV/%s %s CC %d - TG %d - RD %d.wav", getDateN(), getTimeN(), dcc, tgR, rdR);
|
||
openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
||
{
|
||
//fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
||
beeper (opts, state, 1);
|
||
state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it
|
||
}
|
||
|
||
memset(state->dmr_alias_block_segment[1], 0, sizeof(state->dmr_alias_block_segment[1]));
|
||
sprintf (state->dmr_embedded_gps[1], "%s", "");
|
||
|
||
}
|
||
|
||
//P25 P1
|
||
if ( (lls == 0 || lls == 1) && call_matrix[9][2] != rd && nc > 0 && tg > 0 && state->dmrburstL == 26)
|
||
{
|
||
for (short int k = 0; k < 9; k++)
|
||
{
|
||
call_matrix[k][0] = call_matrix[k+1][0];
|
||
call_matrix[k][1] = call_matrix[k+1][1];
|
||
call_matrix[k][2] = call_matrix[k+1][2];
|
||
call_matrix[k][3] = call_matrix[k+1][3];
|
||
call_matrix[k][4] = call_matrix[k+1][4];
|
||
call_matrix[k][5] = call_matrix[k+1][5];
|
||
}
|
||
|
||
call_matrix[9][0] = lls;
|
||
call_matrix[9][1] = tg;
|
||
call_matrix[9][2] = rd;
|
||
call_matrix[9][3] = 0;
|
||
call_matrix[9][4] = nc;
|
||
call_matrix[9][5] = time(NULL);
|
||
|
||
//open wav file if enabled and both rd and tg are not 0
|
||
if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||
{
|
||
//close old first, assign name based on time and radio, open wav file
|
||
closeWavOutFileL (opts, state);
|
||
sprintf (opts->wav_out_file, "./WAV/%s %s P1 - NAC %X - TGT %d - SRC %d.wav", getDateN(), getTimeN(), nc, tg, rd);
|
||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||
}
|
||
|
||
if (opts->call_alert == 1)
|
||
{
|
||
beeper (opts, state, 0);
|
||
}
|
||
|
||
}
|
||
|
||
//Remus DMR End Call Alert Beep
|
||
// if (opts->call_alert == 1)
|
||
// {
|
||
// if (state->dmrburstL == 2 && state->dmr_end_alert[0] == 0) //if TLC and flag not tripped
|
||
// {
|
||
// beeper (opts, state, 0);
|
||
// state->dmr_end_alert[0] = 1; //don't play again until new voice frames
|
||
// state->lasttg = 0;
|
||
// state->lastsrc = 0;
|
||
// rd = 0;
|
||
// tg = 0;
|
||
// }
|
||
// if (state->dmrburstR == 2 && state->dmr_end_alert[1] == 0) //if TLC and flag not tripped
|
||
// {
|
||
// beeper (opts, state, 1);
|
||
// state->dmr_end_alert[1] = 1; //don't play again until new voice frames
|
||
// state->lasttgR = 0;
|
||
// state->lastsrcR = 0;
|
||
// rdR = 0;
|
||
// tgR = 0;
|
||
// }
|
||
// }
|
||
|
||
//Start Printing Section
|
||
erase();
|
||
if (opts->ncurses_compact == 1)
|
||
{
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
printw ("| Digital Speech Decoder: Florida Man Edition %s \n", GIT_TAG);
|
||
}
|
||
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 == 5) printw (" MBElib %s", versionstr);
|
||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||
else printw ("\n");
|
||
}
|
||
attroff(COLOR_PAIR(6)); //6
|
||
attron(COLOR_PAIR(4));
|
||
}
|
||
|
||
printw ("--Input Output----------------------------------------------------------------\n");
|
||
if (opts->audio_in_type == 0)
|
||
{
|
||
printw ("| Pulse Audio Input: [%2i] kHz [%i] Channel\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels);
|
||
}
|
||
if (opts->audio_in_type == 4)
|
||
{
|
||
printw ("| Direct Symbol Bin Input: %s \n", opts->audio_in_dev);
|
||
}
|
||
|
||
if (opts->audio_in_type == 8)
|
||
{
|
||
printw ("| Direct TCP Input: Port [%d] Sample Rate [%d] \n", opts->tcp_portno, opts->wav_sample_rate);
|
||
}
|
||
|
||
if (opts->audio_in_type == 2)
|
||
{
|
||
printw ("| Direct WAV File Input: %s Sample Rate [%d] \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 ("| RTL2838UHIDIR Device #[%d]", opts->rtl_dev_index);
|
||
printw (" Gain [%i] dB -", opts->rtl_gain_value);
|
||
printw (" Squelch [%i]", opts->rtl_squelch_level);
|
||
printw (" VFO [%i] kHz\n", opts->rtl_bandwidth);
|
||
printw ("| Freq: [%d] Hz", opts->rtlsdr_center_freq); //%lld
|
||
printw (" - Tuning available on UDP Port [%i]\n", opts->rtl_udp_port);
|
||
}
|
||
if (opts->audio_out_type == 0)
|
||
{
|
||
printw ("| Pulse Audio Output: [%2i] kHz [%i] Channel", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels);
|
||
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
||
printw (" \n");
|
||
}
|
||
if (opts->monitor_input_audio == 1)
|
||
{
|
||
printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected\n");
|
||
}
|
||
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_file_raw[0] != 0 && opts->audio_in_type == 0)
|
||
{
|
||
printw ("| Appending Raw Sig Audio WAV to file %s\n", opts->wav_out_file_raw);
|
||
}
|
||
if (opts->symbol_out_file[0] != 0 && opts->symbol_out == 1)
|
||
{
|
||
printw ("| SymbolC Bin: %s\n", opts->symbol_out_file);
|
||
}
|
||
if (opts->wav_out_file[0] != 0 && opts->dmr_stereo_wav == 0)
|
||
{
|
||
printw ("| Decoded WAV: %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);
|
||
}
|
||
if (opts->use_rigctl == 1)
|
||
{
|
||
printw ("| RIGCTL Remote Control Client Established on Port [%d]\n", opts->rigctlportno);
|
||
}
|
||
if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) )
|
||
{
|
||
printw ("| Trunk Tracking Active -");
|
||
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));
|
||
printw (" Calls");
|
||
if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n");
|
||
else printw (" - Black List Mode\n");
|
||
}
|
||
if (opts->reverse_mute == 1)
|
||
{
|
||
printw ("| Reverse Mute - Muting Unencrypted Voice\n");
|
||
}
|
||
if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n");
|
||
if (state->M == 1) printw ("| Forcing Key Priority -- Key: %lld \n", state->R);
|
||
if (opts->scanner_mode == 1)
|
||
{
|
||
printw ("| Fast Scan Mode Enabled ");
|
||
if (state->trunk_lcn_freq[state->lcn_freq_roll]) //this is a workaround to fix freq of 0 during roll reset
|
||
printw (" - Frequency: [%.06lf] Mhz \n", (double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000);
|
||
else printw (" - Frequency: [%.06lf] Mhz \n", (double)state->trunk_lcn_freq[0]/1000000);
|
||
}
|
||
|
||
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
|
||
reset = 1;
|
||
}
|
||
if (state->carrier == 0 && opts->reset_state == 1 && reset == 1)
|
||
{
|
||
resetState (state);
|
||
reset = 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);
|
||
printw ("| Decoding: [%s] \n", opts->output_name);
|
||
printw ("| In Level: [%02d%%] \n", level);
|
||
if (opts->dmr_stereo == 0)
|
||
{
|
||
printw ("| Voice Error: [%i][%i] \n", state->errs, state->errs2);
|
||
}
|
||
|
||
if (opts->dmr_stereo == 1)
|
||
{
|
||
printw ("| Voice ErrS1: [%i][%i] \n", state->errs, state->errs2);
|
||
printw ("| Voice ErrS2: [%i][%i] \n", state->errsR, state->errs2R);
|
||
}
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
|
||
printw ("--Call Info-------------------------------------------------------------------\n");
|
||
//DSTAR...what a pain...
|
||
if (lls == 6 || lls == 7 || lls == 18 || lls == 19)
|
||
{
|
||
if (state->dstarradioheader[3] != 0) //
|
||
{
|
||
printw ("| RPT 2: [%c%c%c%c%c%c%c%c] ", state->dstarradioheader[3], state->dstarradioheader[4],
|
||
state->dstarradioheader[5], state->dstarradioheader[6], state->dstarradioheader[7], state->dstarradioheader[8],
|
||
state->dstarradioheader[9], state->dstarradioheader[10]);
|
||
printw ("RPT 1: [%c%c%c%c%c%c%c%c] \n| ", state->dstarradioheader[11], state->dstarradioheader[12],
|
||
state->dstarradioheader[13], state->dstarradioheader[14], state->dstarradioheader[15], state->dstarradioheader[16],
|
||
state->dstarradioheader[17], state->dstarradioheader[18]);
|
||
printw ("YOUR: [%c%c%c%c%c%c%c%c] ", state->dstarradioheader[19], state->dstarradioheader[20],
|
||
state->dstarradioheader[21], state->dstarradioheader[22], state->dstarradioheader[23], state->dstarradioheader[24],
|
||
state->dstarradioheader[25], state->dstarradioheader[26]);
|
||
printw ("MY: [%c%c%c%c%c%c%c%c] [%c%c%c%c]\n", state->dstarradioheader[27],
|
||
state->dstarradioheader[28], state->dstarradioheader[29], state->dstarradioheader[30], state->dstarradioheader[31],
|
||
state->dstarradioheader[32], state->dstarradioheader[33], state->dstarradioheader[34], state->dstarradioheader[35],
|
||
state->dstarradioheader[36], state->dstarradioheader[37], state->dstarradioheader[38]);
|
||
}
|
||
}
|
||
|
||
//NXDN
|
||
if (lls == 28 || lls == 29)
|
||
{
|
||
|
||
if (opts->p25_trunk == 1)
|
||
{
|
||
|
||
printw ("| ");
|
||
if (opts->p25_is_tuned == 0)
|
||
{
|
||
printw ("Monitoring Control Channel");
|
||
if (state->p25_cc_freq != 0)
|
||
{
|
||
printw (" - CC Freq: [%.06lf] Mhz ", (double)state->p25_cc_freq/1000000);
|
||
}
|
||
}
|
||
else if (opts->p25_is_tuned == 1)
|
||
{
|
||
printw ("Monitoring Voice Channel");
|
||
if (state->p25_vc_freq[0] != 0)
|
||
{
|
||
printw (" - VC Freq: [%.06lf] Mhz ", (double)state->p25_vc_freq[0]/1000000);
|
||
}
|
||
}
|
||
|
||
printw ("\n");
|
||
|
||
}
|
||
|
||
printw ("| ");
|
||
printw ("NXDN - RAN: [%02d] ", rn);
|
||
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);
|
||
}
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("TGT: [%5d] ", tgn);
|
||
printw ("SRC: [%5d] ", src);
|
||
if (state->nxdn_alias_block_segment[0][0] > 0)
|
||
{
|
||
printw ("ALIAS: [");
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
for (int j = 0; j < 4; j++)
|
||
{
|
||
printw ("%s", state->nxdn_alias_block_segment[i][j]);
|
||
}
|
||
}
|
||
printw ("]");
|
||
}
|
||
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)
|
||
{
|
||
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));
|
||
}
|
||
}
|
||
if (state->nxdn_cipher_type == 0x2 && state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("IV: [%016llX] ", state->payload_miN);
|
||
attron(COLOR_PAIR(2));
|
||
printw ("DES-OFB ");
|
||
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));
|
||
}
|
||
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 Channel: [%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 ("P25 P1 - [%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 ("P25 P2 - [%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));
|
||
}
|
||
|
||
//REMUS! THIS IS THE OLD ONE
|
||
// printw ("FID: [%02X] SVC: [%02X] ", state->dmr_fid, state->dmr_so);
|
||
//This is the new one
|
||
printw ("%s | ", state->call_string[0]);
|
||
printw ("%s ", DMRBusrtTypes[state->dmrburstL]);
|
||
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));
|
||
}
|
||
|
||
if (state->payload_algid == 0xAA || state->payload_algid == 0x21)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("ADP-RC4");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x81 || state->payload_algid == 0x22)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES-OFB");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x83 || state->payload_algid == 0x23)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("Triple DES");
|
||
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));
|
||
}
|
||
|
||
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) //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 //&& opts->p25_trunk == 0
|
||
{
|
||
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] //Don't print on MS mode
|
||
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));
|
||
}
|
||
|
||
//REMUS! THIS IS THE OLD ONE
|
||
// printw ("FID: [%02X] SVC: [%02X] ", state->dmr_fidR, state->dmr_soR);
|
||
//THIS IS THE NEW ONE
|
||
printw ("%s | ", state->call_string[1]);
|
||
printw ("%s ", DMRBusrtTypes[state->dmrburstR]);
|
||
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));
|
||
}
|
||
if (state->payload_algidR == 0xAA || state->payload_algidR == 0x21)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("ADP-RC4");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x81 || state->payload_algidR == 0x22)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES-OFB");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x83 || state->payload_algidR == 0x23)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("Triple DES");
|
||
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));
|
||
}
|
||
//Call Types, may switch to the more robust version later?
|
||
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) //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 //&& opts->p25_trunk == 0
|
||
{
|
||
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 ("| T INFO | ");
|
||
|
||
// 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);
|
||
}
|
||
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++)
|
||
{
|
||
//shim 443 afs in here for display purposes
|
||
int a = (call_matrix[i][3] >> 7) & 0xF;
|
||
int fs = call_matrix[i][3] & 0x7F;
|
||
printw ("| - LCN [%02d][%.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));
|
||
}
|
||
//print active calls on corresponding LCN line
|
||
if ((i != state->edacs_cc_lcn) && time(NULL) - call_matrix[i][5] < 2)
|
||
{
|
||
attron (COLOR_PAIR(3));
|
||
if (state->ea_mode == 1) printw (" TG [%5lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] );
|
||
else printw (" AFS [%3llX][%02d-%03d]", call_matrix[i][3], a, fs );
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == call_matrix[i][2])
|
||
{
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s]", state->group_array[k].groupMode);
|
||
}
|
||
}
|
||
attroff (COLOR_PAIR(3));
|
||
}
|
||
//print dying or dead calls in red for x seconds longer
|
||
if ( (i != state->edacs_cc_lcn) && (time(NULL) - call_matrix[i][5] >= 2) && (time(NULL) - call_matrix[i][5] < 5) )
|
||
{
|
||
attron (COLOR_PAIR(2));
|
||
if (state->ea_mode == 1) printw (" TG [%5lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] );
|
||
else printw (" AFS [%3llX][%02d-%03d]", call_matrix[i][3], a, fs );
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == call_matrix[i][2])
|
||
{
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s]", state->group_array[k].groupMode);
|
||
}
|
||
}
|
||
attroff (COLOR_PAIR(2));
|
||
}
|
||
if (i == state->edacs_tuned_lcn && opts->p25_is_tuned == 1) printw (" **T**"); //asterisk which lcn is opened
|
||
printw ("\n");
|
||
}
|
||
if (state->carrier == 1)
|
||
{
|
||
attron (COLOR_PAIR(3));
|
||
}
|
||
}
|
||
|
||
|
||
if (lls == 6 || lls == 7 || lls == 18 || lls == 19)
|
||
{
|
||
printw ("| %s ", SyncTypes[lls]);
|
||
//printw ("%s", state->dmr_branding);
|
||
printw ("\n");
|
||
}
|
||
//fence bottom
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
//colors off
|
||
if (state->carrier == 1){ //same as above
|
||
attroff(COLOR_PAIR(3));
|
||
}
|
||
//only print call history if enabled
|
||
if (opts->ncurses_history == 1)
|
||
{
|
||
attron(COLOR_PAIR(4)); //cyan for history
|
||
printw ("--Call History----------------------------------------------------------------\n");
|
||
for (short int j = 0; j < 10; j++)
|
||
{
|
||
//only print if a valid time was assigned to the matrix, and not EDACS/PV, and source is not zero
|
||
if ( ((time(NULL) - call_matrix[9-j][5]) < 999999) && call_matrix[9-j][0] != 14 && call_matrix[9-j][0] != 15 && call_matrix[9-j][0] != 37 && call_matrix[9-j][0] != 38 && call_matrix[9-j][2] != 0) //
|
||
{
|
||
printw ("| %s ", SyncTypes[call_matrix[9-j][0]]);
|
||
if (lls == 28 || lls == 29)
|
||
{
|
||
printw ("RAN [%02lld] ", call_matrix[9-j][1]);
|
||
printw ("TG [%5lld] ", call_matrix[9-j][4]);
|
||
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[%d] ", 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]);
|
||
}
|
||
|
||
printw ("%s ", getDateC(call_matrix[9-j][5]) ); //You're welcome
|
||
printw ("%s \n", getTimeC(call_matrix[9-j][5]) ); //Remus
|
||
}
|
||
|
||
//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][3] != 0)
|
||
{
|
||
printw ("| %s ", SyncTypes[call_matrix[j][0]]);
|
||
printw ("LCN [%2lld] ", call_matrix[j][1]);
|
||
printw ("Group [%8lld] ", call_matrix[j][2]);
|
||
printw ("Source [%8lld] ", call_matrix[j][3]);
|
||
printw ("%s ", getDateC(call_matrix[j][5]) );
|
||
printw ("%s \n", getTimeC(call_matrix[j][5]) );
|
||
}
|
||
|
||
}
|
||
} //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
|
||
{
|
||
ncursesMenu (opts, state); //just a quick test
|
||
}
|
||
|
||
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 mode
|
||
{
|
||
if (opts->p25_trunk == 1) opts->p25_trunk = 0;
|
||
else opts->p25_trunk = 1;
|
||
opts->scanner_mode = 0; //turn off scanner mode
|
||
}
|
||
|
||
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
|
||
{
|
||
ncursesClose();
|
||
cleanupAndExit (opts, state);
|
||
}
|
||
|
||
if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr)
|
||
{
|
||
if (state->M == 1) state->M = 0;
|
||
else state->M = 1;
|
||
}
|
||
|
||
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;
|
||
}
|
||
else
|
||
{
|
||
opts->inverted_dmr = 0;
|
||
opts->inverted_dpmr = 0;
|
||
opts->inverted_x2tdma = 0;
|
||
opts->inverted_ysf = 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 = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
}
|
||
|
||
if (c == 82) //'R', save symbol capture bin with date/time string as name
|
||
{
|
||
sprintf (opts->symbol_out_file, "%s %s.bin", getDateN(), getTimeN());
|
||
if (opts->symbol_out_file[0] != 0)
|
||
{
|
||
opts->symbol_out = 1; //set flag to 1
|
||
openSymbolOutFile (opts, state);
|
||
}
|
||
}
|
||
|
||
if (c == 114) //'r' key, stop capturing symbol capture bin file
|
||
{
|
||
if (opts->symbol_out == 1)
|
||
{
|
||
if (opts->symbol_out_file[0] != 0)
|
||
{
|
||
fclose(opts->symbol_out_f);
|
||
sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file);
|
||
}
|
||
|
||
opts->symbol_out = 0;
|
||
}
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
if (c == 80) //'P' key - start per call wav files
|
||
{
|
||
char wav_file_directory[1024];
|
||
sprintf (wav_file_directory, "./WAV");
|
||
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, "./WAV/DSD-FME-T1.wav");
|
||
sprintf (opts->wav_out_fileR, "./WAV/DSD-FME-T2.wav");
|
||
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;
|
||
}
|
||
|
||
|
||
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);
|
||
}
|
||
|
||
opts->audio_in_type = 0;
|
||
openPulseInput(opts);
|
||
}
|
||
|
||
//Lockout bug in EDACS prevents any group from tuning when using this, not sure why yet
|
||
//WARNING! USE THESE WITH CAUTION! IF BREAKING ISSUES OBSERVED, THEN RESTART AND DON'T USE THEM!!
|
||
if (opts->frame_provoice != 1 && c == 49) //'1' key, 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++;
|
||
|
||
//test tuning away to break sync, if not working so well, then disable
|
||
//RIGCTL
|
||
if (opts->frame_provoice != 1 && opts->p25_is_tuned == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, 450000000);
|
||
|
||
//rtl_udp
|
||
if (opts->frame_provoice != 1 && opts->p25_is_tuned == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, 450000000);
|
||
|
||
}
|
||
|
||
if (opts->frame_provoice != 1 && c == 50) //'2' key, 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++;
|
||
|
||
//test tuning away to break sync, if not working so well, then disable
|
||
//RIGCTL
|
||
if (opts->p25_is_tuned == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, 450000000);
|
||
|
||
//rtl_udp
|
||
if (opts->p25_is_tuned == 1 && opts->audio_in_type == 3) rtl_udp_tune (opts, state, 450000000);
|
||
|
||
}
|
||
|
||
if (c == 48) //'0' key, toggle upsampled audio smoothing
|
||
{
|
||
if (state->audio_smoothing == 1) state->audio_smoothing = 0;
|
||
else state->audio_smoothing = 1;
|
||
}
|
||
|
||
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 == 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;
|
||
|
||
}
|
||
|
||
//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);
|
||
}
|
||
|
||
//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
|
||
|
||
} //end ncursesPrinter
|
||
|
||
void ncursesClose ()
|
||
{
|
||
endwin();
|
||
|
||
}
|