mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 17:27:21 -05:00
5174 lines
172 KiB
C
5174 lines
172 KiB
C
/*-------------------------------------------------------------------------------
|
||
* dsd_ncurses.c
|
||
* DSD-FME ncurses terminal printer with menu system
|
||
*
|
||
* ASCII art generated by:
|
||
* https://fsymbols.com/generators/carty/
|
||
*
|
||
* LWVMOBILE
|
||
* 2022-08 DSD-FME Florida Man Edition
|
||
*
|
||
* ilyacodes
|
||
* 2024-03 EDACS-FME display improvements
|
||
*-----------------------------------------------------------------------------*/
|
||
|
||
|
||
#include "dsd.h"
|
||
#include "git_ver.h"
|
||
|
||
#ifdef USE_RTLSDR
|
||
#include <rtl-sdr.h>
|
||
//use to list out all detected RTL dongles
|
||
char vendor[256], product[256], serial[256], userdev[256];
|
||
int device_count = 0;
|
||
#endif
|
||
|
||
uint32_t temp_freq = -1;
|
||
|
||
|
||
//struct for checking existence of directory to write to
|
||
struct stat st_wav = {0};
|
||
int reset = 0;
|
||
|
||
uint8_t eh_slot = 0; //testing only, have a toggle slot for history
|
||
uint8_t eh_off = 0; //testing only, index offset for scrolling history
|
||
|
||
int lls = -1;
|
||
int i = 0;
|
||
char versionstr[25];
|
||
unsigned long long int edacs_channel_tree[33][6];
|
||
|
||
char * FM_bannerN[9] = {
|
||
" ",
|
||
" ██████╗ ██████╗██████╗ ███████╗███╗ ███╗███████╗ ",
|
||
" ██╔══██╗██╔════╝██╔══██╗ ██╔════╝████╗ ████║██╔════╝ ",
|
||
" ██║ ██║╚█████╗ ██║ ██║ █████╗ ██╔████╔██║█████╗ ",
|
||
" ██║ ██║ ╚═══██╗██║ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
|
||
" ██████╔╝██████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║███████╗ ",
|
||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ",
|
||
" ",
|
||
" "
|
||
};
|
||
|
||
char * SyncTypes[44] = {
|
||
"P25p1",
|
||
"P25p1",
|
||
"X2TDMA DATA",
|
||
"X2TDMA DATA",
|
||
"X2TDMA VOICE",
|
||
"X2TDMA VOICE",
|
||
"DSTAR", //voice
|
||
"DSTAR", //voice
|
||
"M17",
|
||
"M17",
|
||
"DMR", //10
|
||
"DMR",
|
||
"DMR",
|
||
"DMR",
|
||
"EDACS/PV",
|
||
"EDACS/PV",
|
||
"M17", //M17 Voice Stream
|
||
"M17", //M17 Voice Stream
|
||
"DSTAR", //header
|
||
"DSTAR", //header
|
||
"dPMR", //20
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"dPMR",
|
||
"NXDN",
|
||
"NXDN",
|
||
"YSF", //30
|
||
"YSF", //31
|
||
"DMR",
|
||
"DMR",
|
||
"DMR",
|
||
"P25p2",
|
||
"P25p2",
|
||
"EDACS/PV", //37
|
||
"EDACS/PV", //38
|
||
"ANALOG", //39 Generic Sync Types
|
||
"DIGITAL" //40 Generic Sync Types
|
||
};
|
||
|
||
char * DMRBusrtTypes[32] = {
|
||
"PI ",
|
||
"VLC ",
|
||
"TLC ",
|
||
"CSBK ",
|
||
"MBCH ",
|
||
"MBCC ",
|
||
"DATA ",
|
||
"R12D ",
|
||
"R34D ",
|
||
"IDLE ",
|
||
"R1_D ",
|
||
"ERR ",
|
||
"DUID ERR ",
|
||
"R-S ERR ",
|
||
"CRC ERR ",
|
||
"NULL ",
|
||
"VOICE",
|
||
" ",
|
||
"INIT ",
|
||
"INIT ",
|
||
"PTT", //20 MAC
|
||
"VOICE", //21 MAC_ACTIVE
|
||
"HANGTIME", //22 MAC
|
||
"PTT END", //23 MAC
|
||
"IDLE", //24 MAC
|
||
"HDU",
|
||
"VOICE", //26 LDU1
|
||
"VOICE", //27 LDU2
|
||
"TDU/LC",
|
||
"TSBK",
|
||
"SIGNAL", //MAC_SIGNAL
|
||
"SIGNAL" //MAC_SIGNAL
|
||
|
||
};
|
||
|
||
void beeper (dsd_opts * opts, dsd_state * state, int lr, int id, int ad, int len)
|
||
{
|
||
UNUSED(state);
|
||
int i, j, n;
|
||
//use lr as left or right channel designation in stereo config
|
||
float samp_f[160]; //mono float sample
|
||
float samp_fs[320]; //stereo float sample
|
||
short samp_s[160]; //mono short sample
|
||
short samp_ss[320]; //stereo short sample
|
||
short samp_su[960]; //mono short upsample
|
||
short outbuf[6]; //temp storage for upsample
|
||
|
||
n = 0; //rolling sine wave 'degree'
|
||
|
||
//double len if not using Pulse Audio,
|
||
//anything over UDP or using OSS may
|
||
//not clear the buffer at the shorter len
|
||
if (opts->audio_out_type != 0)
|
||
len *= 2;
|
||
|
||
//each j increment is 20 ms at 160 samples / 8 kHz
|
||
for (j = 0; j < len; j++)
|
||
{
|
||
//'zero' out stereo mix samples
|
||
memset (samp_fs, 0, sizeof(samp_fs));
|
||
memset (samp_ss, 0, sizeof(samp_ss));
|
||
|
||
//generate a tone with supplied tone ID and AD value
|
||
soft_tonef(samp_f, n, id, ad);
|
||
|
||
//convert float to short if required
|
||
if (opts->floating_point == 0)
|
||
{
|
||
mbe_floattoshort(samp_f, samp_s);
|
||
for (i = 0; i < 160; i++)
|
||
{
|
||
samp_s[i] *= 4000; //apply gain
|
||
samp_ss[(i*2)+lr] = samp_s[i];
|
||
}
|
||
}
|
||
|
||
//load returned tone sample into appropriate channel -- left = +0; right = +1;
|
||
for (i = 0; i < 160; i++)
|
||
samp_fs[(i*2)+lr] = samp_f[i];
|
||
|
||
//play sample 3 times (20ms x 3 = 60ms)
|
||
if (opts->audio_out_type == 0) //Pulse Audio
|
||
{
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1)
|
||
pa_simple_write(opts->pulse_digi_dev_out, samp_fs, 320*4, NULL);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1)
|
||
pa_simple_write(opts->pulse_digi_dev_out, samp_f, 160*4, NULL);
|
||
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0)
|
||
pa_simple_write(opts->pulse_digi_dev_out, samp_ss, 320*2, NULL);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0)
|
||
pa_simple_write(opts->pulse_digi_dev_out, samp_s, 160*2, NULL);
|
||
|
||
}
|
||
|
||
else if (opts->audio_out_type == 8) //UDP Audio
|
||
{
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1)
|
||
udp_socket_blaster (opts, state, 320*4, samp_fs);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1)
|
||
udp_socket_blaster (opts, state, 160*4, samp_f);
|
||
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0)
|
||
udp_socket_blaster (opts, state, 320*2, samp_ss);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0)
|
||
udp_socket_blaster (opts, state, 160*2, samp_s);
|
||
|
||
}
|
||
|
||
else if (opts->audio_out_type == 1) //STDOUT
|
||
{
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1)
|
||
write(opts->audio_out_fd, samp_fs, 320*4);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1)
|
||
write(opts->audio_out_fd, samp_f, 160*4);
|
||
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0)
|
||
write(opts->audio_out_fd, samp_ss, 320*2);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0)
|
||
write(opts->audio_out_fd, samp_s, 160*2);
|
||
}
|
||
|
||
else if (opts->audio_out_type == 2) //OSS Variable Output (no float)
|
||
{
|
||
|
||
if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0)
|
||
write(opts->audio_out_fd, samp_ss, 320*2);
|
||
|
||
if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0)
|
||
write(opts->audio_out_fd, samp_s, 160*2);
|
||
}
|
||
|
||
else if (opts->audio_out_type == 5) //OSS 48k/1 configuration with upsample
|
||
{
|
||
short prev = 0;
|
||
for (i = 0; i < 160; i++)
|
||
{
|
||
upsampleS (samp_s[i], prev, outbuf);
|
||
samp_su[(i*6)+0] = outbuf[0];
|
||
samp_su[(i*6)+1] = outbuf[1];
|
||
samp_su[(i*6)+2] = outbuf[2];
|
||
samp_su[(i*6)+3] = outbuf[3];
|
||
samp_su[(i*6)+4] = outbuf[4];
|
||
samp_su[(i*6)+5] = outbuf[5];
|
||
}
|
||
|
||
write (opts->audio_out_fd, samp_su, 960*2);
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
time_t nowN;
|
||
|
||
int isCustomAfsString(dsd_state * state) {
|
||
return state->edacs_a_bits != 4 || state->edacs_f_bits != 4 || state->edacs_s_bits != 3;
|
||
}
|
||
|
||
//Get the string length we need for an AFS string, math-style
|
||
int getAfsStringLength(dsd_state * state) {
|
||
if (!isCustomAfsString(state))
|
||
return 6;
|
||
|
||
int length = 0;
|
||
length += (state->edacs_a_bits + 2) / 3;
|
||
length += (state->edacs_f_bits + 2) / 3;
|
||
length += (state->edacs_s_bits + 2) / 3;
|
||
length += 2; //colon separators
|
||
|
||
// This will be either 6 or 7
|
||
return length;
|
||
}
|
||
|
||
//Format the AFS string, Florida-style
|
||
int getAfsString(dsd_state * state, char * buffer, int a, int f, int s) {
|
||
if (!isCustomAfsString(state))
|
||
{
|
||
sprintf(buffer, "%02d-%02d%01d", a, f, s);
|
||
return 6;
|
||
}
|
||
|
||
int printed_chars = 0;
|
||
switch (state->edacs_a_bits)
|
||
{
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
sprintf(buffer, "%01d:", a);
|
||
printed_chars += 1;
|
||
break;
|
||
case 4:
|
||
case 5:
|
||
case 6:
|
||
sprintf(buffer, "%02d:", a);
|
||
printed_chars += 2;
|
||
break;
|
||
case 7:
|
||
case 8:
|
||
case 9:
|
||
sprintf(buffer, "%03d:", a);
|
||
printed_chars += 3;
|
||
break;
|
||
}
|
||
|
||
sprintf(buffer + printed_chars, ":");
|
||
printed_chars++;
|
||
|
||
switch (state->edacs_f_bits) {
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
sprintf(buffer + printed_chars, "%01d", f);
|
||
printed_chars += 1;
|
||
break;
|
||
case 4:
|
||
case 5:
|
||
case 6:
|
||
sprintf(buffer + printed_chars, "%02d", f);
|
||
printed_chars += 2;
|
||
break;
|
||
case 7:
|
||
case 8:
|
||
case 9:
|
||
sprintf(buffer + printed_chars, "%03d", f);
|
||
printed_chars += 3;
|
||
break;
|
||
}
|
||
|
||
sprintf(buffer + printed_chars, ":");
|
||
printed_chars++;
|
||
|
||
switch (state->edacs_s_bits) {
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
sprintf(buffer + printed_chars, "%01d", s);
|
||
printed_chars += 1;
|
||
break;
|
||
case 4:
|
||
case 5:
|
||
case 6:
|
||
sprintf(buffer + printed_chars, "%02d", s);
|
||
printed_chars += 2;
|
||
break;
|
||
case 7:
|
||
case 8:
|
||
case 9:
|
||
sprintf(buffer + printed_chars, "%03d", s);
|
||
printed_chars += 3;
|
||
break;
|
||
}
|
||
|
||
return printed_chars;
|
||
}
|
||
|
||
//testing a few things, going to put this into ncursesMenu
|
||
#define WIDTH 36
|
||
#define HEIGHT 25
|
||
|
||
int startx = 0;
|
||
int starty = 0;
|
||
|
||
char *choicesc[] = {
|
||
"Return",
|
||
" ", //Save Decoded Audio WAV (Legacy Mode) //Disabled
|
||
"Save Signal to Symbol Capture Bin",
|
||
"Toggle Muting Encrypted Traffic ",
|
||
"Save Per Call Decoded WAV",
|
||
"Setup and Start RTL Input ",
|
||
"Retune RTL Dongle ",
|
||
"Toggle C4FM/QPSK (P2 TDMA CC)",
|
||
"Toggle C4FM/QPSK (P1 FDMA CC)",
|
||
"Start TCP Direct Link Audio",
|
||
"Configure RIGCTL",
|
||
"Stop All Decoded WAV Saving",
|
||
"Read OP25/FME Symbol Capture Bin",
|
||
"Replay Last Symbol Capture Bin",
|
||
"Stop & Close Symbol Capture Bin Playback",
|
||
"Stop & Close Symbol Capture Bin Saving",
|
||
"Toggle Call Alert Beep ",
|
||
"Resume Decoding"
|
||
};
|
||
//make tweaks for TDMA and AUTO?
|
||
char *choices[] = {
|
||
"Resume Decoding",
|
||
"Decode AUTO",
|
||
"Decode TDMA",
|
||
"Decode DSTAR",
|
||
"Decode M17",
|
||
"Decode EDACS/PV",
|
||
"Decode P25p2",
|
||
"Decode dPMR",
|
||
"Decode NXDN48",
|
||
"Decode NXDN96",
|
||
"Decode DMR",
|
||
"Decode YSF",
|
||
"Toggle Signal Inversion",
|
||
"Key Entry",
|
||
"Reset Event History",
|
||
"Toggle Payloads to Console",
|
||
"Manually Set p2 Parameters", //16
|
||
"Input & Output Options",
|
||
"LRRP Data to File",
|
||
"Exit DSD-FME",
|
||
};
|
||
|
||
|
||
int n_choices = sizeof(choices) / sizeof(char *);
|
||
// int n_choicesb = sizeof(choicesb) / sizeof(char *);
|
||
int n_choicesc = sizeof(choicesc) / sizeof(char *);
|
||
|
||
void print_menu(WINDOW *menu_win, int highlight)
|
||
{
|
||
int x, y, i;
|
||
|
||
x = 2;
|
||
y = 2;
|
||
box(menu_win, 0, 0);
|
||
for(i = 0; i < n_choices; ++i)
|
||
{ if(highlight == i + 1) /* High light the present choice */
|
||
{ wattron(menu_win, A_REVERSE);
|
||
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||
wattroff(menu_win, A_REVERSE);
|
||
}
|
||
else
|
||
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||
++y;
|
||
}
|
||
wrefresh(menu_win);
|
||
}
|
||
|
||
void print_menuc(WINDOW *menu_win, int highlight)
|
||
{
|
||
int x, y, i;
|
||
|
||
x = 2;
|
||
y = 2;
|
||
box(menu_win, 0, 0);
|
||
for(i = 0; i < n_choicesc; ++i)
|
||
{ if(highlight == i + 1) /* High light the present choice */
|
||
{ wattron(menu_win, A_REVERSE);
|
||
mvwprintw(menu_win, y, x, "%s", choicesc[i]);
|
||
wattroff(menu_win, A_REVERSE);
|
||
}
|
||
else
|
||
mvwprintw(menu_win, y, x, "%s", choicesc[i]);
|
||
++y;
|
||
}
|
||
wrefresh(menu_win);
|
||
}
|
||
|
||
//end Testing
|
||
|
||
void ncursesOpen (dsd_opts * opts, dsd_state * state)
|
||
{
|
||
|
||
UNUSED(opts); UNUSED(state);
|
||
|
||
// state->menuopen = 1; //flag the menu is open, stop processing getFrameSync
|
||
mbe_printVersion (versionstr);
|
||
setlocale(LC_ALL, "");
|
||
initscr(); //Initialize NCURSES screen window
|
||
start_color();
|
||
|
||
#ifdef PRETTY_COLORS
|
||
init_pair(1, COLOR_YELLOW, COLOR_BLACK); //Yellow/Amber for frame sync/control channel, NV style
|
||
init_pair(2, COLOR_RED, COLOR_BLACK); //Red for Terminated Calls
|
||
init_pair(3, COLOR_GREEN, COLOR_BLACK); //Green for Active Calls
|
||
init_pair(4, COLOR_CYAN, COLOR_BLACK); //Cyan for Site Extra and Patches
|
||
init_pair(5, COLOR_MAGENTA, COLOR_BLACK); //Magenta for no frame sync/signal
|
||
init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
#else
|
||
init_pair(1, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(2, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(3, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(4, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(5, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
|
||
#endif
|
||
|
||
noecho();
|
||
cbreak();
|
||
|
||
}
|
||
|
||
//ncursesMenu
|
||
void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||
{
|
||
|
||
//update sync time on cc sync so we don't immediately go CC hunting when exiting the menu
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
//close pulse output if not null output
|
||
if (opts->audio_out == 1 && opts->audio_out_type == 0)
|
||
{
|
||
closePulseOutput (opts);
|
||
}
|
||
|
||
//close OSS output
|
||
if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
|
||
{
|
||
close (opts->audio_out_fd);
|
||
}
|
||
|
||
if (opts->audio_in_type == 0) //close pulse input if it is the specified input method
|
||
{
|
||
closePulseInput(opts);
|
||
}
|
||
|
||
if (opts->audio_in_type == 3)
|
||
{
|
||
#ifdef USE_RTLSDR
|
||
rtl_clean_queue();
|
||
#endif
|
||
}
|
||
|
||
if (opts->audio_in_type == 8) //close TCP input SF file so we don't buffer audio while not decoding
|
||
{
|
||
sf_close(opts->tcp_file_in);
|
||
}
|
||
|
||
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
|
||
//zero out
|
||
state->nxdn_last_tg = 0;
|
||
state->nxdn_last_ran = -1; //0
|
||
state->nxdn_last_rid = 0; //0
|
||
|
||
WINDOW *menu_win;
|
||
WINDOW *test_win;
|
||
WINDOW *entry_win;
|
||
WINDOW *info_win;
|
||
int highlight = 1;
|
||
int highlightc = 1;
|
||
int choice = 0;
|
||
int choicec = 0;
|
||
int c;
|
||
int e;
|
||
|
||
startx = 2;
|
||
starty = 1;
|
||
|
||
menu_win = newwin(HEIGHT, WIDTH, starty, startx);
|
||
keypad(menu_win, TRUE);
|
||
mvprintw(0, 0, " Use arrow keys to go up and down, Press ENTER to select a choice.");
|
||
refresh();
|
||
print_menu(menu_win, highlight);
|
||
while(1)
|
||
{ c = wgetch(menu_win);
|
||
switch(c)
|
||
{ case KEY_UP:
|
||
if(highlight == 1)
|
||
highlight = n_choices;
|
||
else
|
||
--highlight;
|
||
break;
|
||
case KEY_DOWN:
|
||
if(highlight == n_choices)
|
||
highlight = 1;
|
||
else
|
||
++highlight;
|
||
break;
|
||
case 10:
|
||
choice = highlight;
|
||
break;
|
||
default:
|
||
//mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c);
|
||
refresh();
|
||
break;
|
||
}
|
||
|
||
print_menu(menu_win, highlight);
|
||
|
||
|
||
if (highlight == 2)
|
||
{
|
||
info_win = newwin(7, WIDTH+18, starty, startx+20);
|
||
box (info_win, 0, 0);
|
||
mvwprintw(info_win, 2, 2, " AUTO Decoding Class Supports the following:");
|
||
mvwprintw(info_win, 3, 2, " P25p1, YSF, DSTAR, X2-TDMA and DMR");
|
||
mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 4800bps (no H8D-QPSK)");
|
||
wrefresh(info_win);
|
||
}
|
||
|
||
if (highlight == 3)
|
||
{
|
||
info_win = newwin(7, WIDTH+18, starty, startx+20);
|
||
box (info_win, 0, 0);
|
||
mvwprintw(info_win, 2, 2, " TDMA Trunking Class Supports the following:");
|
||
mvwprintw(info_win, 3, 2, " P25p1 Voice/Control, P25p2 Traffic, and DMR");
|
||
mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 4800 or 6000 (no H8D-QPSK)");
|
||
wrefresh(info_win);
|
||
}
|
||
|
||
if (highlight == 7)
|
||
{
|
||
info_win = newwin(7, WIDTH+18, starty, startx+20);
|
||
box (info_win, 0, 0);
|
||
mvwprintw(info_win, 2, 2, " P25p2 Control (MAC_SIGNAL) or Single Voice Freq.");
|
||
mvwprintw(info_win, 3, 2, " NOTE: Manually set WACN/SYSID/CC on Voice Only");
|
||
mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 6000 (no H8D-QPSK)");
|
||
wrefresh(info_win);
|
||
}
|
||
|
||
//Input Output Options
|
||
if (choice == 18)
|
||
{
|
||
//test making a new window while other window is open
|
||
test_win = newwin(HEIGHT-1, WIDTH+9, starty+5, startx+5);
|
||
keypad(menu_win, FALSE);
|
||
keypad(test_win, TRUE);
|
||
mvprintw(0, 0, "Input & Output Options ");
|
||
refresh();
|
||
print_menuc(test_win, highlightc);
|
||
while(1)
|
||
{ e = wgetch(test_win);
|
||
switch(e)
|
||
{ case KEY_UP:
|
||
if(highlightc == 1)
|
||
highlightc = n_choicesc;
|
||
else
|
||
--highlightc;
|
||
break;
|
||
case KEY_DOWN:
|
||
if(highlightc == n_choicesc)
|
||
highlightc = 1;
|
||
else
|
||
++highlightc;
|
||
break;
|
||
case 10:
|
||
choicec = highlightc;
|
||
break;
|
||
default:
|
||
//mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c);
|
||
refresh();
|
||
break;
|
||
}
|
||
print_menuc(test_win, highlightc);
|
||
// if (choicec == 2) //Legacy Decode to single wav file is disabled
|
||
// {
|
||
// char * timestr = getTime();
|
||
// char * datestr = getDate();
|
||
// sprintf (opts->wav_out_file, "%s %s DSD-FME-DECODED.wav", datestr, timestr);
|
||
// if (timestr != NULL)
|
||
// {
|
||
// free (timestr);
|
||
// timestr = NULL;
|
||
// }
|
||
// if (datestr != NULL)
|
||
// {
|
||
// free (datestr);
|
||
// datestr = NULL;
|
||
// }
|
||
// openWavOutFile (opts, state);
|
||
// }
|
||
if (choicec == 3)
|
||
{
|
||
//read in filename for symbol capture bin
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter FME Symbol Capture Bin Filename");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->symbol_out_file); //&opts->symbol_out_file
|
||
noecho();
|
||
|
||
openSymbolOutFile (opts, state);
|
||
}
|
||
if (choicec == 4)
|
||
{
|
||
//toggle all mutes
|
||
if (opts->unmute_encrypted_p25 == 0)
|
||
{
|
||
opts->unmute_encrypted_p25 = 1;
|
||
}
|
||
else opts->unmute_encrypted_p25 = 0;
|
||
|
||
if (opts->dmr_mute_encL == 0)
|
||
{
|
||
opts->dmr_mute_encL = 1;
|
||
}
|
||
else opts->dmr_mute_encL = 0;
|
||
|
||
if (opts->dmr_mute_encR == 0)
|
||
{
|
||
opts->dmr_mute_encR = 1;
|
||
}
|
||
else opts->dmr_mute_encR = 0;
|
||
|
||
}
|
||
if (choicec == 5)
|
||
{
|
||
char wav_file_directory[1024];
|
||
sprintf (wav_file_directory, "%s", opts->wav_out_dir);
|
||
wav_file_directory[1023] = '\0';
|
||
if (stat(wav_file_directory, &st_wav) == -1)
|
||
{
|
||
fprintf (stderr, "%s wav file directory does not exist\n", wav_file_directory);
|
||
fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory);
|
||
mkdir(wav_file_directory, 0700);
|
||
}
|
||
fprintf (stderr,"\n Per Call Wav File Enabled to Directory: %s;.\n", opts->wav_out_dir);
|
||
srand(time(NULL)); //seed random for filenames (so two filenames aren't the exact same datetime string on initailization)
|
||
opts->wav_out_f = open_wav_file(opts->wav_out_dir, opts->wav_out_file, 8000, 0);
|
||
opts->wav_out_fR = open_wav_file(opts->wav_out_dir, opts->wav_out_fileR, 8000, 0);
|
||
opts->dmr_stereo_wav = 1;
|
||
|
||
}
|
||
|
||
if (choicec == 6)
|
||
{
|
||
int confirm = 0;
|
||
|
||
#ifdef USE_RTLSDR
|
||
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL Device Index or Serial Number:");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_dev_index);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL Device PPM Error:");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtlsdr_ppm_error);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Frequency in Hz (851.8 MHz is 851800000 Hz): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtlsdr_center_freq);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " BW (8, 12, 24, 48)(12 Recommended): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_bandwidth);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL Gain Value (0-49) (0 = AGC): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_gain_value);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL UDP Port - Legacy/Optional (Default = 0): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_udp_port);
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL Vol Multiplier (1,2,3) (Default = 1): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_volume_multiplier);
|
||
if (opts->rtl_volume_multiplier > 3 || opts->rtl_volume_multiplier < 0)
|
||
opts->rtl_volume_multiplier = 1;
|
||
noecho();
|
||
|
||
entry_win = newwin(8, WIDTH+22, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " RTL RMS Squelch Level (NXDN/dPMR/Analog/Raw only): ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtl_squelch_level);
|
||
noecho();
|
||
|
||
//use to list out all detected RTL dongles
|
||
device_count = rtlsdr_get_device_count();
|
||
if (!device_count)
|
||
{
|
||
fprintf(stderr, "No supported devices found.\n");
|
||
}
|
||
else fprintf(stderr, "Found %d device(s):\n", device_count);
|
||
for (int i = 0; i < device_count; i++)
|
||
{
|
||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||
fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial);
|
||
|
||
sprintf (userdev, "%08d", opts->rtl_dev_index);
|
||
|
||
//check by index first, then by serial
|
||
if (opts->rtl_dev_index == i)
|
||
{
|
||
fprintf (stderr, "Selected Device #%d with Serial Number: %s \n", i, serial);
|
||
break;
|
||
}
|
||
else if (strcmp (userdev, serial) == 0)
|
||
{
|
||
fprintf (stderr, "Selected Device #%d with Serial Number: %s \n", i, serial);
|
||
opts->rtl_dev_index = i;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
entry_win = newwin(18, WIDTH+20, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Starting RTL Input. Cannot Release/Stop Until Exit.");
|
||
mvwprintw(entry_win, 4, 2, " RTL Frequency: %d Hz", opts->rtlsdr_center_freq);
|
||
mvwprintw(entry_win, 5, 2, " RTL Device Index Number: %d; SN:%s", opts->rtl_dev_index, serial);
|
||
mvwprintw(entry_win, 6, 2, " RTL Device Bandwidth: %d kHz", opts->rtl_bandwidth);
|
||
mvwprintw(entry_win, 7, 2, " RTL Device Gain: %d", opts->rtl_gain_value);
|
||
mvwprintw(entry_win, 8, 2, " RTL Volume Multiplier: %d", opts->rtl_volume_multiplier);
|
||
mvwprintw(entry_win, 9, 2, " RTL Device UDP Port: %d", opts->rtl_udp_port);
|
||
mvwprintw(entry_win, 10, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error);
|
||
mvwprintw(entry_win, 11, 2, " RTL RMS Squelch: %d", opts->rtl_squelch_level);
|
||
mvwprintw(entry_win, 13, 2, " Are You Sure?");
|
||
mvwprintw(entry_win, 14, 2, " 1 = Yes, 2 = No ");
|
||
mvwprintw(entry_win, 15, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &confirm);
|
||
noecho();
|
||
|
||
refresh();
|
||
|
||
//works well, but can't release dongle later, so its a one way trip until exit
|
||
//TODO: Write function to release the dongle -- call cleanup_rtlsdr_stream()
|
||
if (confirm == 1)
|
||
{
|
||
opts->audio_in_type = 3; //RTL input, only set this on confirm
|
||
choicec = 18; //exit to decoder screen only if confirmed, otherwise, just go back
|
||
}
|
||
|
||
#else
|
||
UNUSED(confirm);
|
||
|
||
#endif
|
||
|
||
}
|
||
|
||
if (choicec == 7) //RTL DEV Retune
|
||
{
|
||
//read in new rtl frequency
|
||
#ifdef USE_RTLSDR
|
||
entry_win = newwin(6, WIDTH+18, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter Frequency in Hz (851.8 MHz is 851800000 Hz) ");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rtlsdr_center_freq);
|
||
noecho();
|
||
|
||
temp_freq = opts->rtlsdr_center_freq;
|
||
#endif
|
||
choicec = 18;
|
||
}
|
||
|
||
if (choicec == 8)
|
||
{
|
||
if (state->rf_mod == 0)
|
||
{
|
||
state->rf_mod = 1;
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 1;
|
||
}
|
||
else
|
||
{
|
||
state->rf_mod = 0;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
}
|
||
}
|
||
|
||
if (choicec == 9)
|
||
{
|
||
if (state->rf_mod == 0)
|
||
{
|
||
state->rf_mod = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 1;
|
||
}
|
||
else
|
||
{
|
||
state->rf_mod = 0;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
}
|
||
}
|
||
|
||
// if (choicec == 9)
|
||
// {
|
||
// if (opts->audio_out == 0)
|
||
// {
|
||
// opts->audio_out = 1;
|
||
// opts->audio_out_type = 0;
|
||
// // state->audio_out_buf_p = 0;
|
||
// // state->audio_out_buf_pR = 0;
|
||
// state->audio_out_idx = 0;
|
||
// state->audio_out_idx2 = 0;
|
||
// state->audio_out_idxR = 0;
|
||
// state->audio_out_idx2R = 0;
|
||
// }
|
||
// else
|
||
// {
|
||
// opts->audio_out = 0;
|
||
// opts->audio_out_type = 9;
|
||
// // state->audio_out_buf_p = 0;
|
||
// // state->audio_out_buf_pR = 0;
|
||
// state->audio_out_idx = 0;
|
||
// state->audio_out_idx2 = 0;
|
||
// state->audio_out_idxR = 0;
|
||
// state->audio_out_idx2R = 0;
|
||
// }
|
||
// }
|
||
|
||
//TCP Audio Input
|
||
if (choicec == 10)
|
||
{
|
||
//read in tcp hostname
|
||
sprintf (opts->tcp_hostname, "%s", "localhost");
|
||
opts->tcp_portno = 7355;
|
||
|
||
entry_win = newwin(8, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter TCP Direct Link Hostname:");
|
||
mvwprintw(entry_win, 3, 2, " (default is localhost)");
|
||
mvwprintw(entry_win, 4, 2, " ");
|
||
mvwprintw(entry_win, 5, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->tcp_hostname);
|
||
noecho();
|
||
|
||
//read in tcp port number
|
||
entry_win = newwin(8, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter TCP Direct Link Port Number:");
|
||
mvwprintw(entry_win, 3, 2, " (default is 7355)");
|
||
mvwprintw(entry_win, 4, 2, " ");
|
||
mvwprintw(entry_win, 5, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->tcp_portno);
|
||
noecho();
|
||
|
||
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
|
||
if (opts->tcp_sockfd == 0) goto TCP_END;
|
||
//successful connection, continue;
|
||
|
||
opts->audio_in_type = 8;
|
||
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
|
||
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
|
||
opts->audio_in_file_info->channels=1;
|
||
opts->audio_in_file_info->seekable=0;
|
||
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||
|
||
if(opts->tcp_file_in == NULL)
|
||
{
|
||
fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||
if (opts->audio_out_type == 0)
|
||
{
|
||
sprintf (opts->audio_in_dev, "%s", "pulse");
|
||
opts->audio_in_type = 0;
|
||
}
|
||
else opts->audio_in_type = 5;
|
||
|
||
}
|
||
|
||
|
||
|
||
TCP_END: ; //do nothing
|
||
|
||
}
|
||
|
||
//RIGCTL
|
||
if (choicec == 11)
|
||
{
|
||
//read in tcp hostname
|
||
sprintf (opts->rigctlhostname, "%s", "localhost");
|
||
opts->rigctlportno = 4532;
|
||
|
||
entry_win = newwin(8, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter RIGCTL Hostname:");
|
||
mvwprintw(entry_win, 3, 2, " (default is localhost)");
|
||
mvwprintw(entry_win, 4, 2, " ");
|
||
mvwprintw(entry_win, 5, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->rigctlhostname);
|
||
noecho();
|
||
|
||
//read in tcp port number
|
||
entry_win = newwin(8, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter RIGCTL Port Number:");
|
||
mvwprintw(entry_win, 3, 2, " (default is 4532)");
|
||
mvwprintw(entry_win, 4, 2, " ");
|
||
mvwprintw(entry_win, 5, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%d", &opts->rigctlportno);
|
||
noecho();
|
||
|
||
opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno);
|
||
if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1;
|
||
else opts->use_rigctl = 0;
|
||
}
|
||
|
||
// if (choicec == 10)
|
||
// {
|
||
// if (opts->ncurses_compact == 0)
|
||
// {
|
||
// opts->ncurses_compact = 1;
|
||
// }
|
||
// else opts->ncurses_compact = 0;
|
||
|
||
// }
|
||
|
||
// if (choicec == 11)
|
||
// {
|
||
// if (opts->ncurses_history == 0)
|
||
// {
|
||
// opts->ncurses_history = 1;
|
||
// }
|
||
// else opts->ncurses_history = 0;
|
||
// }
|
||
|
||
if (choicec == 12)
|
||
{
|
||
//TODO: Add Closing of RAW files as well?
|
||
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, &state->event_history_s[0]);
|
||
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, &state->event_history_s[1]);
|
||
opts->wav_out_file[0] = 0; //Bugfix for decoded wav file display after disabling
|
||
opts->wav_out_fileR[0] = 0;
|
||
opts->dmr_stereo_wav = 0;
|
||
}
|
||
|
||
if (choicec == 13) //lucky number 13 for OP25 Symbol Capture Bin Files
|
||
{
|
||
//read in filename for symbol capture bin
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter OP25 Symbol Capture Bin Filename");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->audio_in_dev); //&opts->audio_in_dev
|
||
noecho();
|
||
//do the thing with the thing
|
||
struct stat stat_buf;
|
||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||
{
|
||
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||
goto SKIP;
|
||
}
|
||
if (S_ISREG(stat_buf.st_mode))
|
||
{
|
||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||
opts->audio_in_type = 4; //symbol capture bin files
|
||
}
|
||
SKIP:
|
||
choicec = 18;
|
||
}
|
||
|
||
if (choicec == 14) //replay last file
|
||
{
|
||
struct stat stat_buf;
|
||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||
{
|
||
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||
goto SKIPR;
|
||
}
|
||
if (S_ISREG(stat_buf.st_mode))
|
||
{
|
||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||
opts->audio_in_type = 4; //symbol capture bin files
|
||
}
|
||
SKIPR:
|
||
choicec = 18; //exit
|
||
}
|
||
|
||
if (choicec == 15) //stop/close last file PLAYBACK
|
||
{
|
||
if (opts->symbolfile != NULL)
|
||
{
|
||
if (opts->audio_in_type == 4) //check first, or issuing a second fclose will crash the SOFTWARE
|
||
{
|
||
fclose(opts->symbolfile); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once
|
||
|
||
}
|
||
|
||
}
|
||
if (opts->audio_out_type == 0) opts->audio_in_type = 0; //set after closing to prevent above crash condition
|
||
else (opts->audio_in_type = 5);
|
||
|
||
choicec = 18; //exit
|
||
}
|
||
|
||
if (choicec == 16) //stop/close last file RECORDING
|
||
{
|
||
if (opts->symbol_out_f)
|
||
{
|
||
closeSymbolOutFile (opts, state);
|
||
sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file); //swap output bin filename to input for quick replay
|
||
}
|
||
choicec = 18; //exit
|
||
}
|
||
|
||
//toggle call alert beep
|
||
if (choicec == 17)
|
||
{
|
||
if (opts->call_alert == 0)
|
||
{
|
||
opts->call_alert = 1;
|
||
}
|
||
else opts->call_alert = 0;
|
||
}
|
||
|
||
if (choicec != 0 && choicec != 18 ) //return to last menu
|
||
{
|
||
//return
|
||
choice = 0;
|
||
choicec = 0;
|
||
|
||
keypad(test_win, FALSE);
|
||
keypad(menu_win, TRUE);
|
||
delwin(test_win);
|
||
print_menu(menu_win, highlight);
|
||
//wrefresh(menu_win);
|
||
break;
|
||
}
|
||
|
||
if (choicec == 18) //exit both menus
|
||
{
|
||
//exit
|
||
choice = 1;
|
||
choicec = 0;
|
||
|
||
keypad(test_win, FALSE);
|
||
keypad(menu_win, TRUE);
|
||
delwin(test_win);
|
||
print_menu(menu_win, highlight);
|
||
break;
|
||
}
|
||
}
|
||
clrtoeol(); //clear to end of line?
|
||
refresh();
|
||
}
|
||
|
||
//Key Entry
|
||
if (choice == 14)
|
||
{
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
short int option = 0;
|
||
entry_win = newwin(16, 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 - Hytera Privacy ");
|
||
mvwprintw(entry_win, 6, 2, "3 - NXDN/dPMR Scrambler ");
|
||
mvwprintw(entry_win, 7, 2, "4 - Force BP/Scr Key Priority ");
|
||
mvwprintw(entry_win, 8, 3, "-------------------------------- ");
|
||
mvwprintw(entry_win, 9, 2, "5 - RC4 or DES Key ");
|
||
// mvwprintw(entry_win, 10, 2, "6 - Force DMR RC4 Priority/LE ");
|
||
mvwprintw(entry_win, 10, 2, "6 - AES-128 or AES-256 Key ");
|
||
mvwprintw(entry_win, 11, 3, "-------------------------------- ");
|
||
mvwprintw(entry_win, 14, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%hd", &option); //%d
|
||
noecho();
|
||
opts->dmr_mute_encL = 0;
|
||
opts->dmr_mute_encR = 0;
|
||
if (option == 1)
|
||
{
|
||
state->K = 0;
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, "Basic Privacy Key Number (DEC):");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%lld", &state->K);
|
||
noecho();
|
||
if (state->K > 255) state->K = 255;
|
||
|
||
state->keyloader = 0; //turn off keyloader
|
||
}
|
||
if (option == 2)
|
||
{
|
||
state->K1 = 0;
|
||
state->K2 = 0;
|
||
state->K3 = 0;
|
||
state->K4 = 0;
|
||
state->H = 0;
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " 10 Char or First 16 for 32/64");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->H);
|
||
noecho();
|
||
state->K1 = state->H;
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 2 (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " Second 16 Chars or Zero");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->K2);
|
||
noecho();
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 3 (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " Third 16 Chars or Zero");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->K3);
|
||
noecho();
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 4 (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " Fourth 16 Chars or Zero");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->K4);
|
||
noecho();
|
||
|
||
state->keyloader = 0; //turn off keyloader
|
||
}
|
||
if (option == 3)
|
||
{
|
||
state->R = 0;
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, "NXDN/dPMR Scrambler Key Value (DEC):");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%lld", &state->R);
|
||
noecho();
|
||
if (state->R > 0x7FFF) state->R = 0x7FFF;
|
||
|
||
state->keyloader = 0; //turn off keyloader
|
||
}
|
||
//toggle enforcement of basic privacy key over enc bit set on traffic
|
||
if (option == 4)
|
||
{
|
||
if (state->M == 1 || state->M == 0x21)
|
||
{
|
||
state->M = 0;
|
||
}
|
||
else state->M = 1;
|
||
}
|
||
|
||
if (option == 5)
|
||
{
|
||
state->R = 0;
|
||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, "RC4/DES Key Value (HEX):");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->R);
|
||
noecho();
|
||
//disable size check for DES keys
|
||
// if (state->R > 0xFFFFFFFFFF)
|
||
// {
|
||
// state->R = 0xFFFFFFFFFF;
|
||
// }
|
||
state->RR = state->R; //assign for both slots
|
||
state->keyloader = 0; //turn off keyloader
|
||
}
|
||
|
||
//toggle enforcement of rc4 key over missing pi header/le on DMR
|
||
// if (option == 6)
|
||
// {
|
||
// if (state->M == 1 || state->M == 0x21)
|
||
// {
|
||
// state->M = 0;
|
||
// }
|
||
// else state->M = 0x21;
|
||
// }
|
||
|
||
//load AES keys
|
||
if (option == 6)
|
||
{
|
||
state->K1 = 0;
|
||
state->K2 = 0;
|
||
state->K3 = 0;
|
||
state->K4 = 0;
|
||
state->H = 0;
|
||
|
||
memset (state->A1, 0, sizeof(state->A1));
|
||
memset (state->A2, 0, sizeof(state->A2));
|
||
memset (state->A3, 0, sizeof(state->A3));
|
||
memset (state->A4, 0, sizeof(state->A4));
|
||
|
||
entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter AES128/256 Key Value (HEX) ");
|
||
mvwprintw(entry_win, 3, 2, " First 16 Chars or Zero");
|
||
mvwprintw(entry_win, 4, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->K1);
|
||
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 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();
|
||
|
||
//load the AES keys into a seperate handler
|
||
state->A1[0] = state->A1[1] = state->K1;
|
||
state->A2[0] = state->A2[1] = state->K2;
|
||
state->A3[0] = state->A3[1] = state->K3;
|
||
state->A4[0] = state->A4[1] = state->K4;
|
||
|
||
//zero out the K1-K4
|
||
state->K1 = 0;
|
||
state->K2 = 0;
|
||
state->K3 = 0;
|
||
state->K4 = 0;
|
||
|
||
state->keyloader = 0; //turn off keyloader
|
||
|
||
//check to see if there is a value loaded or not
|
||
if (state->A1[0] == 0 && state->A2[0] == 0 && state->A3[0] == 0 && state->A4[0] == 0)
|
||
state->aes_key_loaded[0] = 0;
|
||
else state->aes_key_loaded[0] = 1;
|
||
|
||
//mirror
|
||
state->aes_key_loaded[1] = state->aes_key_loaded[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 == 99) //UNUSED
|
||
{
|
||
//setup Auto parameters--default ones
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "Legacy Auto");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 1;
|
||
opts->frame_x2tdma = 1;
|
||
opts->frame_p25p1 = 1;
|
||
opts->frame_p25p2 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 1;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 1;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
|
||
}
|
||
if (choice == 6)
|
||
{
|
||
//ProVoice Specifics
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 5;
|
||
state->symbolCenter = 2;
|
||
sprintf (opts->output_name, "EDACS/PV");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_p25p2 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 1;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 1;
|
||
state->rf_mod = 2;
|
||
break;
|
||
}
|
||
if (choice == 4)
|
||
{
|
||
//DSTAR
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "DSTAR");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 1;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_p25p2 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
// state->rf_mod = 2;
|
||
opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
}
|
||
if (choice == 3) //was 5, changed to 3 and also made it the TDMA class
|
||
{
|
||
//TDMA -- was P25p1 only
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
// opts->use_heuristics = 1; //Causes issues with Voice Wide
|
||
if (opts->use_heuristics == 1)
|
||
{
|
||
initialize_p25_heuristics(&state->p25_heuristics);
|
||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||
}
|
||
opts->frame_p25p1 = 1;
|
||
opts->frame_p25p2 = 1;
|
||
opts->frame_dmr = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "TDMA");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 1; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 2;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
}
|
||
|
||
if (choice == 2)
|
||
{
|
||
//AUTO Stereo P25 1, 2, and DMR
|
||
// resetState (state); //use sparingly, seems to cause issue when switching back to other formats
|
||
if (opts->use_heuristics == 1)
|
||
{
|
||
initialize_p25_heuristics(&state->p25_heuristics);
|
||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||
}
|
||
// opts->use_heuristics = 0;
|
||
opts->frame_dmr = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "AUTO");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 1; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 2;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 1;
|
||
opts->frame_p25p2 = 1;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 1;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
break;
|
||
}
|
||
if (choice == 7)
|
||
{
|
||
// resetState (state); //use sparingly, seems to cause issue when switching back to other formats
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
sprintf (opts->output_name, "P25p2");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 1; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 2;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_p25p2 = 1;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
break;
|
||
}
|
||
if (choice == 8)
|
||
{
|
||
//dPMR
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 20;
|
||
state->symbolCenter = 10;
|
||
sprintf (opts->output_name, "dPMR");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 1;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
break;
|
||
}
|
||
if (choice == 9)
|
||
{
|
||
//NXDN48
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
opts->frame_nxdn48 = 1;
|
||
state->samplesPerSymbol = 20;
|
||
state->symbolCenter = 10;
|
||
state->rf_mod = 0;
|
||
sprintf (opts->output_name, "NXDN48");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 1;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
// opts->mod_qpsk = 0;
|
||
// opts->mod_gfsk = 0;
|
||
// state->rf_mod = 0;
|
||
}
|
||
if (choice == 10)
|
||
{
|
||
//NXDN96
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "NXDN96");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 1;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
}
|
||
if (choice == 11)
|
||
{
|
||
//Decode DMR Stereo (was X2-TDMA)
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
// sprintf (opts->output_name, "X2-TDMA");
|
||
sprintf (opts->output_name, "DMR");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 1; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 2;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 1;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
//opts->unmute_encrypted_p25 = 0;
|
||
}
|
||
if (choice == 12)
|
||
{
|
||
//Decode YSF Fusion
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "YSF");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 1;
|
||
opts->frame_m17 = 0;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
}
|
||
if (choice == 5) //was 3
|
||
{
|
||
//Decode M17
|
||
// resetState (state); //use sparingly, may cause memory leak
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
sprintf (opts->output_name, "M17");
|
||
opts->dmr_mono = 0;
|
||
opts->dmr_stereo = 0; //this value is the end user option
|
||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||
opts->pulse_digi_rate_out = 8000;
|
||
opts->pulse_digi_out_channels = 1;
|
||
opts->frame_dstar = 0;
|
||
opts->frame_x2tdma = 0;
|
||
opts->frame_p25p1 = 0;
|
||
opts->frame_nxdn48 = 0;
|
||
opts->frame_nxdn96 = 0;
|
||
opts->frame_dmr = 0;
|
||
opts->frame_dpmr = 0;
|
||
opts->frame_provoice = 0;
|
||
opts->frame_ysf = 0;
|
||
opts->frame_m17 = 1;
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
}
|
||
if (choice == 13)
|
||
{
|
||
//Set all signal for inversion or uninversion
|
||
if (opts->inverted_dmr == 0)
|
||
{
|
||
opts->inverted_dmr = 1;
|
||
opts->inverted_dpmr = 1;
|
||
opts->inverted_x2tdma = 1;
|
||
opts->inverted_ysf = 1;
|
||
opts->inverted_m17 = 1;
|
||
}
|
||
else
|
||
{
|
||
opts->inverted_dmr = 0;
|
||
opts->inverted_dpmr = 0;
|
||
opts->inverted_x2tdma = 0;
|
||
opts->inverted_ysf = 0;
|
||
opts->inverted_m17 = 0;
|
||
}
|
||
|
||
}
|
||
if (choice == 15) //reset event history
|
||
{
|
||
//initialize event history items (0 to 255)
|
||
for (uint8_t i = 0; i < 2; i++)
|
||
init_event_history(&state->event_history_s[i], 0, 255);
|
||
}
|
||
|
||
if (choice == 16) //toggle payload printing
|
||
{
|
||
if (opts->payload == 0)
|
||
{
|
||
opts->payload = 1;
|
||
fprintf(stderr, "Payload on\n");
|
||
}
|
||
else
|
||
{
|
||
opts->payload = 0;
|
||
fprintf(stderr, "Payload Off\n");
|
||
}
|
||
}
|
||
if (choice == 17)
|
||
{
|
||
//hardset P2 WACN, SYSID, and NAC
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter Phase 2 WACN (HEX)");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->p2_wacn); //%X
|
||
if (state->p2_wacn > 0xFFFFF)
|
||
{
|
||
state->p2_wacn = 0xFFFFF;
|
||
}
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter Phase 2 SYSID (HEX)");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->p2_sysid); //%X
|
||
if (state->p2_sysid > 0xFFF)
|
||
{
|
||
state->p2_sysid = 0xFFF;
|
||
}
|
||
noecho();
|
||
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter Phase 2 NAC/CC (HEX)");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%llX", &state->p2_cc); //%X
|
||
if (state->p2_cc > 0xFFF)
|
||
{
|
||
state->p2_cc = 0xFFF;
|
||
}
|
||
noecho();
|
||
|
||
//need handling to truncate larger than expected values
|
||
|
||
//set our hardset flag to 1 if values inserted, else set to 0 so we can attempt to get them from TSBK/LCCH
|
||
if (state->p2_wacn != 0 && state->p2_sysid != 0 && state->p2_cc != 0)
|
||
{
|
||
state->p2_hardset = 1;
|
||
}
|
||
else state->p2_hardset = 0;
|
||
|
||
|
||
}
|
||
if (choice == 19)
|
||
{
|
||
short int lrrpchoice = 0;
|
||
entry_win = newwin(10, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enable or Disable LRRP Data File");
|
||
mvwprintw(entry_win, 3, 2, " 1 - ~/lrrp.txt (QGis)");
|
||
mvwprintw(entry_win, 4, 2, " 2 - ./DSDPlus.LRRP (LRRP.exe)");
|
||
mvwprintw(entry_win, 5, 2, " 3 - ./Custom Filename");
|
||
mvwprintw(entry_win, 6, 2, " 4 - Cancel/Stop");
|
||
mvwprintw(entry_win, 7, 2, " ");
|
||
mvwprintw(entry_win, 8, 2, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%hd", &lrrpchoice); //%d
|
||
noecho();
|
||
|
||
if (lrrpchoice == 1)
|
||
{
|
||
//find user home directory and append directory and filename.
|
||
char * filename = "/lrrp.txt";
|
||
char * home_dir = getenv("HOME");
|
||
char * filepath = malloc(strlen(home_dir) + strlen(filename) + 1);
|
||
strncpy (filepath, home_dir, strlen(home_dir) + 1);
|
||
strncat (filepath, filename, strlen(filename) + 1);
|
||
//assign home directory/filename to lrrp_out_file
|
||
sprintf (opts->lrrp_out_file, "%s", filepath); //double check make sure this still works
|
||
opts->lrrp_file_output = 1;
|
||
}
|
||
|
||
else if (lrrpchoice == 2)
|
||
{
|
||
sprintf (opts->lrrp_out_file, "DSDPlus.LRRP");
|
||
opts->lrrp_file_output = 1;
|
||
}
|
||
|
||
else if (lrrpchoice == 3)
|
||
{
|
||
//read in filename for symbol capture bin
|
||
opts->lrrp_out_file[0] = 0;
|
||
entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
|
||
box (entry_win, 0, 0);
|
||
mvwprintw(entry_win, 2, 2, " Enter LRRP Data Filename");
|
||
mvwprintw(entry_win, 3, 3, " ");
|
||
echo();
|
||
refresh();
|
||
wscanw(entry_win, "%s", opts->lrrp_out_file); //&opts->lrrp_out_file
|
||
noecho();
|
||
if (opts->lrrp_out_file[0] != 0) //NULL
|
||
{
|
||
opts->lrrp_file_output = 1;
|
||
}
|
||
else
|
||
{
|
||
opts->lrrp_file_output = 0;
|
||
sprintf (opts->lrrp_out_file, "%s", "");
|
||
opts->lrrp_out_file[0] = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
opts->lrrp_file_output = 0;
|
||
sprintf (opts->lrrp_out_file, "%s", "");
|
||
opts->lrrp_out_file[0] = 0;
|
||
}
|
||
}
|
||
if (choice == 20)
|
||
{
|
||
exitflag = 1;
|
||
break;
|
||
}
|
||
|
||
if(choice != 0 && choice != 20) /* User did a choice come out of the infinite loop */
|
||
break;
|
||
|
||
}
|
||
|
||
clrtoeol(); //clear to end of line?
|
||
refresh();
|
||
state->menuopen = 0; //flag the menu is closed, resume processing getFrameSync
|
||
|
||
//reopen pulse output with new parameters, if not null output type
|
||
if (opts->audio_out == 1 && opts->audio_out_type == 0)
|
||
{
|
||
openPulseOutput (opts);
|
||
}
|
||
|
||
if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
|
||
{
|
||
openOSSOutput (opts);
|
||
}
|
||
|
||
|
||
if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method
|
||
{
|
||
openPulseInput(opts);
|
||
}
|
||
//fix location of this statement to inside the if statement and add conditions
|
||
if (opts->audio_in_type == 3) //open rtl input if it is the specified input method
|
||
{
|
||
// ncursesPrinter (opts, state); //not sure why this was placed here originally, but causes a double free core dump when calling free(timestr)
|
||
#ifdef USE_RTLSDR
|
||
if (opts->rtl_started == 0)
|
||
{
|
||
opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again
|
||
open_rtlsdr_stream(opts);
|
||
}
|
||
rtl_clean_queue();
|
||
reset_dibit_buffer(state); //test and observe for any random issues, disable if needed
|
||
#elif AERO_BUILD
|
||
opts->audio_out_type = 5; //hopefully the audio stream is still/already open //shouldn't this be 5? Was set to 3
|
||
#else
|
||
opts->audio_out_type = 0; //need to see if we need to open pulseoutput as well here?
|
||
openPulseOutput (opts);
|
||
#endif
|
||
}
|
||
|
||
if (opts->audio_in_type == 8) //re-open TCP input 'file'
|
||
{
|
||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||
}
|
||
|
||
|
||
//update sync time on cc sync so we don't immediately go CC hunting when exiting the menu
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
}
|
||
//end Ncurses Menu
|
||
|
||
void
|
||
ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||
{
|
||
uint8_t idas = 0;
|
||
int level = 0;
|
||
int c = 0;
|
||
|
||
//for filenames (no colons, etc)
|
||
char * timestr = getTime();
|
||
char * datestr = getDate();
|
||
|
||
if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN -
|
||
{
|
||
timeout(0); //
|
||
c = getch(); //
|
||
}
|
||
|
||
//use rtl_dev_tune
|
||
#ifdef USE_RTLSDR
|
||
if (temp_freq == opts->rtlsdr_center_freq)
|
||
{
|
||
rtl_dev_tune (opts, temp_freq);
|
||
temp_freq = -1;
|
||
}
|
||
#endif
|
||
|
||
//Variable reset/set section
|
||
|
||
//set lls sync types
|
||
if (state->synctype >= 0)
|
||
lls = state->synctype;
|
||
|
||
//EDACS Channel Tree
|
||
if ( (lls == 14 || lls == 15 || lls == 37 || lls == 38) && state->carrier == 1)
|
||
{
|
||
|
||
if (state->edacs_vc_lcn != -1)
|
||
{
|
||
edacs_channel_tree[state->edacs_vc_lcn][0] = lls;
|
||
edacs_channel_tree[state->edacs_vc_lcn][1] = state->edacs_vc_lcn;
|
||
edacs_channel_tree[state->edacs_vc_lcn][2] = state->lasttg;
|
||
//EDACS standard does not provide source LIDs on channel update messages; instead, for the sake of display, let's
|
||
//assume the prior source for a given LCN is still accurate, unless we have an updated one provided (or the call
|
||
//type has changed under us).
|
||
//
|
||
//If you MUST have perfectly-accurate source LIDs, look at the logged CC messages yourself - incorrect source LIDs
|
||
//may be displayed if we miss an initial call channel assignment.
|
||
if (state->ea_mode == 1 || (state->lastsrc != 0 || edacs_channel_tree[state->edacs_vc_lcn][4] != state->edacs_vc_call_type))
|
||
edacs_channel_tree[state->edacs_vc_lcn][3] = state->lastsrc;
|
||
edacs_channel_tree[state->edacs_vc_lcn][4] = state->edacs_vc_call_type;
|
||
edacs_channel_tree[state->edacs_vc_lcn][5] = time(NULL);
|
||
}
|
||
|
||
}
|
||
|
||
//Start Printing Section
|
||
erase();
|
||
if (opts->ncurses_compact == 1)
|
||
{
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
printw ("| Digital Speech Decoder: Florida Man Edition - AW %s \n", GIT_TAG);
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
}
|
||
if (opts->ncurses_compact == 0)
|
||
{
|
||
attron(COLOR_PAIR(6));
|
||
for (short int i = 0; i < 7; i++)
|
||
{
|
||
printw("%s", FM_bannerN[i]);
|
||
if (i == 1) printw (" ESC to Menu");
|
||
if (i == 2) printw (" 'q' to Quit ");
|
||
if (i == 3 && state->debug_mode == 1) printw (" DEBUG MODE!");
|
||
if (i == 4 && opts->frame_m17 == 0) printw (" MBElib %s", versionstr);
|
||
#ifdef USE_CODEC2
|
||
if (i == 4 && opts->frame_m17 == 1) printw (" CODEC2");
|
||
#endif
|
||
#ifdef __CYGWIN__
|
||
if (i == 5) printw (" %s ", "AW (CYGWIN)");
|
||
#else
|
||
if (i == 5) printw (" %s ", "AW ");
|
||
#endif
|
||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||
else printw ("\n");
|
||
}
|
||
attroff(COLOR_PAIR(6)); //6
|
||
attron(COLOR_PAIR(4));
|
||
}
|
||
|
||
//fix color/pair issue when compact and trunking enabled
|
||
if (opts->ncurses_compact == 1 && opts->p25_trunk == 1) attron(COLOR_PAIR(4));
|
||
|
||
printw ("--Input Output----------------------------------------------------------------\n");
|
||
if (opts->audio_in_type == 0)
|
||
{
|
||
printw ("| Pulse Signal Input: %i kHz; %i Ch; ", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels);
|
||
if (opts->pa_input_idx[0] != 0)
|
||
printw (" D: %s;", opts->pa_input_idx);
|
||
if (opts->use_rigctl == 1)
|
||
printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno);
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->audio_in_type == 5)
|
||
{
|
||
printw ("| OSS Signal Input: %i kHz; 1 Ch;", SAMPLE_RATE_IN/1000);
|
||
if (opts->use_rigctl == 1)
|
||
printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno);
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->audio_in_type == 4)
|
||
{
|
||
printw ("| Dibit Bin Input: %s \n", opts->audio_in_dev);
|
||
}
|
||
|
||
if (opts->audio_in_type == 44)
|
||
{
|
||
printw ("| Symbol Float Input: %s \n", opts->audio_in_dev);
|
||
}
|
||
|
||
if (opts->m17decoderip == 1 && opts->udp_sockfd)
|
||
printw ("| M17 UDP IP Frame Input: %s:%d \n", opts->m17_hostname, opts->m17_portno);
|
||
|
||
if (opts->audio_in_type == 8)
|
||
{
|
||
printw ("| TCP Signal Input: %s:%d; %d kHz; 1 Ch; ", opts->tcp_hostname, opts->tcp_portno, opts->wav_sample_rate/1000);
|
||
if (opts->use_rigctl == 1)
|
||
printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno);
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->audio_in_type == 2)
|
||
{
|
||
printw ("| WAV Audio Input: %s; %d kHz; \n", opts->audio_in_dev, opts->wav_sample_rate);
|
||
}
|
||
|
||
if (opts->audio_in_type == 1)
|
||
{
|
||
printw ("| STDIN Standard Input: - Menu Disabled when using STDIN!\n");
|
||
// printw ("| NCURSES Menu Disabled when using STDIN! - Use CTRL + C to Close. \n");
|
||
}
|
||
|
||
if (opts->audio_in_type == 3)
|
||
{
|
||
printw ("| RTL: %d;", opts->rtl_dev_index);
|
||
if (opts->rtl_gain_value == 0)
|
||
printw (" G: AGC;");
|
||
else
|
||
printw (" G: %idB;", opts->rtl_gain_value);
|
||
printw (" V: %iX;", opts->rtl_volume_multiplier);
|
||
printw (" PPM: %i;", opts->rtlsdr_ppm_error);
|
||
printw (" SQ: %i;", opts->rtl_squelch_level);
|
||
printw (" RMS: %04li;", opts->rtl_rms);
|
||
printw (" BW: %i;", opts->rtl_bandwidth);
|
||
printw (" FRQ: %i;", opts->rtlsdr_center_freq);
|
||
if (opts->rtl_udp_port != 0) printw ("\n| External RTL Tuning on UDP Port: %i", opts->rtl_udp_port);
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->audio_out_type == 0)
|
||
{
|
||
printw ("| Pulse Digital Output: %i kHz; %i Ch; G: %02.0f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2);
|
||
if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2);
|
||
if (opts->floating_point == 1) printw (" FLOAT: %02.0f%%;", opts->audio_gain*2);
|
||
if (opts->audio_gain == 0) printw (" (+|-) Auto ");
|
||
if (opts->audio_gain > 0) printw (" (+|-) Manual");
|
||
if (opts->use_hpf_d == 1) printw (" HPF");
|
||
if (opts->call_alert == 1) printw (" *CA!"); //Call Alert
|
||
if (opts->pa_output_idx[0] != 0)
|
||
printw (" D: %s;", opts->pa_output_idx);
|
||
|
||
printw (" \n");
|
||
}
|
||
|
||
if ( opts->audio_out_type == 0 && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||
{
|
||
printw ("| Pulse Analog Output: %i kHz; %i Ch; G: %02.0f%% (/|*) ", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->audio_gainA);
|
||
if (opts->audio_gainA == 0.0f) printw ("Auto ");
|
||
else printw ("Manual ");
|
||
if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms);
|
||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||
if (opts->pa_output_idx[0] != 0)
|
||
printw (" D: %s;", opts->pa_output_idx);
|
||
printw (" \n");
|
||
}
|
||
|
||
if (opts->audio_out_type == 5 || opts->audio_out_type == 2)
|
||
{
|
||
printw ("| OSS Audio Output: %i kHz; %i Ch; G: %02.0f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2);
|
||
if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2);
|
||
if (opts->audio_gain == 0) printw (" (+/-) Auto ");
|
||
if (opts->audio_gain > 0) printw (" (+/-) Manual");
|
||
if (opts->use_hpf_d == 1) printw (" HPF");
|
||
if (opts->call_alert == 1) printw (" *CA!"); //Call Alert
|
||
|
||
if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||
{
|
||
printw ("\n| Analog Monitor RMS: %04ld; G: %02.0f%% (/|*) ", opts->rtl_rms, opts->audio_gainA);
|
||
if (opts->audio_gainA == 0.0f) printw ("Auto ");
|
||
else printw ("Manual ");
|
||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||
}
|
||
printw (" \n");
|
||
}
|
||
|
||
if (opts->audio_out_type == 8)
|
||
{
|
||
printw ("| UDP Digital Output: %s:%d; %d kHz %d Ch; %02.0f%%", opts->udp_hostname, opts->udp_portno, opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2);
|
||
if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2);
|
||
if (opts->audio_gain == 0) printw (" (+/-) Auto ");
|
||
if (opts->audio_gain > 0) printw (" (+/-) Manual");
|
||
if (opts->use_hpf_d == 1) printw (" HPF");
|
||
if (opts->call_alert == 1) printw (" *CA!"); //Call Alert
|
||
if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||
printw (" - Monitor RMS: %04ld ", opts->rtl_rms);
|
||
printw (" \n");
|
||
if (opts->udp_sockfdA != 0) //Analog Output on udp port +2
|
||
{
|
||
printw ("| UDP Analog Output: %s:%d; 48 kHz 1 Ch; G: %02.0f%% (/|*) ", opts->udp_hostname, opts->udp_portno+2, opts->audio_gainA);
|
||
if (opts->audio_gainA == 0.0f) printw ("A ");
|
||
else printw ("M ");
|
||
if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms);
|
||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||
printw (" \n");
|
||
}
|
||
}
|
||
|
||
if (opts->m17encoder == 1)
|
||
{
|
||
printw ("| M17 Encoder:");
|
||
if (state->m17encoder_tx == 1 && state->m17_vox == 0) printw (" Toggle TX (\\) ON ;");
|
||
if (state->m17encoder_tx == 0 && state->m17_vox == 0) printw (" Toggle TX (\\) OFF;");
|
||
if (state->m17_vox == 1) printw (" Vox Mode;");
|
||
printw (" Input Gain (/|*): %02.0f%% ", opts->audio_gainA);
|
||
|
||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||
if (opts->audio_in_type != 3 && state->m17_vox == 1) printw ( " SQL: %04ld : %04d;", opts->rtl_rms, opts->rtl_squelch_level);
|
||
printw ("\n");
|
||
|
||
}
|
||
|
||
if (opts->m17_use_ip == 1)
|
||
printw ("| M17 UDP IP Frame Output: %s:%d \n", opts->m17_hostname, opts->m17_portno);
|
||
|
||
if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0)
|
||
{
|
||
printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir);
|
||
}
|
||
|
||
if (opts->wav_out_raw)
|
||
{
|
||
printw ("| Raw Audio Output: %s\n", opts->wav_out_file_raw);
|
||
}
|
||
|
||
if (opts->symbol_out_f) //don't display when not actively capturing
|
||
{
|
||
printw ("| Symbol Bin Output: %s\n", opts->symbol_out_file);
|
||
}
|
||
|
||
if (opts->dmr_stereo_wav == 0 && opts->wav_out_file[0] != 0)
|
||
{
|
||
printw ("| Decoded WAV Output: %s\n", opts->wav_out_file);
|
||
}
|
||
|
||
//new Per Call setup would just be random names until closed,
|
||
//so no need to show, and will be in the event history anyways
|
||
if (opts->dmr_stereo_wav == 1)
|
||
printw ("| Per Call Wav File Enabled to Directory: %s \n", opts->wav_out_dir);
|
||
|
||
#ifdef PRETTY_COLORS
|
||
if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) )
|
||
{
|
||
printw ("| Trunking -");
|
||
if (opts->trunk_tune_group_calls == 0) attron(COLOR_PAIR(2));
|
||
printw (" Group(g)");
|
||
attron(COLOR_PAIR(4));
|
||
if (opts->trunk_tune_private_calls == 0) attron(COLOR_PAIR(2));
|
||
printw (" Private(u)");
|
||
attron(COLOR_PAIR(4));
|
||
if (opts->trunk_tune_data_calls == 0) attron(COLOR_PAIR(2));
|
||
printw (" Data(d)");
|
||
attron(COLOR_PAIR(4));
|
||
if (opts->trunk_tune_enc_calls == 0) attron(COLOR_PAIR(2));
|
||
printw (" Encrypted(e)");
|
||
attron(COLOR_PAIR(4));
|
||
printw (" Calls");
|
||
if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n");
|
||
else printw (" - Black List Mode\n");
|
||
}
|
||
#else //set on to UPPER CASE, off to lower case
|
||
if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) )
|
||
{
|
||
printw ("| Trunking -");
|
||
if (opts->trunk_tune_group_calls == 0) printw (" group(g)");
|
||
else printw (" GROUP(g)");
|
||
if (opts->trunk_tune_private_calls == 0) printw (" private(u)");
|
||
else printw (" PRIVATE(u)");
|
||
if (opts->trunk_tune_data_calls == 0) printw (" data(d)");
|
||
else printw (" DATA(d)");
|
||
if (opts->trunk_tune_enc_calls == 0) printw (" encrypted(e)");
|
||
else printw (" ENCRYPTED(e)");
|
||
printw (" Calls");
|
||
if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n");
|
||
else printw (" - Black List Mode\n");
|
||
}
|
||
#endif
|
||
//print additional information for EDACS modes and toggles
|
||
#ifdef PRETTY_COLORS
|
||
if (opts->p25_trunk == 1 && opts->frame_provoice == 1)
|
||
{
|
||
printw ("| \\--EDACS -");
|
||
if (state->ea_mode == -1)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Standard/Network");
|
||
printw (" Extended Address");
|
||
attron(COLOR_PAIR(4));
|
||
}
|
||
else if (state->ea_mode == 0)
|
||
{
|
||
printw (" Standard/Network");
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Extended Address");
|
||
attron(COLOR_PAIR(4));
|
||
}
|
||
else if (state->ea_mode == 1)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Standard/Network");
|
||
attron(COLOR_PAIR(4));
|
||
printw (" Extended Address");
|
||
}
|
||
printw (" Mode (S);");
|
||
|
||
printw(" ESK: %02X", state->esk_mask);
|
||
printw (" (A);");
|
||
|
||
if (state->ea_mode == 0)
|
||
printw (" AFS: %d:%d:%d;", state->edacs_a_bits, state->edacs_f_bits, state->edacs_s_bits);
|
||
|
||
//TG Hold on EDACS, if specified by user
|
||
if (state->tg_hold != 0)
|
||
{
|
||
// Compute AFS for display purposes only
|
||
int a = (state->tg_hold >> state->edacs_a_shift) & state->edacs_a_mask;
|
||
int f = (state->tg_hold >> state->edacs_f_shift) & state->edacs_f_mask;
|
||
int s = state->tg_hold & state->edacs_s_mask;
|
||
if (state->ea_mode == 1) printw ("\n| \\TG HOLD: %d; ", state->tg_hold);
|
||
else
|
||
{
|
||
char afs_str[8];
|
||
getAfsString(state, afs_str, a, f, s);
|
||
printw ("\n| \\TG HOLD: %d [%s]; ", state->tg_hold, afs_str);
|
||
}
|
||
}
|
||
|
||
attron(COLOR_PAIR(4));
|
||
printw ("\n");
|
||
}
|
||
#else //set on to UPPER CASE, off to lower case
|
||
if (opts->p25_trunk == 1 && opts->frame_provoice == 1)
|
||
{
|
||
printw ("| \\--EDACS -");
|
||
if (state->ea_mode == -1)
|
||
{
|
||
printw (" standard/network");
|
||
printw (" extended address");
|
||
}
|
||
else if (state->ea_mode == 0)
|
||
{
|
||
printw (" STANDARD/NETWORK");
|
||
printw (" extended address");
|
||
}
|
||
else if (state->ea_mode == 1)
|
||
{
|
||
printw (" standard/network");
|
||
printw (" EXTENDED ADDRESS");
|
||
}
|
||
printw (" Mode (S);");
|
||
|
||
printw(" ESK: %02X", state->esk_mask);
|
||
printw (" (A) Toggle; ");
|
||
|
||
if (state->ea_mode == 0)
|
||
printw (" AFS: %d:%d:%d;", state->edacs_a_bits, state->edacs_f_bits, state->edacs_s_bits);
|
||
|
||
//TG Hold on EDACS, if specified by user
|
||
if (state->tg_hold != 0)
|
||
{
|
||
// Compute AFS for display purposes only
|
||
int a = (state->tg_hold >> state->edacs_a_shift) & state->edacs_a_mask;
|
||
int f = (state->tg_hold >> state->edacs_f_shift) & state->edacs_f_mask;
|
||
int s = state->tg_hold & state->edacs_s_mask;
|
||
if (state->ea_mode == 1) printw ("\n| \\TG HOLD: %d; ", state->tg_hold);
|
||
else
|
||
{
|
||
char afs_str[8];
|
||
getAfsString(state, afs_str, a, f, s);
|
||
printw ("\n| \\TG HOLD: %d [%s]; ", state->tg_hold, afs_str);
|
||
}
|
||
}
|
||
|
||
printw ("\n");
|
||
}
|
||
#endif
|
||
// if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n");
|
||
if (state->M == 1)
|
||
{
|
||
if (state->R != 0) printw ("| Forcing Key Priority -- NXDN Sc Key: %05lld \n", state->R);
|
||
if (state->K != 0) printw ("| Forcing Key Priority -- Moto BP Key: %03lld \n", state->K);
|
||
if (state->K1 != 0) printw ("| Forcing Key Priority -- Hytera BP Key: %016llX \n", state->K1);
|
||
if (state->K != 0 && state->K1 != 0) printw ("| Warning! Multiple DMR Key Types Loaded! \n"); //warning may not be required
|
||
}
|
||
if (state->M == 0x21)
|
||
{
|
||
if (state->R != 0) printw ("| Forcing Key Priority -- RC4 Key: %010llX \n", state->R);
|
||
}
|
||
if (state->M == 0x16) printw ("| Forcing Key Priority -- TYT 16-bit Key: %04llX \n", state->H);
|
||
|
||
if (opts->scanner_mode == 1)
|
||
{
|
||
printw ("| Scan Mode: ");
|
||
if (state->lcn_freq_roll != 0)
|
||
printw (" Frequency: %.06lf Mhz", (double)state->trunk_lcn_freq[state->lcn_freq_roll-1]/1000000);
|
||
printw (" Speed: %.02lf sec \n", opts->trunk_hangtime); //not sure values less than 1 make a difference, may be system/environment dependent
|
||
}
|
||
|
||
if (opts->reverse_mute == 1) printw ("| Reverse Mute - Muting Unencrypted Voice\n");
|
||
// if (opts->call_alert == 1) printw ("| Call Alert Tone Enabled\n");
|
||
|
||
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
attroff(COLOR_PAIR(4));
|
||
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
level = (int) state->max / 164; //only update on carrier present
|
||
if (opts->mod_qpsk == 1) level = (int) state->max / 328; //test values here
|
||
if (opts->audio_in_type == 4) level = 50; //hard set when reading symbol bin files, otherwise, it will just be near zero
|
||
if (level > 100) level = 100; //cap max at 100 to prevent it going over
|
||
reset = 1;
|
||
}
|
||
else level = 0;
|
||
|
||
printw ("--Audio Decode----------------------------------------------------------------\n");
|
||
printw ("| Demod/Rate: ");
|
||
if (opts->mod_qpsk == 1) printw ("[QPSK]");
|
||
if (opts->mod_c4fm == 1) printw ("[C4FM]");
|
||
if (opts->mod_gfsk == 1) printw ("[GFSK]");
|
||
printw ( "[%d] \n", (48000*opts->wav_interpolator)/state->samplesPerSymbol);
|
||
if (opts->m17encoder == 1) printw ("| Encoding: [%s] \n", opts->output_name);
|
||
printw ("| Decoding: [%s] ", opts->output_name);
|
||
if (opts->aggressive_framesync == 0) printw ("CRC/(RAS) ");
|
||
//debug -- troubleshoot voice tuning after grant on DMR CC, subsequent grant may not tune because tuner isn't available
|
||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1) printw ("Tuner Locked ");
|
||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) printw ("Tuner Available ");
|
||
printw ("\n");
|
||
printw ("| In Level: [%02d%%] \n", level);
|
||
|
||
if (opts->dmr_stereo == 0)
|
||
{
|
||
printw ("| Voice Error: [%X][%X]", state->errs&0xF, state->errs2&0xF);
|
||
if (opts->slot1_on == 0) printw (" OFF");
|
||
if (opts->slot1_on == 1) printw (" ON");
|
||
printw ("\n");
|
||
}
|
||
|
||
if (opts->dmr_stereo == 1)
|
||
{
|
||
printw ("| Voice Error: [%X][%X] Slot 1 (1)", state->errs&0xF, state->errs2&0xF);
|
||
if (opts->slot1_on == 0) printw (" OFF");
|
||
if (opts->slot1_on == 1) printw (" ON");
|
||
if (opts->slot_preference == 0) printw (" *Preferred (3)");
|
||
printw ("\n");
|
||
printw ("| Voice Error: [%X][%X] Slot 2 (2)", state->errsR&0xF, state->errs2R&0xF);
|
||
if (opts->slot2_on == 0) printw (" OFF");
|
||
if (opts->slot2_on == 1) printw (" ON");
|
||
if (opts->slot_preference == 1) printw (" *Preferred (3)");
|
||
printw ("\n");
|
||
}
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
|
||
printw ("--Call Info-------------------------------------------------------------------\n");
|
||
|
||
//DSTAR
|
||
if (lls == 6 || lls == 7 || lls == 18 || lls == 19)
|
||
{
|
||
printw ("| %s ", SyncTypes[lls]);
|
||
printw ("\n");
|
||
printw ("| RPT2: %s", state->dstar_rpt2);
|
||
printw (" RPT1: %s", state->dstar_rpt1);
|
||
printw ("\n");
|
||
printw ("| DEST: %s", state->dstar_dst);
|
||
printw (" SRC: %s", state->dstar_src);
|
||
printw ("\n");
|
||
printw ("| TEXT: %s", state->dstar_txt);
|
||
printw ("\n");
|
||
printw ("| DATA: %s", state->dstar_gps);
|
||
printw ("\n");
|
||
}
|
||
|
||
//M17
|
||
if (lls == 8 || lls == 9 || lls == 16 || lls == 17)
|
||
{
|
||
|
||
printw ("| ");
|
||
printw ("M17: ");
|
||
|
||
//insert data type and frame information
|
||
if (state->m17_str_dt == 0) printw("Reserved");
|
||
if (state->m17_str_dt == 1) printw("Data ");
|
||
if (state->m17_str_dt == 2) printw("Voice (3200) ");
|
||
if (state->m17_str_dt == 3) printw("Voice (1600) + Data");
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
printw ("DST: ");
|
||
if (state->m17_dst == 0xFFFFFFFFFFFF)
|
||
printw("BROADCAST ");
|
||
else if (state->m17_dst != 0 && state->m17_dst >= 0xEE6B28000000)
|
||
printw("RESERVED (%012llx) ", state->m17_dst);
|
||
else
|
||
printw("%s", state->m17_dst_str);
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
printw ("SRC: ");
|
||
if (state->m17_src != 0 && state->m17_src >= 0xEE6B28000000)
|
||
printw("RESERVED (%012llx)", state->m17_src);
|
||
else
|
||
printw("%s", state->m17_src_str);
|
||
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
printw ("CAN: %02d ", state->m17_can);
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
|
||
//fill in any extra info, like Meta (IV, etc)
|
||
if (state->m17_enc == 1)
|
||
{
|
||
printw (" Scrambler - Type: %d", state->m17_enc_st);
|
||
}
|
||
|
||
if (state->m17_enc == 2)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("AES-CTR - IV: ");
|
||
//display packed meta as IV
|
||
for (i = 0; i < 16; i++)
|
||
printw ("%02X", state->m17_meta[i]);
|
||
}
|
||
|
||
if (state->m17_enc == 3)
|
||
{
|
||
printw (" Reserved Enc - Type: %d", state->m17_enc_st);
|
||
}
|
||
|
||
printw ("\n");
|
||
|
||
}
|
||
|
||
//YSF
|
||
if (lls == 30 || lls == 31)
|
||
{
|
||
// printw ("\n");
|
||
printw ("| ");
|
||
printw ("Fusion - ");
|
||
//insert data type and frame information
|
||
if (state->ysf_dt == 0) printw("V/D1 ");
|
||
if (state->ysf_dt == 1) printw("DATA ");
|
||
if (state->ysf_dt == 2) printw("V/D2 ");
|
||
if (state->ysf_dt == 3) printw("VWFR ");
|
||
printw (" ");
|
||
if (state->ysf_cm == 0) printw("Group/CQ ");
|
||
if (state->ysf_cm == 3) printw("Private ");
|
||
if (state->ysf_cm == 1) printw("Radio ID ");
|
||
if (state->ysf_cm == 2) printw("Reserved ");
|
||
|
||
if (state->ysf_fi == 0) printw("HC ");
|
||
if (state->ysf_fi == 1) printw("CC ");
|
||
if (state->ysf_fi == 2) printw("TC ");
|
||
if (state->ysf_fi == 3) printw("XX ");
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
//NOTE: In Radio ID Mode, the DST will be split on Destination and Source Radio ID values
|
||
printw ("DST: %s ", state->ysf_tgt);
|
||
printw ("SRC: %s ", state->ysf_src);
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("UPL: %s ", state->ysf_upl);
|
||
printw ("DNL: %s ", state->ysf_dnl);
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("RM1: %s ", state->ysf_rm1);
|
||
printw ("RM2: %s ", state->ysf_rm2);
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("RM3: %s ", state->ysf_rm3);
|
||
printw ("RM4: %s ", state->ysf_rm4);
|
||
|
||
//these texts can get pretty long and out of sorts, and lots of 0x20 spaces
|
||
//just going to leave these to only be in the console output
|
||
|
||
// printw ("\n");
|
||
// printw ("| ");
|
||
// printw ("TXT: ");
|
||
// for (i = 4; i < 8; i++)
|
||
// {
|
||
// for (int j = 0; j < 20; j++)
|
||
// {
|
||
// //no spaces and no asterisks
|
||
// if (state->ysf_txt[i][j] != 0x2A)
|
||
// printw ("%c", state->ysf_txt[i][j]);
|
||
// }
|
||
// // printw (" "); //just a single space between each 'block'
|
||
// }
|
||
|
||
printw ("\n");
|
||
|
||
}
|
||
|
||
//NXDN
|
||
if (lls == 28 || lls == 29)
|
||
{
|
||
if (strcmp (state->nxdn_location_category, "Type-D") == 0) idas = 1;
|
||
|
||
if (opts->p25_trunk == 1)
|
||
{
|
||
|
||
printw ("| ");
|
||
if (opts->p25_is_tuned == 0)
|
||
{
|
||
if (idas == 0) printw ("Monitoring RCCH Channel"); //Control Channel
|
||
if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2 Channel
|
||
if (state->p25_cc_freq != 0)
|
||
{
|
||
printw (" - Frequency: %.06lf Mhz ", (double)state->p25_cc_freq/1000000);
|
||
}
|
||
}
|
||
else if (opts->p25_is_tuned == 1)
|
||
{
|
||
if (idas == 0) printw ("Monitoring RTCH Channel"); //Traffic Channel
|
||
if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2
|
||
if (state->p25_vc_freq[0] != 0)
|
||
{
|
||
printw (" - Frequency: %.06lf Mhz ", (double)state->p25_vc_freq[0]/1000000);
|
||
}
|
||
}
|
||
|
||
printw ("\n");
|
||
}
|
||
|
||
|
||
|
||
printw ("| ");
|
||
// #ifdef LIMAZULUTWEAKS
|
||
if (idas == 0) printw ("NXDN - RAN: %02d; ", state->nxdn_last_ran);
|
||
if (idas == 1) printw ("IDAS - Area: %02d; ", state->nxdn_last_ran);
|
||
// #else
|
||
// if (idas == 0) printw ("NXDN - RAN: [%02d] ", rn);
|
||
// if (idas == 1) printw ("IDAS - Area: [%02d] ", rn);
|
||
// #endif
|
||
if (state->nxdn_location_site_code != 0)
|
||
{
|
||
printw ("Cat: %s; ", state->nxdn_location_category);
|
||
printw ("Sys Code: %d; ", state->nxdn_location_sys_code);
|
||
printw ("Site Code: %d; ", state->nxdn_location_site_code);
|
||
}
|
||
|
||
//if system supports Direct Frequency Assignment
|
||
if (state->nxdn_rcn == 1) printw ("DFA ");
|
||
|
||
printw ("\n");
|
||
printw ("| ");
|
||
printw ("TGT: [%5d] ", state->nxdn_last_tg);
|
||
printw ("SRC: [%5d] ", state->nxdn_last_rid);
|
||
printw ("Alias: [%s]", state->generic_talker_alias[0]);
|
||
|
||
//Group Name Labels from CSV import
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == state->nxdn_last_tg)
|
||
{
|
||
printw ("TG: ");
|
||
attron(COLOR_PAIR(4));
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s] ", state->group_array[k].groupMode);
|
||
}
|
||
else if (state->group_array[k].groupNumber == state->nxdn_last_rid)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
}
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
|
||
if (state->carrier == 1)
|
||
{
|
||
printw(" %s ", state->nxdn_call_type);
|
||
}
|
||
printw ("\n|");
|
||
if (state->nxdn_cipher_type > 0)
|
||
{
|
||
// printw (" ALG: %d Key ID: %02X ", state->nxdn_cipher_type, state->nxdn_key);
|
||
printw (" ALG: %d Key ID: %02d ", state->nxdn_cipher_type, state->nxdn_key);
|
||
}
|
||
if (state->nxdn_cipher_type == 0x1 && state->carrier == 1)
|
||
{
|
||
if (state->R == 0) attron(COLOR_PAIR(2));
|
||
printw ("Scrambler ");
|
||
if (state->R == 0) attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
if (state->R != 0)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("Seed: %04llX ", state->payload_miN);
|
||
printw ("Key: %05lld ", state->R );
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
if (state->nxdn_cipher_type == 0x2 && state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("IV: %016llX ", state->payload_miN);
|
||
attron(COLOR_PAIR(2));
|
||
printw ("DES1 ");
|
||
if (state->R != 0) printw ("Key: %016llX ", state->R);
|
||
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 ");
|
||
if (state->aes_key_loaded[0] == 1) printw ("KS: %016llX", state->A4[0]);
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->nxdn_cipher_type > 0x3 && state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw ("Unknown Encryption ");
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//Active Trunking Channels (NXDN and IDAS)
|
||
if (1 == 1) //opts->p25_trunk
|
||
{
|
||
printw ("\n");
|
||
printw ("| ");
|
||
|
||
//active channel display
|
||
attron(COLOR_PAIR(4));
|
||
for (int i = 0; i < 16; i++)
|
||
{
|
||
if (state->active_channel[i] != 0) printw ("%s", state->active_channel[i]);
|
||
}
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
}
|
||
|
||
//TG Hold, if specified by user
|
||
if (state->tg_hold != 0) printw ("TG HOLD: %d", state->tg_hold);
|
||
|
||
printw("\n");
|
||
}
|
||
|
||
//P25 and DMR BS/MS
|
||
if ( lls == 0 || lls == 1 || lls == 12 || lls == 13 || lls == 10 ||
|
||
lls == 11 || lls == 32 || lls == 33 || lls == 34 || lls == 35 || lls == 36)
|
||
{
|
||
printw ("| ");
|
||
if (lls > 1 && lls < 30)
|
||
{
|
||
printw ("DMR BS - DCC: %02i; ", state->dmr_color_code);
|
||
// printw ("%s %s", state->dmr_branding, state->dmr_branding_sub);
|
||
printw ("%s ", state->dmr_branding);
|
||
printw ("%s", state->dmr_branding_sub);
|
||
printw ("%s", state->dmr_site_parms); //site id, net id, etc
|
||
if (state->dmr_rest_channel > 0)
|
||
{
|
||
printw ("Rest LSN: %02d; ", state->dmr_rest_channel);
|
||
if (state->trunk_chan_map[state->dmr_rest_channel] != 0)
|
||
{
|
||
printw ("Freq: %.06lf Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000);
|
||
}
|
||
}
|
||
else if (state->p25_cc_freq != 0)
|
||
{
|
||
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||
}
|
||
|
||
}
|
||
else if (lls == 32 || lls == 33 || lls == 34)
|
||
{
|
||
printw ("DMR MS - DCC: %02i; ", state->dmr_color_code);
|
||
}
|
||
else if (lls == 0 || lls == 1) //P1
|
||
{
|
||
printw ("P25p1 - %05llX:%03llX:%03llX; RFSS: %lld SITE: %lld ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
|
||
if (state->p25_cc_freq != 0)
|
||
{
|
||
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||
}
|
||
|
||
//load talker aliases here (Moto, Tait, Harris)
|
||
for (int16_t i = 0; i < state->group_tally; i++)
|
||
{
|
||
if (state->group_array[i].groupNumber == state->lastsrc) //or state->lastsrc
|
||
{
|
||
sprintf (state->generic_talker_alias[0], "%s", state->group_array[i].groupName);
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
else if (lls == 35 || lls == 36) //P2
|
||
{
|
||
printw ("P25p2 - %05llX:%03llX:%03llX; RFSS: %lld SITE: %lld ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
|
||
if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Phase 2 Missing Parameters ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
else if (state->p2_wacn == 0xFFFFF || state->p2_sysid == 0xFFF || state->p2_cc == 0xFFF)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw (" Phase 2 Invalid Parameters ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
else
|
||
{
|
||
if (state->p25_cc_freq != 0)
|
||
{
|
||
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||
}
|
||
}
|
||
|
||
//load talker aliases here (Moto, Tait, Harris)
|
||
for (int16_t i = 0; i < state->group_tally; i++)
|
||
{
|
||
if (state->group_array[i].groupNumber == state->lastsrc)
|
||
{
|
||
sprintf (state->generic_talker_alias[0], "%s", state->group_array[i].groupName);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//load talker aliases here (Moto, Tait, Harris)
|
||
for (int16_t i = 0; i < state->group_tally; i++)
|
||
{
|
||
if (state->group_array[i].groupNumber == state->lastsrcR)
|
||
{
|
||
sprintf (state->generic_talker_alias[1], "%s", state->group_array[i].groupName);
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
printw ("\n");
|
||
//Slot 1 [0]
|
||
printw ("| SLOT 1 - ");
|
||
if (state->dmrburstL < 16 && state->carrier == 1 && state->lasttg > 0 && state->lastsrc > 0)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
}
|
||
printw ("TGT: [%8i] SRC: [%8i] ", state->lasttg, state->lastsrc);
|
||
if (state->dmrburstL != 16 && state->carrier == 1 && state->lasttg > 0 && state->lastsrc > 0)
|
||
{
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
printw ("%s | ", state->call_string[0]);
|
||
printw ("%s ", DMRBusrtTypes[state->dmrburstL]);
|
||
|
||
if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21)) printw ("*M*");
|
||
|
||
|
||
printw ("\n");
|
||
|
||
printw ("| V XTRA | "); //10 spaces
|
||
|
||
if(state->dmrburstL == 16 && state->payload_algid == 0 && state->dmr_so & 0x40) //4F or CF mask? & 0xCF currently //&& (state->dmr_so & 0xCF) == 0x40
|
||
{
|
||
attron(COLOR_PAIR(5));
|
||
printw (" **BP** ");
|
||
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 & 0x40)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("BP 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 & 0x40)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("Hytera BP 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 & 0x40)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("ALG: 0x%02X KEY: 0x%02X MI: 0x%08llX ", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//P25 FDMA/TDMA
|
||
if(state->dmrburstL > 19 && state->payload_algid > 0 && state->payload_algid != 0x80)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("ALG: 0x%02X KEY: 0x%04X MI: 0x%016llX ", state->payload_algid, state->payload_keyid, state->payload_miP);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//Anytone 0x01 will never show here since its converted to 0x21 for handling
|
||
if (state->payload_algid == 0xAA || state->payload_algid == 0x21 || state->payload_algid == 0x01)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("RC4 ");
|
||
if (state->R != 0) { printw("Key: %010llX ", state->R); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x81 || state->payload_algid == 0x22)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES1 ");
|
||
if (state->R != 0) { printw("Key: %010llX ", state->R); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x9F)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES-XL ");
|
||
if (state->R != 0) { printw("Key: %010llX ", state->R); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x82)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES2 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x83)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES3 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x89 || state->payload_algid == 0x24)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("AES-128 ");
|
||
if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A2[0]); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x84 || state->payload_algid == 0x25 || state->payload_algid == 0x05)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("AES-256 ");
|
||
if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algid == 0x02)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("Hytera Enhanced");
|
||
// if (state->R != 0)
|
||
// printw(" Key: %010X", state->R);
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
printw ("\n");
|
||
|
||
//printw ("| | "); //10 spaces
|
||
printw ("| D XTRA | ");
|
||
|
||
attron(COLOR_PAIR(4));
|
||
|
||
if(state->dmrburstL == 16 || state->dmrburstL == 21 || state->dmrburstL == 26 || state->dmrburstL == 27 || state->dmrburstL == 32) //only during call
|
||
{
|
||
|
||
attron(COLOR_PAIR(4));
|
||
|
||
//Embedded GPS (not LRRP)
|
||
printw ("%s ", state->dmr_embedded_gps[0]);
|
||
|
||
//Embedded Talker Alias String
|
||
printw ("%s ", state->generic_talker_alias[0]);
|
||
|
||
attroff(COLOR_PAIR(5));
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
|
||
//LRRP
|
||
if(state->dmrburstL != 16) //only during data and no trunking
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("%s", state->dmr_lrrp_gps[0]);
|
||
}
|
||
|
||
//Group Name Labels from CSV import
|
||
if (state->dmrburstL == 16 || state->dmrburstL > 19)
|
||
{
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == state->lasttg)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s] ", state->group_array[k].groupMode);
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
|
||
printw ("\n");
|
||
|
||
//Slot 2 [1] -- Also Including DMR MS now to keep the display more 'uniform' in nature
|
||
// if (lls < 30 || lls == 35 || lls == 36)
|
||
{
|
||
printw ("| SLOT 2 - ");
|
||
if (state->dmrburstR < 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
}
|
||
printw ("TGT: [%8i] SRC: [%8i] ", state->lasttgR, state->lastsrcR);
|
||
if (state->dmrburstR != 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0)
|
||
{
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
printw ("%s | ", state->call_string[1]);
|
||
printw ("%s ", DMRBusrtTypes[state->dmrburstR]);
|
||
|
||
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*");
|
||
|
||
printw ("\n");
|
||
|
||
printw ("| V XTRA | "); //10 spaces
|
||
|
||
if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->dmr_soR & 0x40) //4F or CF mask?
|
||
{
|
||
attron(COLOR_PAIR(5));
|
||
printw (" **BP** ");
|
||
attroff(COLOR_PAIR(5));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->K > 0 && state->dmr_soR & 0x40 && state->dmr_fidR == 0x10)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("BP 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 & 0x40 && state->dmr_fidR == 0x68)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("Hytera BP 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 & 0x40)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("ALG: 0x%02X KEY: 0x%02X MI: 0x%08llX ", state->payload_algidR, state->payload_keyidR, state->payload_miR);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
//P25-P1 and P2
|
||
if(state->dmrburstR > 19 && state->payload_algidR > 0 && state->payload_algidR != 0x80)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("ALG: 0x%02X KEY: 0x%04X MI: 0x%016llX ", state->payload_algidR, state->payload_keyidR, state->payload_miN);
|
||
attroff(COLOR_PAIR(1));
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
//Anytone 0x01 will never show here since its converted to 0x21 for handling
|
||
if (state->payload_algidR == 0xAA || state->payload_algidR == 0x21 || state->payload_algidR == 0x01)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("RC4 ");
|
||
if (state->RR != 0) { printw("Key: %010llX ", state->RR); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x81 || state->payload_algidR == 0x22)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES1 ");
|
||
if (state->RR != 0) { printw("Key: %010llX ", state->RR); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x9F)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES-XL ");
|
||
if (state->RR != 0) { printw("Key: %010llX ", state->RR); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x82)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES2 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x83)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("DES3 ");
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x89 || state->payload_algidR == 0x24)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("AES-128 ");
|
||
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A2[1]); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x84 || state->payload_algidR == 0x25 || state->payload_algidR == 0x05)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("AES-256 ");
|
||
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
if (state->payload_algidR == 0x02)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw("Hytera Enhanced");
|
||
// if (state->RR != 0)
|
||
// printw(" Key: %010X", state->RR);
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
printw ("\n");
|
||
|
||
//printw ("| | ");
|
||
printw ("| D XTRA | ");
|
||
|
||
attron(COLOR_PAIR(4));
|
||
|
||
if(state->dmrburstR == 16 || state->dmrburstR == 21) //only during call
|
||
{
|
||
|
||
//Embedded GPS (not LRRP)
|
||
attron(COLOR_PAIR(4));
|
||
printw ("%s ", state->dmr_embedded_gps[1]);
|
||
|
||
//Embedded Talker Alias String
|
||
printw ("%s ", state->generic_talker_alias[1]);
|
||
|
||
attroff(COLOR_PAIR(5));
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
|
||
}
|
||
|
||
//LRRP
|
||
if(state->dmrburstR != 16) //only during data and no trunking
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("%s", state->dmr_lrrp_gps[1]);
|
||
}
|
||
|
||
//Group Name Labels from CSV import
|
||
if (state->dmrburstR == 16 || state->dmrburstR > 19)
|
||
{
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == state->lasttgR)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s] ", state->group_array[k].groupMode);
|
||
}
|
||
if (state->carrier == 1)
|
||
{
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
}
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
|
||
printw ("\n");
|
||
|
||
if (1 == 1) //opts->p25_trunk == 1
|
||
{
|
||
printw ("| | "); //Active Trunking Channels
|
||
|
||
//active channel display
|
||
attron(COLOR_PAIR(4));
|
||
for (int i = 0; i < 31; i++) //up to 31 idas channels
|
||
{
|
||
if (state->active_channel[i] != 0) printw ("%s", state->active_channel[i]);
|
||
}
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
printw ("\n");
|
||
}
|
||
|
||
if (1 == 1) //opts->p25_trunk == 1
|
||
{
|
||
printw ("| | "); //Currently Tuned Frequency
|
||
|
||
// Tuned Frequency Display
|
||
if (state->p25_vc_freq[0] != 0)
|
||
{
|
||
attron(COLOR_PAIR(4));
|
||
printw ("Frequency: %.06lf MHz ", (double)state->p25_vc_freq[0]/1000000);
|
||
}
|
||
|
||
//TG Hold, if specified by user
|
||
if (state->tg_hold != 0) printw ("TG HOLD: %d", state->tg_hold);
|
||
|
||
if (state->carrier == 1) attron(COLOR_PAIR(3));
|
||
else attroff(COLOR_PAIR(4));
|
||
printw ("\n");
|
||
}
|
||
|
||
} // end if not MS
|
||
} //end DMR BS Types
|
||
|
||
//dPMR
|
||
if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27)
|
||
{
|
||
printw ("| DCC: [%i] ", state->dpmr_color_code);
|
||
printw ("TGT: [%s] SRC: [%s] ", state->dpmr_target_id, state->dpmr_caller_id);
|
||
printw ("\n| ");
|
||
if (state->dPMRVoiceFS2Frame.Version[0] == 3)
|
||
{
|
||
attron(COLOR_PAIR(2));
|
||
printw ("Scrambler ");
|
||
attroff(COLOR_PAIR(2));
|
||
attron(COLOR_PAIR(3));
|
||
if (state->R != 0)
|
||
{
|
||
attron(COLOR_PAIR(1));
|
||
printw ("KEY VALUE: [%05lld] ", state->R );
|
||
//printw ("SEED: [%04llX]", state->payload_miN);
|
||
attron(COLOR_PAIR(3));
|
||
}
|
||
}
|
||
printw ("\n");
|
||
}
|
||
|
||
//EDACS and ProVoice
|
||
if (lls == 14 || lls == 15 || lls == 37 || lls == 38)
|
||
{
|
||
attroff (COLOR_PAIR(3)); //colors off for EDACS
|
||
if (state->edacs_site_id != 0)
|
||
{
|
||
if (opts->p25_is_tuned == 0)
|
||
{
|
||
printw ("| Monitoring CC - LCN [%02d]\n", state->edacs_cc_lcn);
|
||
}
|
||
else
|
||
{
|
||
printw ("| Monitoring VC - LCN [%02d]\n", state->edacs_tuned_lcn);
|
||
//since we are tuned, keep updating the time so it doesn't disappear during call
|
||
edacs_channel_tree[state->edacs_tuned_lcn][5] = time(NULL);
|
||
}
|
||
printw ("| SITE [%03lld][%02llX]", state->edacs_site_id, state->edacs_site_id);
|
||
|
||
if (state->ea_mode == 1)
|
||
{
|
||
printw (" Extended Addressing");
|
||
}
|
||
else printw (" Standard/Networked");
|
||
if (state->esk_mask == 0xA0)
|
||
{
|
||
printw (" w/ ESK");
|
||
}
|
||
else printw (" w/o ESK");
|
||
printw ("\n");
|
||
}
|
||
for (i = 1; i <= state->edacs_lcn_count; i++)
|
||
{
|
||
// Compute AFS for display purposes only
|
||
int a = (edacs_channel_tree[i][2] >> state->edacs_a_shift) & state->edacs_a_mask;
|
||
int f = (edacs_channel_tree[i][2] >> state->edacs_f_shift) & state->edacs_f_mask;
|
||
int s = edacs_channel_tree[i][2] & state->edacs_s_mask;
|
||
printw ("| - LCN [%02d][%010.06lf] MHz", i, (double)state->trunk_lcn_freq[i-1]/1000000);
|
||
|
||
//print Control Channel on LCN line with the current Control Channel
|
||
if ( (i) == state->edacs_cc_lcn)
|
||
{
|
||
attron (COLOR_PAIR(1)); //yellow
|
||
printw (" Control Channel");
|
||
attroff (COLOR_PAIR(1));
|
||
}
|
||
|
||
int print_call = 0;
|
||
//print active calls on corresponding LCN line
|
||
if ((i != state->edacs_cc_lcn) && time(NULL) - edacs_channel_tree[i][5] < 2)
|
||
{
|
||
print_call = 3;
|
||
attron (COLOR_PAIR(3));
|
||
}
|
||
//print dying or dead calls in red for x seconds longer
|
||
else if ( (i != state->edacs_cc_lcn) && (time(NULL) - edacs_channel_tree[i][5] >= 2) && (time(NULL) - edacs_channel_tree[i][5] < 5) )
|
||
{
|
||
print_call = 2;
|
||
attron (COLOR_PAIR(2));
|
||
}
|
||
|
||
if (print_call != 0)
|
||
{
|
||
if (state->ea_mode == 1)
|
||
{
|
||
// Voice call
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_VOICE) != 0)
|
||
{
|
||
// Group call
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_GROUP) != 0)
|
||
printw (" TGT [%8lld] SRC [%8lld]", edacs_channel_tree[i][2], edacs_channel_tree[i][3] );
|
||
// I-Call
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_INDIVIDUAL) != 0)
|
||
printw (" TGT [%8lld] SRC [%8lld] I-Call", edacs_channel_tree[i][2], edacs_channel_tree[i][3] );
|
||
// System all-call
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_ALL_CALL) != 0)
|
||
printw (" TGT [ SYSTEM ] SRC [%8lld] All-Call", edacs_channel_tree[i][3] );
|
||
// Interconnect call
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_INTERCONNECT) != 0)
|
||
printw (" TGT [ SYSTEM ] SRC [%8lld] Interconnect", edacs_channel_tree[i][3] );
|
||
// Test call
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_TEST_CALL) != 0)
|
||
printw (" TGT [ SYSTEM ] SRC [ SYSTEM ] Test Call");
|
||
// Unknown call
|
||
else
|
||
printw (" Unknown call type" );
|
||
|
||
// Call flags
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_TEST_CALL) != 0) {}
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]");
|
||
else printw (" [Dig]");
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]");
|
||
}
|
||
else
|
||
// Data call
|
||
printw (" TGT [ DATA ] SRC [%8lld] Data", edacs_channel_tree[i][3] );
|
||
}
|
||
else
|
||
{
|
||
// Voice call
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_VOICE) != 0)
|
||
{
|
||
// Group call
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_GROUP) != 0)
|
||
{
|
||
char afs_str[8];
|
||
getAfsString(state, afs_str, a, f, s);
|
||
printw (" TGT [%6lld][%s] SRC [%5lld]", edacs_channel_tree[i][2], afs_str, edacs_channel_tree[i][3] );
|
||
}
|
||
// I-Call
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_INDIVIDUAL) != 0)
|
||
if (getAfsStringLength(state) == 6)
|
||
printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", edacs_channel_tree[i][2], edacs_channel_tree[i][3] );
|
||
else
|
||
printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", edacs_channel_tree[i][2], edacs_channel_tree[i][3] );
|
||
// System all-call
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_ALL_CALL) != 0)
|
||
if (getAfsStringLength(state) == 6)
|
||
printw (" TGT [ SYSTEM ] SRC [%5lld] All-Call", edacs_channel_tree[i][3] );
|
||
else
|
||
printw (" TGT [ SYSTEM ] SRC [%5lld] All-Call", edacs_channel_tree[i][3] );
|
||
// Interconnect call
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_INTERCONNECT) != 0)
|
||
if (getAfsStringLength(state) == 6)
|
||
printw (" TGT [ SYSTEM ] SRC [%5lld] Interconnect", edacs_channel_tree[i][3] );
|
||
else
|
||
printw (" TGT [ SYSTEM ] SRC [%5lld] Interconnect", edacs_channel_tree[i][3] );
|
||
// Test call
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_TEST_CALL) != 0)
|
||
if (getAfsStringLength(state) == 6)
|
||
printw (" TGT [ SYSTEM ] SRC [ SYS ] Test Call");
|
||
else
|
||
printw (" TGT [ SYSTEM ] SRC [ SYS ] Test Call");
|
||
// Unknown call
|
||
else
|
||
printw (" Unknown call type" );
|
||
|
||
// Call flags
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_TEST_CALL) != 0) {}
|
||
else if ((edacs_channel_tree[i][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]");
|
||
else printw (" [Dig]");
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_AGENCY_CALL) != 0) printw ("[A]");
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_FLEET_CALL) != 0) printw ("[F]");
|
||
if ((edacs_channel_tree[i][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]");
|
||
}
|
||
// Data call
|
||
else
|
||
if (getAfsStringLength(state) == 6)
|
||
printw (" TGT [ DATA ] SRC [%5lld] Data", edacs_channel_tree[i][3] );
|
||
else
|
||
printw (" TGT [ DATA ] SRC [%5lld] Data", edacs_channel_tree[i][3] );
|
||
}
|
||
for (int k = 0; k < state->group_tally; k++)
|
||
{
|
||
if (state->group_array[k].groupNumber == edacs_channel_tree[i][2] && edacs_channel_tree[i][2] != 0)
|
||
{
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s]", state->group_array[k].groupMode);
|
||
break;
|
||
}
|
||
else if (state->group_array[k].groupNumber == edacs_channel_tree[i][3] && edacs_channel_tree[i][3] != 0)
|
||
{
|
||
printw (" [%s]", state->group_array[k].groupName);
|
||
printw ("[%s]", state->group_array[k].groupMode);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (print_call == 3)
|
||
attroff (COLOR_PAIR(3));
|
||
else if (print_call == 2)
|
||
attroff (COLOR_PAIR(2));
|
||
}
|
||
|
||
if (i == state->edacs_tuned_lcn && opts->p25_is_tuned == 1) printw (" **T**"); //asterisk which lcn is tuned
|
||
printw ("\n");
|
||
}
|
||
if (state->carrier == 1)
|
||
{
|
||
attron (COLOR_PAIR(3));
|
||
}
|
||
}
|
||
|
||
//fence bottom
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
//colors off
|
||
if (state->carrier == 1){ //same as above
|
||
attroff(COLOR_PAIR(3));
|
||
}
|
||
//only print event history if enabled
|
||
if (opts->ncurses_history == 1)
|
||
{
|
||
attron(COLOR_PAIR(4)); //cyan for history
|
||
printw ("--Latest Event History ([|])---Slot %d (\\)-------------------------------------\n", eh_slot+1);
|
||
for (uint16_t i = (state->eh_index+1); i < (state->eh_index+11); i++)
|
||
{
|
||
// if ((i%255) == 0) continue; //0 is the event in progress before completion
|
||
|
||
char text_string[2000];
|
||
sprintf (text_string, "%s", "BUMBLEBEETUNA");
|
||
uint8_t slot = eh_slot;
|
||
|
||
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].event_string, 13) != 0)
|
||
{
|
||
memcpy(text_string, state->event_history_s[slot].Event_History_Items[i%255].event_string, 71*sizeof(char));
|
||
text_string[71] = 0; //terminate string
|
||
printw ("| #%03d %s \n", i%255, text_string);
|
||
}
|
||
else printw ("| #%03d \n", i%255); //empty event, but since we can freely scroll now, keeps things uniform
|
||
|
||
sprintf (text_string, "%s", "BUMBLEBEETUNA");
|
||
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].text_message, 13) != 0)
|
||
printw ("| %s \n", state->event_history_s[slot].Event_History_Items[i%255].text_message);
|
||
|
||
sprintf (text_string, "%s", "BUMBLEBEETUNA");
|
||
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].alias, 13) != 0)
|
||
printw ("| Alias: %s \n", state->event_history_s[slot].Event_History_Items[i%255].alias);
|
||
|
||
sprintf (text_string, "%s", "BUMBLEBEETUNA");
|
||
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].gps_s, 13) != 0)
|
||
printw ("| GPS: %s \n", state->event_history_s[slot].Event_History_Items[i%255].gps_s);
|
||
|
||
}
|
||
printw ("------------------------------------------------------------------------------\n");
|
||
attroff(COLOR_PAIR(4)); //cyan for history
|
||
}
|
||
|
||
refresh();
|
||
|
||
//keyboard shortcuts - codes same as ascii codes
|
||
if (c == 27) //esc key, open menu
|
||
{
|
||
if (opts->m17encoder == 0) //don't allow menu if using M17 encoder
|
||
ncursesMenu (opts, state);
|
||
}
|
||
|
||
//use k and l keys to test tg hold toggles on slots 1 and slots 2
|
||
if (c == 107) //'k' key, hold tg on slot 1 for trunking purposes, or toggle clear
|
||
{
|
||
if (state->tg_hold == 0)
|
||
state->tg_hold = state->lasttg;
|
||
else state->tg_hold = 0;
|
||
|
||
if ( (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1) && (state->tg_hold == 0) )
|
||
state->tg_hold = state->nxdn_last_tg;
|
||
|
||
else if (opts->frame_provoice == 1 && state->ea_mode == 0)
|
||
state->tg_hold = state->lastsrc;
|
||
}
|
||
|
||
if (c == 108) //'l' key, hold tg on slot 2 for trunking purposes, or toggle clear
|
||
{
|
||
if (state->tg_hold == 0)
|
||
state->tg_hold = state->lasttgR;
|
||
else state->tg_hold = 0;
|
||
}
|
||
|
||
//toggling when 48k/1 OSS still has some lag -- needed to clear out the buffer when switching
|
||
if (c == 49) // '1' key, toggle slot1 on
|
||
{
|
||
//switching, but want to control each seperately plz
|
||
if (opts->slot1_on == 1)
|
||
{
|
||
opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
||
// opts->slot_preference = 1; //slot 2
|
||
//clear any previously buffered audio
|
||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||
state->audio_out_idx2 = 0;
|
||
state->audio_out_idx = 0;
|
||
}
|
||
else if (opts->slot1_on == 0)
|
||
{
|
||
opts->slot1_on = 1;
|
||
if (opts->audio_out_type == 5) //OSS 48k/1
|
||
{
|
||
opts->slot_preference = 0; //slot 1
|
||
// opts->slot2_on = 0; //turn off slot 2
|
||
}
|
||
}
|
||
}
|
||
|
||
if (c == 50) // '2' key, toggle slot2 on
|
||
{
|
||
//switching, but want to control each seperately plz
|
||
if (opts->slot2_on == 1)
|
||
{
|
||
opts->slot2_on = 0;
|
||
opts->slot_preference = 0; //slot 1
|
||
//clear any previously buffered audio
|
||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||
memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
||
memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
||
state->audio_out_idx2R = 0;
|
||
state->audio_out_idxR = 0;
|
||
}
|
||
else if (opts->slot2_on == 0)
|
||
{
|
||
opts->slot2_on = 1;
|
||
if (opts->audio_out_type == 5) //OSS 48k/1
|
||
{
|
||
opts->slot_preference = 1; //slot 2
|
||
// opts->slot1_on = 0; //turn off slot 1
|
||
}
|
||
}
|
||
}
|
||
|
||
// if (c == 51) //'3' key, toggle slot preference on 48k/1
|
||
// {
|
||
// if (opts->slot_preference == 1) opts->slot_preference = 0;
|
||
// else opts->slot_preference = 1;
|
||
// }
|
||
|
||
if (c == 51) //'3' key, cycle slot preference
|
||
{
|
||
if (opts->slot_preference == 0 || opts->slot_preference == 1) opts->slot_preference++;
|
||
else opts->slot_preference = 0;
|
||
}
|
||
|
||
if (c == 43) //+ key, increment audio_gain
|
||
{
|
||
|
||
if (opts->audio_gain < 50)
|
||
opts->audio_gain++;
|
||
|
||
state->aout_gain = opts->audio_gain;
|
||
state->aout_gainR = opts->audio_gain;
|
||
|
||
opts->audio_gainR = opts->audio_gain;
|
||
|
||
}
|
||
|
||
if (c == 45) //- key, decrement audio_gain
|
||
{
|
||
|
||
if (opts->audio_gain > 0)
|
||
opts->audio_gain--;
|
||
|
||
state->aout_gain = opts->audio_gain;
|
||
state->aout_gainR = opts->audio_gain;
|
||
|
||
//reset to default on 0 for auto
|
||
if (opts->audio_gain == 0)
|
||
{
|
||
state->aout_gain = 25;
|
||
state->aout_gainR = 25;
|
||
}
|
||
|
||
opts->audio_gainR = opts->audio_gain;
|
||
|
||
}
|
||
|
||
if (c == 42) // * key, increment audio_gainA
|
||
{
|
||
if (opts->audio_gainA < 100)
|
||
opts->audio_gainA++;
|
||
}
|
||
|
||
if (c == 47) // / key, decrement audio_gainA
|
||
{
|
||
if (opts->audio_gainA > 0)
|
||
opts->audio_gainA--;
|
||
}
|
||
|
||
if (c == 122) //'z' key, toggle payload to console
|
||
{
|
||
if (opts->payload == 1) opts->payload = 0;
|
||
else opts->payload = 1;
|
||
}
|
||
|
||
if (c == 99) //'c' key, toggle compact mode
|
||
{
|
||
if (opts->ncurses_compact == 1) opts->ncurses_compact = 0;
|
||
else opts->ncurses_compact = 1;
|
||
}
|
||
|
||
if (c == 116) //'t' key, toggle trunking
|
||
{
|
||
if (opts->p25_trunk == 1) opts->p25_trunk = 0;
|
||
else opts->p25_trunk = 1;
|
||
}
|
||
|
||
if (c == 121) //'y' key, toggle scanner mode
|
||
{
|
||
if (opts->scanner_mode == 1) opts->scanner_mode = 0;
|
||
else opts->scanner_mode = 1;
|
||
opts->p25_trunk = 0; //turn off trunking mode
|
||
}
|
||
|
||
if (c == 97) //'a' key, toggle call alert beep
|
||
{
|
||
if (opts->call_alert == 1) opts->call_alert = 0;
|
||
else opts->call_alert = 1;
|
||
}
|
||
|
||
if (c == 104) //'h' key, toggle history
|
||
{
|
||
if (opts->ncurses_history == 1) opts->ncurses_history = 0;
|
||
else opts->ncurses_history = 1;
|
||
}
|
||
|
||
if (c == 113) //'q' key, quit
|
||
{
|
||
exitflag = 1;
|
||
}
|
||
|
||
if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr)
|
||
{
|
||
if (state->M == 1 || state->M == 0x21) state->M = 0;
|
||
else state->M = 1;
|
||
}
|
||
|
||
if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry
|
||
{
|
||
if (state->M == 1 || state->M == 0x21) state->M = 0;
|
||
else state->M = 0x21;
|
||
}
|
||
|
||
if (c == 105) //'i' key, toggle signal inversion on inverted types
|
||
{
|
||
//Set all signal for inversion or uninversion
|
||
if (opts->inverted_dmr == 0)
|
||
{
|
||
opts->inverted_dmr = 1;
|
||
opts->inverted_dpmr = 1;
|
||
opts->inverted_x2tdma = 1;
|
||
opts->inverted_ysf = 1;
|
||
opts->inverted_m17 = 1;
|
||
}
|
||
else
|
||
{
|
||
opts->inverted_dmr = 0;
|
||
opts->inverted_dpmr = 0;
|
||
opts->inverted_x2tdma = 0;
|
||
opts->inverted_ysf = 0;
|
||
opts->inverted_m17 = 0;
|
||
}
|
||
}
|
||
|
||
if (c == 109) //'m' key, toggle qpsk/c4fm - everything but phase 2
|
||
{
|
||
if (state->rf_mod == 0)
|
||
{
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 1;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 1;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
else
|
||
{
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
}
|
||
|
||
if (c == 77) //'M' key, toggle qpsk - phase 2 6000 sps
|
||
{
|
||
if (state->rf_mod == 0)
|
||
{
|
||
opts->mod_c4fm = 0;
|
||
opts->mod_qpsk = 1;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 1;
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
}
|
||
else
|
||
{
|
||
opts->mod_c4fm = 1;
|
||
opts->mod_qpsk = 0;
|
||
opts->mod_gfsk = 0;
|
||
state->rf_mod = 0;
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
}
|
||
}
|
||
|
||
if (c == 82) //'R', save symbol capture bin with date/time string as name
|
||
{
|
||
sprintf (opts->symbol_out_file, "%s %s.bin", datestr, timestr);
|
||
openSymbolOutFile (opts, state);
|
||
}
|
||
|
||
if (c == 114) //'r' key, stop capturing symbol capture bin file
|
||
{
|
||
if (opts->symbol_out_f)
|
||
{
|
||
closeSymbolOutFile (opts, state);
|
||
sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file);
|
||
}
|
||
}
|
||
|
||
#ifdef __CYGWIN__
|
||
//do nothing
|
||
#else
|
||
if (c == 32) //'space bar' replay last bin file (rework to do wav files too?)
|
||
{
|
||
struct stat stat_buf;
|
||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||
{
|
||
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||
goto SKIPR;
|
||
}
|
||
if (S_ISREG(stat_buf.st_mode))
|
||
{
|
||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||
opts->audio_in_type = 4; //symbol capture bin files
|
||
}
|
||
SKIPR: ; //do nothing
|
||
}
|
||
#endif
|
||
|
||
if (c == 80) //'P' key - start per call wav files //TODO: Fix
|
||
{
|
||
char wav_file_directory[1024];
|
||
sprintf (wav_file_directory, "%s", opts->wav_out_dir);
|
||
wav_file_directory[1023] = '\0';
|
||
if (stat(wav_file_directory, &st_wav) == -1)
|
||
{
|
||
fprintf (stderr, "%s wav file directory does not exist\n", wav_file_directory);
|
||
fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory);
|
||
mkdir(wav_file_directory, 0700);
|
||
}
|
||
fprintf (stderr,"\n Per Call Wav File Enabled to Directory: %s;.\n", opts->wav_out_dir);
|
||
srand(time(NULL)); //seed random for filenames (so two filenames aren't the exact same datetime string on initailization)
|
||
opts->wav_out_f = open_wav_file(opts->wav_out_dir, opts->wav_out_file, 8000, 0);
|
||
opts->wav_out_fR = open_wav_file(opts->wav_out_dir, opts->wav_out_fileR, 8000, 0);
|
||
opts->dmr_stereo_wav = 1;
|
||
}
|
||
|
||
if (c == 112) //'p' key - stop all per call wav files //TODO: Fix
|
||
{
|
||
//TODO: Add Closing of RAW files as well?
|
||
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, &state->event_history_s[0]);
|
||
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, &state->event_history_s[1]);
|
||
opts->wav_out_file[0] = 0; //Bugfix for decoded wav file display after disabling
|
||
opts->wav_out_fileR[0] = 0;
|
||
opts->dmr_stereo_wav = 0;
|
||
}
|
||
|
||
//
|
||
#ifdef __CYGWIN__ //this might be okay on Aero as well, will need to look into and/or test
|
||
//
|
||
#else
|
||
if (c == 115) //'s' key, stop playing wav or symbol in files
|
||
{
|
||
if (opts->symbolfile != NULL)
|
||
{
|
||
if (opts->audio_in_type == 4)
|
||
{
|
||
fclose(opts->symbolfile);
|
||
}
|
||
}
|
||
|
||
if (opts->audio_in_type == 2) //wav input file
|
||
{
|
||
sf_close(opts->audio_in_file);
|
||
}
|
||
|
||
if (opts->audio_out_type == 0)
|
||
{
|
||
opts->audio_in_type = 0;
|
||
openPulseInput(opts);
|
||
}
|
||
else opts->audio_in_type = 5; //exitflag = 1;
|
||
|
||
}
|
||
#endif
|
||
|
||
//makes buzzing sound when locked out in new audio config and short, probably something to do with processaudio running or not running
|
||
if (state->lasttg != 0 && opts->frame_provoice != 1 && c == 33) //SHIFT+'1' key (exclamation point), lockout slot 1 or conventional tg from tuning/playback during session
|
||
{
|
||
state->group_array[state->group_tally].groupNumber = state->lasttg;
|
||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
|
||
state->group_tally++;
|
||
|
||
//if we have an opened group file, let's write a group lock out into it to make it permanent
|
||
if (opts->group_in_file[0] != 0) //file is available
|
||
{
|
||
FILE * pFile; //file pointer
|
||
//open file by name that is supplied in the ncurses terminal, or cli
|
||
pFile = fopen (opts->group_in_file, "a");
|
||
fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttg, state->payload_algid);
|
||
fclose (pFile);
|
||
}
|
||
|
||
//extra safeguards due to sync issues with NXDN
|
||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||
|
||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||
|
||
//reset dmr blocks
|
||
dmr_reset_blocks (opts, state);
|
||
|
||
//zero out additional items
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->payload_algid = 0;
|
||
state->payload_algidR = 0;
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
state->payload_mi = 0;
|
||
state->payload_miR = 0;
|
||
state->payload_miP = 0;
|
||
state->payload_miN = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||
|
||
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||
//RIGCTL
|
||
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||
{
|
||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||
}
|
||
|
||
//rtl
|
||
#ifdef USE_RTLSDR
|
||
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq);
|
||
#endif
|
||
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 0)
|
||
{
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
|
||
}
|
||
|
||
if (state->lasttgR != 0 && opts->frame_provoice != 1 && c == 64) //SHIFT+'2' key (@ at sign), lockout slot 2 tdma tgR from tuning/playback during session
|
||
{
|
||
state->group_array[state->group_tally].groupNumber = state->lasttgR;
|
||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
|
||
state->group_tally++;
|
||
|
||
//if we have an opened group file, let's write a group lock out into it to make it permanent
|
||
if (opts->group_in_file[0] != 0) //file is available
|
||
{
|
||
FILE * pFile; //file pointer
|
||
//open file by name that is supplied in the ncurses terminal, or cli
|
||
pFile = fopen (opts->group_in_file, "a");
|
||
fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttgR, state->payload_algidR);
|
||
fclose (pFile);
|
||
}
|
||
|
||
//extra safeguards due to sync issues with NXDN
|
||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||
|
||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||
|
||
//reset dmr blocks
|
||
dmr_reset_blocks (opts, state);
|
||
|
||
//zero out additional items
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->payload_algid = 0;
|
||
state->payload_algidR = 0;
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
state->payload_mi = 0;
|
||
state->payload_miR = 0;
|
||
state->payload_miP = 0;
|
||
state->payload_miN = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||
|
||
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||
//RIGCTL
|
||
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||
{
|
||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||
}
|
||
|
||
//rtl
|
||
#ifdef USE_RTLSDR
|
||
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq);
|
||
#endif
|
||
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 0)
|
||
{
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
|
||
}
|
||
|
||
if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode
|
||
{
|
||
if (opts->trunk_use_allow_list == 1) opts->trunk_use_allow_list = 0;
|
||
else opts->trunk_use_allow_list = 1;
|
||
}
|
||
|
||
if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls
|
||
{
|
||
if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0;
|
||
else opts->trunk_tune_private_calls = 1;
|
||
}
|
||
|
||
if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls
|
||
{
|
||
if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0;
|
||
else opts->trunk_tune_data_calls = 1;
|
||
}
|
||
|
||
if (opts->p25_trunk == 1 && c == 101) //'e' key, toggle tune enc calls (P25 only on certain grants)
|
||
{
|
||
if (opts->trunk_tune_enc_calls == 1) opts->trunk_tune_enc_calls = 0;
|
||
else opts->trunk_tune_enc_calls = 1;
|
||
}
|
||
|
||
if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls
|
||
{
|
||
if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0;
|
||
else opts->trunk_tune_group_calls = 1;
|
||
}
|
||
|
||
if (c == 70) //'F' key - toggle agressive sync/crc failure/ras
|
||
{
|
||
if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1;
|
||
else opts->aggressive_framesync = 0;
|
||
}
|
||
|
||
if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc.
|
||
{
|
||
//dmr trunking/ncurses stuff
|
||
state->dmr_rest_channel = -1; //init on -1
|
||
state->dmr_mfid = -1; //
|
||
|
||
//dmr mfid branding and site parms
|
||
sprintf(state->dmr_branding_sub, "%s", "");
|
||
sprintf(state->dmr_branding, "%s", "");
|
||
sprintf (state->dmr_site_parms, "%s", "");
|
||
|
||
//DMR Location Area - DMRLA B***S***
|
||
opts->dmr_dmrla_is_set = 0;
|
||
opts->dmr_dmrla_n = 0;
|
||
|
||
//reset NXDN info
|
||
state->nxdn_location_site_code = 0;
|
||
state->nxdn_location_sys_code = 0;
|
||
sprintf (state->nxdn_location_category, "%s", " ");
|
||
|
||
state->nxdn_last_ran = -1; //0
|
||
state->nxdn_ran = 0; //0
|
||
|
||
state->nxdn_rcn = 0;
|
||
state->nxdn_base_freq = 0;
|
||
state->nxdn_step = 0;
|
||
state->nxdn_bw = 0;
|
||
|
||
}
|
||
|
||
//Debug/Troubleshooting Option
|
||
if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z)
|
||
{
|
||
// opts->p25_is_tuned = 0;
|
||
state->last_cc_sync_time = 0;
|
||
state->last_vc_sync_time = 0;
|
||
noCarrier(opts, state);
|
||
}
|
||
|
||
if (c == 93) //']' key - increment event history indexer
|
||
{
|
||
state->eh_index++;
|
||
}
|
||
|
||
if (c == 91) //'[' key - decrement event history indexer
|
||
{
|
||
state->eh_index--;
|
||
}
|
||
|
||
if (c == 92) //'\' key - toggle events for slot displayed, and reset eh_index
|
||
{
|
||
eh_slot ^= 1;
|
||
state->eh_index = 0;
|
||
}
|
||
|
||
|
||
|
||
|
||
//attempt retry to TCP Audio server
|
||
if (c == 56) // '8' key, try audio in type 8 (TCP Audio Server connection) using defaults OR whatever the user last specified
|
||
{
|
||
|
||
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
|
||
if (opts->tcp_sockfd != 0)
|
||
{
|
||
//reset audio input stream
|
||
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
|
||
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
|
||
opts->audio_in_file_info->channels=1;
|
||
opts->audio_in_file_info->seekable=0;
|
||
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||
|
||
if(opts->tcp_file_in == NULL)
|
||
{
|
||
fprintf(stderr, "Error, couldn't Connect to TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||
}
|
||
else
|
||
{
|
||
//close pulse input if it is currently open
|
||
if (opts->audio_in_type == 0) closePulseInput(opts);
|
||
fprintf (stderr, "TCP Socket Connected Successfully.\n");
|
||
opts->audio_in_type = 8;
|
||
}
|
||
}
|
||
else fprintf (stderr, "TCP Socket Connection Error.\n");
|
||
}
|
||
|
||
if (c == 57) //'9' key, try rigctl connection with default values
|
||
{
|
||
//use same or last specified host for TCP audio sink for connection
|
||
memcpy (opts->rigctlhostname, opts->tcp_hostname, sizeof (opts->rigctlhostname) );
|
||
opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno);
|
||
if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1;
|
||
else opts->use_rigctl = 0;
|
||
}
|
||
|
||
//if trunking and user wants to just go back to the control channel and skip this call
|
||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && c == 67) //Capital C key - Return to CC
|
||
{
|
||
|
||
//extra safeguards due to sync issues with NXDN
|
||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||
|
||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||
|
||
//reset dmr blocks
|
||
dmr_reset_blocks (opts, state);
|
||
|
||
//zero out additional items
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->payload_algid = 0;
|
||
state->payload_algidR = 0;
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
state->payload_mi = 0;
|
||
state->payload_miR = 0;
|
||
state->payload_miP = 0;
|
||
state->payload_miN = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||
|
||
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||
//RIGCTL
|
||
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||
{
|
||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||
}
|
||
|
||
//rtl
|
||
#ifdef USE_RTLSDR
|
||
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq);
|
||
#endif
|
||
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 0)
|
||
{
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
|
||
//if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 1)
|
||
{
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
}
|
||
|
||
fprintf (stderr, "\n User Activated Return to CC; \n ");
|
||
|
||
}
|
||
|
||
//if trunking or scanning, manually cycle forward through channels loaded (can be run without trunking or scanning enabled)
|
||
if ( (opts->use_rigctl == 1 || opts->audio_in_type == 3) && c == 76) //Capital L key - Cycle Channels Forward
|
||
{
|
||
|
||
//extra safeguards due to sync issues with NXDN
|
||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||
|
||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||
|
||
//reset dmr blocks
|
||
dmr_reset_blocks (opts, state);
|
||
|
||
//zero out additional items
|
||
state->lasttg = 0;
|
||
state->lasttgR = 0;
|
||
state->lastsrc = 0;
|
||
state->lastsrcR = 0;
|
||
state->payload_algid = 0;
|
||
state->payload_algidR = 0;
|
||
state->payload_keyid = 0;
|
||
state->payload_keyidR = 0;
|
||
state->payload_mi = 0;
|
||
state->payload_miR = 0;
|
||
state->payload_miP = 0;
|
||
state->payload_miN = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||
|
||
//just copy and pasted the cycle logic for CC/signal hunting on no sync
|
||
if (state->lcn_freq_roll >= state->lcn_freq_count) //fixed this to skip the extra wait out at the end of the list
|
||
{
|
||
state->lcn_freq_roll = 0; //reset to zero
|
||
}
|
||
|
||
//roll an extra value up if the current is the same as what's already loaded -- faster hunting on Cap+, etc
|
||
if (state->lcn_freq_roll != 0)
|
||
{
|
||
if (state->trunk_lcn_freq[state->lcn_freq_roll-1] == state->trunk_lcn_freq[state->lcn_freq_roll])
|
||
{
|
||
state->lcn_freq_roll++;
|
||
//check roll again if greater than expected, then go back to zero
|
||
if (state->lcn_freq_roll >= state->lcn_freq_count)
|
||
{
|
||
state->lcn_freq_roll = 0; //reset to zero
|
||
}
|
||
}
|
||
}
|
||
|
||
//check that we have a non zero value first, then tune next frequency
|
||
if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
|
||
{
|
||
//rigctl
|
||
if (opts->use_rigctl == 1)
|
||
{
|
||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||
}
|
||
//rtl
|
||
if (opts->audio_in_type == 3)
|
||
{
|
||
#ifdef USE_RTLSDR
|
||
rtl_dev_tune (opts, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||
#endif
|
||
}
|
||
|
||
fprintf (stderr, "\n User Activated Channel Cycle;");
|
||
fprintf (stderr, " Tuning to Frequency: %.06lf MHz\n",
|
||
(double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000);
|
||
|
||
}
|
||
state->lcn_freq_roll++;
|
||
state->last_cc_sync_time = time(NULL);
|
||
|
||
|
||
//may need to test to see if we want to do the conditional below or not for symbol rate flipping
|
||
|
||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 0)
|
||
{
|
||
state->samplesPerSymbol = 10;
|
||
state->symbolCenter = 4;
|
||
}
|
||
|
||
//if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate
|
||
if (state->p25_cc_is_tdma == 1)
|
||
{
|
||
state->samplesPerSymbol = 8;
|
||
state->symbolCenter = 3;
|
||
}
|
||
|
||
}
|
||
|
||
if (c == 118 && opts->audio_in_type == 3) //'v' key, cycle rtl volume multiplier, when active
|
||
{
|
||
if (opts->rtl_volume_multiplier == 1 || opts->rtl_volume_multiplier == 2) opts->rtl_volume_multiplier++;
|
||
else opts->rtl_volume_multiplier = 1;
|
||
}
|
||
|
||
if (c == 86) // 'V' Key, toggle LPF
|
||
{
|
||
if (opts->use_lpf == 0) opts->use_lpf = 1;
|
||
else opts->use_lpf = 0;
|
||
}
|
||
|
||
if (c == 66) // 'B' Key, toggle HPF
|
||
{
|
||
if (opts->use_hpf == 0) opts->use_hpf = 1;
|
||
else opts->use_hpf = 0;
|
||
}
|
||
|
||
if (c == 78) // 'N' Key, toggle PBF
|
||
{
|
||
if (opts->use_pbf == 0) opts->use_pbf = 1;
|
||
else opts->use_pbf = 0;
|
||
}
|
||
|
||
if (c == 72) // 'H' Key, toggle HPF on digital
|
||
{
|
||
if (opts->use_hpf_d == 0) opts->use_hpf_d = 1;
|
||
else opts->use_hpf_d = 0;
|
||
}
|
||
|
||
if (opts->m17encoder == 1 && c == 92) //'\' key - toggle M17 encoder Encode + TX
|
||
{
|
||
if (state->m17encoder_tx == 0) state->m17encoder_tx = 1;
|
||
else state->m17encoder_tx = 0;
|
||
|
||
//flag on the EOT marker to send last frame after toggling encoder to zero
|
||
if (state->m17encoder_tx == 0) state->m17encoder_eot = 1;
|
||
|
||
}
|
||
|
||
if(opts->frame_provoice == 1 && c == 65) //'A' Key, toggle ESK mask 0xA0
|
||
{
|
||
if (state->esk_mask == 0) state->esk_mask = 0xA0;
|
||
else state->esk_mask = 0;
|
||
}
|
||
|
||
if(opts->frame_provoice == 1 && c == 83) //'S' Key, toggle STD or EA mode and reset
|
||
{
|
||
if (state->ea_mode == -1) state->ea_mode = 0;
|
||
else if (state->ea_mode == 0) state->ea_mode = 1;
|
||
else state->ea_mode = 0;
|
||
|
||
//reset -- test to make sure these don't do weird things when reset
|
||
state->edacs_site_id = 0;
|
||
state->edacs_lcn_count = 0;
|
||
state->edacs_cc_lcn = 0;
|
||
state->edacs_vc_lcn = 0;
|
||
state->edacs_tuned_lcn = -1;
|
||
state->edacs_vc_call_type = 0;
|
||
state->p25_cc_freq = 0;
|
||
opts->p25_is_tuned = 0;
|
||
state->lasttg = 0;
|
||
state->lastsrc = 0;
|
||
|
||
}
|
||
|
||
//anything with an entry box will need the inputs and outputs stopped first
|
||
//so probably just write a function to handle c input, and when c = certain values
|
||
//needing an entry box, then stop all of those
|
||
|
||
//allocated memory pointer needs to be free'd
|
||
if (timestr != NULL)
|
||
{
|
||
free (timestr);
|
||
timestr = NULL;
|
||
}
|
||
if (datestr != NULL)
|
||
{
|
||
free (datestr);
|
||
datestr = NULL;
|
||
}
|
||
|
||
} //end ncursesPrinter
|
||
|
||
void ncursesClose ()
|
||
{
|
||
endwin();
|
||
|
||
}
|
||
|
||
//init each event history struct passed into here
|
||
void init_event_history (Event_History_I * event_struct, uint8_t start, uint8_t stop)
|
||
{
|
||
for (uint8_t i = start; i < stop; i++)
|
||
{
|
||
event_struct->Event_History_Items[i].write = 0;
|
||
event_struct->Event_History_Items[i].systype = -1;
|
||
event_struct->Event_History_Items[i].subtype = -1;
|
||
event_struct->Event_History_Items[i].sys_id1 = 0;
|
||
event_struct->Event_History_Items[i].sys_id2 = 0;
|
||
event_struct->Event_History_Items[i].sys_id3 = 0;
|
||
event_struct->Event_History_Items[i].sys_id4 = 0;
|
||
event_struct->Event_History_Items[i].sys_id5 = 0;
|
||
event_struct->Event_History_Items[i].gi = 0;
|
||
event_struct->Event_History_Items[i].enc = 0;
|
||
event_struct->Event_History_Items[i].enc_alg = 0;
|
||
event_struct->Event_History_Items[i].enc_key = 0;
|
||
event_struct->Event_History_Items[i].mi = 0;
|
||
event_struct->Event_History_Items[i].svc = 0;
|
||
event_struct->Event_History_Items[i].source_id = 0;
|
||
event_struct->Event_History_Items[i].target_id = 0;
|
||
sprintf (event_struct->Event_History_Items[i].src_str, "%s", "BUMBLEBEETUNA");
|
||
sprintf (event_struct->Event_History_Items[i].tgt_str, "%s", "BUMBLEBEETUNA");
|
||
sprintf (event_struct->Event_History_Items[i].t_name, "%s", "BUMBLEBEETUNA");
|
||
sprintf (event_struct->Event_History_Items[i].s_name, "%s", "BUMBLEBEETUNA");
|
||
sprintf (event_struct->Event_History_Items[i].t_mode, "%s", "BUMBLEBEETUNA");
|
||
sprintf (event_struct->Event_History_Items[i].s_mode, "%s", "BUMBLEBEETUNA");
|
||
event_struct->Event_History_Items[i].channel = 0;
|
||
event_struct->Event_History_Items[i].event_time = 0;
|
||
|
||
memset (event_struct->Event_History_Items[i].pdu, 0, sizeof(event_struct->Event_History_Items[0].pdu));
|
||
sprintf (event_struct->Event_History_Items[i].sysid_string, "%s", "");
|
||
sprintf (event_struct->Event_History_Items[i].alias, "%s", "BUMBLEBEETUNA");
|
||
sprintf (event_struct->Event_History_Items[i].gps_s, "%s", "BUMBLEBEETUNA");
|
||
sprintf (event_struct->Event_History_Items[i].text_message, "%s", "BUMBLEBEETUNA");
|
||
sprintf (event_struct->Event_History_Items[i].event_string, "%s", "BUMBLEBEETUNA");
|
||
}
|
||
}
|
||
|
||
void push_event_history (Event_History_I * event_struct)
|
||
{
|
||
|
||
//Fixed, had it going in the wrong direction first time
|
||
for (uint8_t i = 254; i >= 1; i--)
|
||
{
|
||
event_struct->Event_History_Items[i].write = event_struct->Event_History_Items[i-1].write;
|
||
event_struct->Event_History_Items[i].systype = event_struct->Event_History_Items[i-1].systype;
|
||
event_struct->Event_History_Items[i].subtype = event_struct->Event_History_Items[i-1].subtype;
|
||
event_struct->Event_History_Items[i].sys_id1 = event_struct->Event_History_Items[i-1].sys_id1;
|
||
event_struct->Event_History_Items[i].sys_id2 = event_struct->Event_History_Items[i-1].sys_id2;
|
||
event_struct->Event_History_Items[i].sys_id3 = event_struct->Event_History_Items[i-1].sys_id3;
|
||
event_struct->Event_History_Items[i].sys_id4 = event_struct->Event_History_Items[i-1].sys_id4;
|
||
event_struct->Event_History_Items[i].sys_id5 = event_struct->Event_History_Items[i-1].sys_id5;
|
||
event_struct->Event_History_Items[i].gi = event_struct->Event_History_Items[i-1].gi;
|
||
event_struct->Event_History_Items[i].enc = event_struct->Event_History_Items[i-1].enc;
|
||
event_struct->Event_History_Items[i].enc_alg = event_struct->Event_History_Items[i-1].enc_alg;
|
||
event_struct->Event_History_Items[i].enc_key = event_struct->Event_History_Items[i-1].enc_key;
|
||
event_struct->Event_History_Items[i].mi = event_struct->Event_History_Items[i-1].mi;
|
||
event_struct->Event_History_Items[i].svc = event_struct->Event_History_Items[i-1].svc;
|
||
event_struct->Event_History_Items[i].source_id = event_struct->Event_History_Items[i-1].source_id;
|
||
event_struct->Event_History_Items[i].target_id = event_struct->Event_History_Items[i-1].target_id;
|
||
sprintf (event_struct->Event_History_Items[i].src_str, "%s", event_struct->Event_History_Items[i-1].src_str);
|
||
sprintf (event_struct->Event_History_Items[i].tgt_str, "%s", event_struct->Event_History_Items[i-1].tgt_str);
|
||
sprintf (event_struct->Event_History_Items[i].t_name, "%s", event_struct->Event_History_Items[i-1].t_name);
|
||
sprintf (event_struct->Event_History_Items[i].s_name, "%s", event_struct->Event_History_Items[i-1].s_name);
|
||
sprintf (event_struct->Event_History_Items[i].t_mode, "%s", event_struct->Event_History_Items[i-1].t_mode);
|
||
sprintf (event_struct->Event_History_Items[i].s_mode, "%s", event_struct->Event_History_Items[i-1].s_mode);
|
||
event_struct->Event_History_Items[i].channel = event_struct->Event_History_Items[i-1].channel;
|
||
event_struct->Event_History_Items[i].event_time = event_struct->Event_History_Items[i+1].event_time;
|
||
|
||
memcpy (event_struct->Event_History_Items[i].pdu, event_struct->Event_History_Items[i-1].pdu, sizeof(event_struct->Event_History_Items[0].pdu));
|
||
sprintf (event_struct->Event_History_Items[i].sysid_string, "%s", event_struct->Event_History_Items[i-1].sysid_string);
|
||
sprintf (event_struct->Event_History_Items[i].alias, "%s", event_struct->Event_History_Items[i-1].alias);
|
||
sprintf (event_struct->Event_History_Items[i].gps_s, "%s", event_struct->Event_History_Items[i-1].gps_s);
|
||
sprintf (event_struct->Event_History_Items[i].text_message, "%s", event_struct->Event_History_Items[i-1].text_message);
|
||
sprintf (event_struct->Event_History_Items[i].event_string, "%s", event_struct->Event_History_Items[i-1].event_string);
|
||
}
|
||
}
|
||
|
||
void write_event_to_log_file (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t swrite, char * event_string) //pass completed event string here that is in the struct
|
||
{
|
||
|
||
//open log file
|
||
FILE * event_log_file;
|
||
event_log_file = fopen(opts->event_out_file, "a");
|
||
|
||
fprintf (event_log_file, "%s ", event_string);
|
||
if (swrite == 1)
|
||
fprintf (event_log_file, "Slot %d; ", slot+1);
|
||
fprintf (event_log_file,"\n");
|
||
|
||
char text_string[2000]; sprintf (text_string, "%s", "BUMBLEBEETUNA");
|
||
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].text_message, 13) != 0)
|
||
fprintf (event_log_file, "%s \n", state->event_history_s[slot].Event_History_Items[0].text_message);
|
||
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].alias, 13) != 0)
|
||
fprintf (event_log_file, " Talker Alias: %s \n", state->event_history_s[slot].Event_History_Items[0].alias);
|
||
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].gps_s, 13) != 0)
|
||
fprintf (event_log_file, " GPS: %s \n", state->event_history_s[slot].Event_History_Items[0].gps_s);
|
||
|
||
//flush and close log file
|
||
fflush (event_log_file);
|
||
fclose (event_log_file);
|
||
}
|
||
|
||
// run once per loop to check for and push and update event history
|
||
void watchdog_event_history (dsd_opts * opts, dsd_state * state, uint8_t slot)
|
||
{
|
||
|
||
//create a pointer to the current slot event history
|
||
Event_History_I * event_struct = &state->event_history_s[slot];
|
||
|
||
//is this a TDMA slot (append Slot value to end of written event history)
|
||
uint8_t swrite = 0;
|
||
|
||
//who is currently talking
|
||
uint32_t source_id = 0;
|
||
|
||
//last values pulled from the event history
|
||
uint32_t last_source_id = event_struct->Event_History_Items[0].source_id;
|
||
|
||
if (slot == 0)
|
||
source_id = state->lastsrc;
|
||
else
|
||
source_id = state->lastsrcR;
|
||
|
||
//if DMR BS or P25P2, then flag the swrite, so write can append slot value to event history log //|| state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34 MS
|
||
if (state->lastsynctype == 10 || state->lastsynctype == 11 || state->lastsynctype == 12 || state->lastsynctype == 13)
|
||
swrite = 1;
|
||
|
||
else if (state->lastsynctype == 35 || state->lastsynctype == 36)
|
||
swrite = 1;
|
||
|
||
if (slot == 0) //BUGFIX: generic catch on FDMA systems so that we don't write duplicate data to slot 2 event history
|
||
{
|
||
//NXDN RID (TODO: Changeover to lastsrc later on)
|
||
if (state->lastsynctype == 28 || state->lastsynctype == 29)
|
||
source_id = state->nxdn_last_rid;
|
||
|
||
if (state->lastsynctype == 30 || state->lastsynctype == 30) //YSF Fusion
|
||
{
|
||
source_id = 0;
|
||
for (uint8_t i = 0; i < 11; i++)
|
||
source_id += state->ysf_src[i]; //convert to sum value to make a distinct enough src value
|
||
}
|
||
|
||
if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) //M17 STR
|
||
{
|
||
source_id = (uint32_t)state->m17_src;
|
||
}
|
||
|
||
if (state->lastsynctype == 6 || state->lastsynctype == 7 || state->lastsynctype == 18 || state->lastsynctype == 19) //DSTAR
|
||
{
|
||
source_id = 0;
|
||
for (uint8_t i = 0; i < 12; i++)
|
||
source_id += state->dstar_src[i]; //convert to sum value to make a distinct enough src value
|
||
|
||
//need a strncmp here for 8 spaces in this field first so we don't blip a blank into the event history
|
||
if (strncmp(state->dstar_src, " ", 8) == 0)
|
||
source_id = 0;
|
||
}
|
||
|
||
if (state->lastsynctype == 20 || state->lastsynctype == 24 || state->lastsynctype == 21 || state->lastsynctype == 25 || state->lastsynctype == 22 || state->lastsynctype == 26 || state->lastsynctype == 23 || state->lastsynctype == 27) //dPMR
|
||
{
|
||
source_id = 0;
|
||
for (uint8_t i = 0; i < 20; i++)
|
||
source_id += state->dpmr_caller_id[i]; //convert to sum value to make a distinct enough src value
|
||
|
||
//need a strncmp here for 8 spaces in this field first so we don't blip a blank into the event history
|
||
if (strncmp(state->dpmr_caller_id, " ", 6) == 0)
|
||
source_id = 0;
|
||
}
|
||
|
||
if (state->lastsynctype == 14 || state->lastsynctype == 15 || state->lastsynctype == 37 || state->lastsynctype == 38) //EDACS Calls
|
||
{
|
||
source_id = 0;
|
||
if (opts->p25_is_tuned == 1)
|
||
source_id = state->lastsrc;
|
||
}
|
||
|
||
}
|
||
|
||
//call alert beep when new call detected
|
||
if (last_source_id == 0 && source_id != 0 && opts->call_alert == 1)
|
||
beeper (opts, state, slot, 40, 86, 3);
|
||
|
||
if (source_id != last_source_id && last_source_id != 0)
|
||
{
|
||
|
||
if (opts->event_out_file[0] != 0)
|
||
write_event_to_log_file(opts, state, slot, swrite, event_struct->Event_History_Items[0].event_string);
|
||
|
||
event_struct->Event_History_Items[0].write = 1; //written, or pushed at this point
|
||
|
||
if (slot == 0 && opts->wav_out_f != NULL)
|
||
{
|
||
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, event_struct);
|
||
opts->wav_out_f = open_wav_file(opts->wav_out_dir, opts->wav_out_file, 8000, 0);
|
||
}
|
||
|
||
else if (slot == 1 && opts->wav_out_fR != NULL)
|
||
{
|
||
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, event_struct);
|
||
opts->wav_out_fR = open_wav_file(opts->wav_out_dir, opts->wav_out_fileR, 8000, 0);
|
||
}
|
||
|
||
push_event_history (event_struct);
|
||
init_event_history (event_struct, 0, 1);
|
||
|
||
//clear out some strings and things
|
||
memset(state->ysf_txt, 0, sizeof(state->ysf_txt));
|
||
memset(state->dstar_gps, 0, sizeof(state->dstar_gps));
|
||
memset(state->dstar_txt, 0, sizeof(state->dstar_txt));
|
||
state->gi[slot] = -1; //return to an unset value
|
||
|
||
//end of voice call alert
|
||
if (opts->call_alert == 1)
|
||
beeper (opts, state, slot, 40, 86, 3);
|
||
}
|
||
|
||
}
|
||
|
||
//similar to above, but constantly testing and checking the most recent event only
|
||
//this will hopefully be more useful when dealing with an ongoing event with
|
||
//features that update over time with embedded signalling, etc
|
||
void watchdog_event_current (dsd_opts * opts, dsd_state * state, uint8_t slot)
|
||
{
|
||
|
||
//create a pointer to the current slot event history
|
||
Event_History_I * event_struct = &state->event_history_s[slot];
|
||
|
||
//TODO: Flesh out more later on.
|
||
uint32_t source_id = 0;
|
||
uint32_t target_id = 0;
|
||
char src_str[200]; memset (src_str, 0, sizeof(src_str));
|
||
sprintf (src_str, "%s", "BUMBLEBEETUNA");
|
||
char tgt_str[200]; memset (tgt_str, 0, sizeof(tgt_str));
|
||
sprintf (tgt_str, "%s", "BUMBLEBEETUNA");
|
||
|
||
//group import items
|
||
char t_name[200]; memset (t_name, 0, sizeof(t_name));
|
||
sprintf (t_name, "%s", "BUMBLEBEETUNA");
|
||
char s_name[200]; memset (s_name, 0, sizeof(s_name));
|
||
sprintf (s_name, "%s", "BUMBLEBEETUNA");
|
||
char t_mode[200]; memset (t_mode, 0, sizeof(t_mode));
|
||
sprintf (t_mode, "%s", "BUMBLEBEETUNA");
|
||
char s_mode[200]; memset (s_mode, 0, sizeof(s_mode));
|
||
sprintf (s_mode, "%s", "BUMBLEBEETUNA");
|
||
|
||
uint16_t svc_opts = 0;
|
||
uint8_t subtype = 0;
|
||
uint8_t mfid = 0;
|
||
uint32_t sys_id1 = 0;
|
||
uint32_t sys_id2 = 0;
|
||
uint32_t sys_id3 = 0;
|
||
uint32_t sys_id4 = 0;
|
||
uint32_t sys_id5 = 0;
|
||
|
||
uint32_t channel = 0;
|
||
|
||
uint8_t enc = 0;
|
||
uint8_t alg_id = 0;
|
||
uint16_t key_id = 0;
|
||
unsigned long long int mi;
|
||
|
||
char sysid_string[200]; memset(sysid_string, 0, sizeof(sysid_string));
|
||
sprintf (sysid_string, "%s", "");
|
||
|
||
if (slot == 0)
|
||
{
|
||
source_id = state->lastsrc;
|
||
target_id = state->lasttg;
|
||
|
||
subtype = state->dmrburstL;
|
||
mfid = state->dmr_fid;
|
||
|
||
svc_opts = state->dmr_so;
|
||
enc = (svc_opts >> 6) & 1;
|
||
alg_id = state->payload_algid;
|
||
key_id = (uint16_t)state->payload_keyid;
|
||
|
||
mi = state->payload_mi;
|
||
}
|
||
else
|
||
{
|
||
source_id = state->lastsrcR;
|
||
target_id = state->lasttgR;
|
||
|
||
subtype = state->dmrburstR;
|
||
mfid = state->dmr_fidR;
|
||
|
||
svc_opts = state->dmr_soR;
|
||
enc = (svc_opts >> 6) & 1;
|
||
|
||
alg_id = state->payload_algidR;
|
||
key_id = (uint16_t)state->payload_keyidR;
|
||
mi = state->payload_miR;
|
||
}
|
||
|
||
//if P25 (if not P25, then these will all be zero anyways)
|
||
sys_id1 = state->p2_wacn;
|
||
sys_id2 = state->p2_sysid;
|
||
if (state->nac != 0)
|
||
sys_id3 = state->nac; //same as state->p2_cc, but zeroes out when no signal or error
|
||
else sys_id3 = state->p2_cc;
|
||
sys_id4 = state->p2_rfssid;
|
||
sys_id5 = state->p2_siteid;
|
||
|
||
if (sys_id1)
|
||
sprintf (sysid_string, "P25_%05X%03X%03X_%d_%d", sys_id1, sys_id2, sys_id3, sys_id4, sys_id5);
|
||
else sprintf (sysid_string, "P25_%03X", sys_id3);
|
||
|
||
if (state->lastsynctype == 10 || state->lastsynctype == 11 || state->lastsynctype == 12 || state->lastsynctype == 13 ||
|
||
state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34 )
|
||
{
|
||
sys_id1 = state->dmr_t3_syscode;
|
||
sys_id2 = state->dmr_color_code;
|
||
|
||
if (sys_id1)
|
||
sprintf (sysid_string, "DMR_%X_CC_%d", sys_id1, sys_id2);
|
||
else sprintf (sysid_string, "DMR_CC_%d", sys_id2);
|
||
}
|
||
|
||
if (slot == 0) //BUGFIX: generic catch on FDMA systems so that we don't write duplicate data to slot 2 event history
|
||
{
|
||
//NXDN RID (TODO: Changeover to lastsrc and lasttg later on)
|
||
if (state->lastsynctype == 28 || state->lastsynctype == 29)
|
||
{
|
||
source_id = state->nxdn_last_rid;
|
||
target_id = state->nxdn_last_tg;
|
||
if (state->nxdn_cipher_type != 0)
|
||
enc = 1;
|
||
alg_id = state->nxdn_cipher_type;
|
||
key_id = state->nxdn_key;
|
||
|
||
sys_id1 = state->nxdn_location_site_code;
|
||
sys_id2 = state->nxdn_location_sys_code;
|
||
sys_id3 = state->nxdn_last_ran; //might be an issue on conventional systems that have a different RAN on the tx_rel or idle data bursts
|
||
|
||
if (sys_id1)
|
||
sprintf (sysid_string, "NXDN_%d_%d_RAN_%d", sys_id2, sys_id1, sys_id3);
|
||
else sprintf (sysid_string, "NXDN_RAN_%d", sys_id3);
|
||
}
|
||
|
||
if (state->lastsynctype == 30 || state->lastsynctype == 30) //YSF Fusion
|
||
{
|
||
source_id = 0;
|
||
for (uint8_t i = 0; i < 11; i++)
|
||
source_id += state->ysf_src[i]; //convert to sum value to make a distinct enough src value
|
||
|
||
//WIP: If Text, compile it here (still having issues with an empty txt string making a line break)
|
||
uint8_t k = 0; char ysf_emp[21][21]; memset(ysf_emp, 0, sizeof(ysf_emp));
|
||
if (memcmp(ysf_emp, state->ysf_txt, sizeof(state->ysf_txt)) != 0)
|
||
{
|
||
for (uint8_t i = 4; i < 8; i++)
|
||
{
|
||
for (uint8_t j = 0; j < 20; j++)
|
||
{
|
||
if (state->ysf_txt[i][j] != 0x2A)
|
||
event_struct->Event_History_Items[0].text_message[k++] = state->ysf_txt[i][j];
|
||
else event_struct->Event_History_Items[0].text_message[k++] = 0x20; //space
|
||
|
||
}
|
||
event_struct->Event_History_Items[0].text_message[k] = 0; //terminate
|
||
}
|
||
}
|
||
else sprintf (event_struct->Event_History_Items[0].text_message, "%s", "BUMBLEBEETUNA");
|
||
|
||
sprintf (sysid_string, "%s", "YSF");
|
||
|
||
char temp_str[20];
|
||
memset(temp_str, 0, sizeof(temp_str));
|
||
|
||
//set src string as a non-spaced non-garbo char string
|
||
for (uint8_t i = 0; i < 10; i++)
|
||
{
|
||
if (state->ysf_src[i] == 0x20) //spaces to underscore
|
||
temp_str[i] = 0x5F;
|
||
else if (state->ysf_src[i] > 0x20 && state->ysf_src[i] < 0x7F) //copy normal ascii range characters
|
||
temp_str[i] = state->ysf_src[i];
|
||
else if (state->ysf_src[i] == 0) break; //hit the terminator, so stop
|
||
else temp_str[i] = 0x5F; //unknown to underscore
|
||
}
|
||
sprintf (src_str, "%s", temp_str);
|
||
|
||
//same for tgt str
|
||
memset(temp_str, 0, sizeof(temp_str));
|
||
for (uint8_t i = 0; i < 10; i++)
|
||
{
|
||
if (state->ysf_tgt[i] == 0x20) //spaces to underscore
|
||
temp_str[i] = 0x5F;
|
||
else if (state->ysf_tgt[i] > 0x20 && state->ysf_tgt[i] < 0x7F) //copy normal ascii range characters
|
||
temp_str[i] = state->ysf_tgt[i];
|
||
else if (state->ysf_tgt[i] == 0) break; //hit the terminator, so stop
|
||
else temp_str[i] = 0x5F; //unknown to underscore
|
||
}
|
||
sprintf (tgt_str, "%s", temp_str);
|
||
|
||
}
|
||
|
||
if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) //M17 STR
|
||
{
|
||
target_id = (uint32_t)state->m17_dst;
|
||
source_id = (uint32_t)state->m17_src;
|
||
sys_id1 = state->m17_can;
|
||
sprintf (sysid_string, "M17_CAN_%d", sys_id1);
|
||
sprintf (src_str, "%s", state->m17_src_csd);
|
||
sprintf (tgt_str, "%s", state->m17_dst_csd);
|
||
}
|
||
|
||
if (state->lastsynctype == 6 || state->lastsynctype == 7 || state->lastsynctype == 18 || state->lastsynctype == 19) //DSTAR
|
||
{
|
||
source_id = 0;
|
||
for (uint8_t i = 0; i < 12; i++)
|
||
source_id += state->dstar_src[i]; //convert to sum value to make a distinct enough src value
|
||
|
||
//need a strncmp here for 8 spaces in this field first so we don't blip a blank into the event history
|
||
if (strncmp(state->dstar_src, " ", 8) == 0)
|
||
source_id = 0;
|
||
|
||
sprintf (sysid_string, "%s", "DSTAR");
|
||
|
||
char temp_str[20];
|
||
memset(temp_str, 0, sizeof(temp_str));
|
||
|
||
//set src string as a non-spaced non-garbo char string
|
||
for (uint8_t i = 0; i < 12; i++)
|
||
{
|
||
if (state->dstar_src[i] == 0x20) //spaces to underscore
|
||
temp_str[i] = 0x5F;
|
||
else if (state->dstar_src[i] > 0x20 && state->dstar_src[i] < 0x7F) //copy normal ascii range characters
|
||
temp_str[i] = state->dstar_src[i];
|
||
else if (state->dstar_src[i] == 0) break; //hit the terminator, so stop
|
||
else temp_str[i] = 0x5F; //unknown to underscore
|
||
}
|
||
sprintf (src_str, "%s", temp_str);
|
||
|
||
//same for tgt str
|
||
memset(temp_str, 0, sizeof(temp_str));
|
||
for (uint8_t i = 0; i < 8; i++)
|
||
{
|
||
if (state->dstar_dst[i] == 0x20) //spaces to underscore
|
||
temp_str[i] = 0x5F;
|
||
else if (state->dstar_dst[i] > 0x20 && state->dstar_dst[i] < 0x7F) //copy normal ascii range characters
|
||
temp_str[i] = state->dstar_dst[i];
|
||
else if (state->dstar_dst[i] == 0) break; //hit the terminator, so stop
|
||
else temp_str[i] = 0x5F; //unknown to underscore
|
||
}
|
||
sprintf (tgt_str, "%s", temp_str);
|
||
}
|
||
|
||
if (state->lastsynctype == 20 || state->lastsynctype == 24 || state->lastsynctype == 21 || state->lastsynctype == 25 || state->lastsynctype == 22 || state->lastsynctype == 26 || state->lastsynctype == 23 || state->lastsynctype == 27) //dPMR
|
||
{
|
||
source_id = 0;
|
||
for (uint8_t i = 0; i < 20; i++)
|
||
source_id += state->dpmr_caller_id[i]; //convert to sum value to make a distinct enough src value
|
||
|
||
//need a strncmp here for 8 spaces in this field first so we don't blip a blank into the event history
|
||
if (strncmp(state->dpmr_caller_id, " ", 6) == 0)
|
||
source_id = 0;
|
||
|
||
sprintf (sysid_string, "DPMR_CC_%d", state->dpmr_color_code);
|
||
|
||
sprintf (src_str, "%s", state->dpmr_caller_id);
|
||
sprintf (tgt_str, "%s", state->dpmr_target_id);
|
||
}
|
||
|
||
if (state->lastsynctype == 14 || state->lastsynctype == 15 || state->lastsynctype == 37 || state->lastsynctype == 38) //EDACS Calls
|
||
{
|
||
source_id = 0;
|
||
if (opts->p25_is_tuned == 1)
|
||
{
|
||
source_id = state->lastsrc;
|
||
channel = state->edacs_tuned_lcn;
|
||
}
|
||
|
||
sys_id1 = state->edacs_site_id;
|
||
sys_id2 = state->edacs_area_code;
|
||
sys_id3 = state->edacs_sys_id;
|
||
svc_opts = state->edacs_vc_call_type;
|
||
char sup_str[200]; memset (sup_str, 0, sizeof(sup_str));
|
||
sprintf (sup_str, "%s", "_");
|
||
if (svc_opts & 0x02)
|
||
strcat (sup_str, "Digital_");
|
||
else strcat (sup_str, "Analog_");
|
||
if (svc_opts & 0x04)
|
||
strcat (sup_str, "Emergency_");
|
||
if (svc_opts & 0x08)
|
||
strcat (sup_str, "Group_");
|
||
if (svc_opts & 0x10)
|
||
strcat (sup_str, "I_");
|
||
if (svc_opts & 0x20)
|
||
strcat (sup_str, "ALL_");
|
||
if (svc_opts & 0x40)
|
||
strcat (sup_str, "INTER_");
|
||
if (svc_opts & 0x80)
|
||
strcat (sup_str, "TEST_");
|
||
if (svc_opts & 0x100)
|
||
strcat (sup_str, "AGENCY_");
|
||
if (svc_opts & 0x200)
|
||
strcat (sup_str, "FLEET_");
|
||
if (svc_opts & 0x01)
|
||
strcat (sup_str, "Voice_");
|
||
strcat (sup_str, "Call");
|
||
|
||
sprintf (sysid_string, "EDACS_SITE_%03d", sys_id1);
|
||
strcat (sysid_string, sup_str);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//if we have a group_array import, search and load it here
|
||
//will search and load both target values, and src values if available
|
||
uint8_t t_name_loaded = 0;
|
||
uint8_t s_name_loaded = 0;
|
||
if (target_id != 0)
|
||
{
|
||
for (int i = 0; i < state->group_tally; i++)
|
||
{
|
||
if (state->group_array[i].groupNumber == target_id)
|
||
{
|
||
sprintf (t_name, "%s", state->group_array[i].groupName);
|
||
sprintf (t_mode, "%s", state->group_array[i].groupMode);
|
||
t_name_loaded = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (source_id != 0) //&& state->gi[slot] == 1
|
||
{
|
||
for (int i = 0; i < state->group_tally; i++)
|
||
{
|
||
if (state->group_array[i].groupNumber == source_id)
|
||
{
|
||
sprintf (s_name, "%s", state->group_array[i].groupName);
|
||
sprintf (s_mode, "%s", state->group_array[i].groupMode);
|
||
s_name_loaded = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//system type string (P25, DMR, etc)
|
||
char * sys_string = "Digital";
|
||
if (state->lastsynctype != -1)
|
||
sys_string = SyncTypes[state->lastsynctype];
|
||
|
||
//date and time strings
|
||
char * timestr = getTimeN(time(NULL));
|
||
char * datestr = getDateN(time(NULL));
|
||
|
||
if (source_id != 0)
|
||
{
|
||
event_struct->Event_History_Items[0].write = 0;
|
||
if (state->lastsynctype != -1)
|
||
event_struct->Event_History_Items[0].systype = state->lastsynctype;
|
||
else event_struct->Event_History_Items[0].systype = 39; //generic digital call
|
||
event_struct->Event_History_Items[0].subtype = subtype; //voice
|
||
event_struct->Event_History_Items[0].gi = state->gi[slot]; //need this add this to link control messages
|
||
event_struct->Event_History_Items[0].sys_id1 = sys_id1;
|
||
event_struct->Event_History_Items[0].sys_id2 = sys_id2;
|
||
event_struct->Event_History_Items[0].sys_id3 = sys_id3;
|
||
event_struct->Event_History_Items[0].sys_id4 = sys_id4;
|
||
event_struct->Event_History_Items[0].sys_id5 = sys_id5;
|
||
event_struct->Event_History_Items[0].enc = enc;
|
||
event_struct->Event_History_Items[0].enc_alg = alg_id;
|
||
event_struct->Event_History_Items[0].enc_key = key_id;
|
||
event_struct->Event_History_Items[0].mi = mi;
|
||
event_struct->Event_History_Items[0].svc = svc_opts;
|
||
event_struct->Event_History_Items[0].source_id = source_id;
|
||
event_struct->Event_History_Items[0].target_id = target_id;
|
||
event_struct->Event_History_Items[0].channel = channel; //need to add this to trunking messages, if tuned from call grant
|
||
event_struct->Event_History_Items[0].event_time = time(NULL);
|
||
sprintf (event_struct->Event_History_Items[0].sysid_string, "%s", sysid_string);
|
||
sprintf (event_struct->Event_History_Items[0].src_str, "%s", src_str);
|
||
sprintf (event_struct->Event_History_Items[0].tgt_str, "%s", tgt_str);
|
||
|
||
sprintf (event_struct->Event_History_Items[0].t_name, "%s", t_name);
|
||
sprintf (event_struct->Event_History_Items[0].s_name, "%s", s_name);
|
||
sprintf (event_struct->Event_History_Items[0].t_mode, "%s", t_mode);
|
||
sprintf (event_struct->Event_History_Items[0].s_mode, "%s", s_mode);
|
||
|
||
}
|
||
|
||
//Craft an event string for ncurses event history, and a more complex string for logging
|
||
char event_string[200]; memset(event_string, 0, sizeof(event_string));
|
||
|
||
//WIP: Seperate Voice Call Event Strings when SRC/TGT values are numerical,
|
||
//and a seperate one for when they are string values (M17, YSF, DSTAR, and dPMR, or use special formatting)
|
||
if (state->lastsynctype == 30 || state->lastsynctype == 30) //YSF Fusion //TODO: Data calls dumping a lot of events as VOICE
|
||
{
|
||
//TODO: See if we can add some decoded data as well in the future to an event string
|
||
sprintf (event_string, "%s %s %s TGT: %s SRC: %s ", datestr, timestr, sys_string, state->ysf_tgt, state->ysf_src);
|
||
}
|
||
else if (state->lastsynctype == 16 || state->lastsynctype == 17) //M17
|
||
{
|
||
//TODO: See if we can add some decoded data as well in the future to an event string
|
||
if (state->m17_dst == 0xFFFFFFFFFFFF)
|
||
sprintf (event_string, "%s %s %s TGT: %s SRC: %s CAN: %02d;", datestr, timestr, sys_string, "BROADCAST", state->m17_src_str, state->m17_can);
|
||
else
|
||
sprintf (event_string, "%s %s %s TGT: %s SRC: %s CAN: %02d;", datestr, timestr, sys_string, state->m17_dst_str, state->m17_src_str, state->m17_can);
|
||
}
|
||
else if (state->lastsynctype == 6 || state->lastsynctype == 7 || state->lastsynctype == 18 || state->lastsynctype == 19) //DSTAR
|
||
{
|
||
//TODO: See if we can add some decoded data as well in the future to an event string
|
||
sprintf (event_string, "%s %s %s TGT: %s SRC: %s ", datestr, timestr, sys_string, state->dstar_dst, state->dstar_src);
|
||
}
|
||
else if (state->lastsynctype == 20 || state->lastsynctype == 24 || state->lastsynctype == 21 || state->lastsynctype == 25 || state->lastsynctype == 22 || state->lastsynctype == 26 || state->lastsynctype == 23 || state->lastsynctype == 27) //dPMR
|
||
{
|
||
//TODO: See if we can add some decoded data as well in the future to an event string
|
||
sprintf (event_string, "%s %s %s CC: %02d; TGT: %s; SRC: %s; ", datestr, timestr, sys_string, state->dpmr_color_code, state->dpmr_target_id, state->dpmr_caller_id);
|
||
if (state->dPMRVoiceFS2Frame.Version[0] == 3)
|
||
strcat (event_string, "Scrambler Enc; ");
|
||
}
|
||
//TODO: Find out why EDACS is also placing items into Slot 2 Event History with valid src, but invalid tg (not a problem, just odd)
|
||
else if (state->lastsynctype == 14 || state->lastsynctype == 15 || state->lastsynctype == 37 || state->lastsynctype == 38) //EDACS Calls
|
||
{
|
||
//is this AFS format, or EA format, also, need to re-add Ilya's other decoded call elements into this somehow
|
||
if (state->ea_mode == 1)
|
||
{
|
||
sprintf (event_string, "%s %s %s TGT: %07d; SRC: %07d; LCN: %02d; SITE: %d:%d.%04X; ", datestr, timestr, sys_string, target_id, source_id, channel, sys_id1, sys_id2, sys_id3);
|
||
}
|
||
else
|
||
{
|
||
//TODO: Have EDACS decoder write a nicer string for us to use in this instance
|
||
// Compute AFS for display purposes only
|
||
int a = (state->tg_hold >> state->edacs_a_shift) & state->edacs_a_mask;
|
||
int f = (state->tg_hold >> state->edacs_f_shift) & state->edacs_f_mask;
|
||
int s = state->tg_hold & state->edacs_s_mask;
|
||
char afs_str[8];
|
||
getAfsString(state, afs_str, a, f, s);
|
||
sprintf (event_string, "%s %s %s Voice AFS: %s ", datestr, timestr, sys_string, afs_str);
|
||
}
|
||
}
|
||
else if (state->lastsynctype == 10 || state->lastsynctype == 11 || state->lastsynctype == 12 || state->lastsynctype == 13 ||
|
||
state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34 ) //DMR
|
||
{
|
||
if (sys_id1)
|
||
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; CC: %02d; SYS: %X; ", datestr, timestr, sys_string, target_id, source_id, sys_id2, sys_id1);
|
||
else
|
||
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; CC: %02d; ", datestr, timestr, sys_string, target_id, source_id, sys_id2);
|
||
if (enc)
|
||
strcat(event_string, "ENC; ");
|
||
if (alg_id != 0)
|
||
{
|
||
char ess_str[30];
|
||
sprintf (ess_str, "ALG: %02X; KID: %02X; ", alg_id, key_id);
|
||
strcat(event_string, ess_str);
|
||
}
|
||
|
||
//monitor for misc link control that may set a SO without having SO inside of it,
|
||
//those could cause misc issues here, will need to observe and make adjustments
|
||
if (svc_opts & 0x80)
|
||
strcat (event_string, "Emergency; ");
|
||
|
||
if (svc_opts & 0x08)
|
||
strcat (event_string, "Broadcast; ");
|
||
|
||
if (svc_opts & 0x04)
|
||
strcat (event_string, "OVCM; ");
|
||
|
||
if (state->gi[slot] == 0)
|
||
strcat (event_string, "Group; ");
|
||
else if (state->gi[slot] == 1)
|
||
strcat (event_string, "Private; ");
|
||
|
||
if (mfid == 0x10)
|
||
{
|
||
if (svc_opts & 0x20)
|
||
strcat (event_string, "TXI; ");
|
||
else if (svc_opts & 0x10)
|
||
strcat (event_string, "TXI; "); //this is the svc opt bit that tells you when the next VC6 will be pre-empted, but not helpful here
|
||
|
||
if (svc_opts & 0x03)
|
||
strcat (event_string, "PRIORITY; "); //need to break this apart into each one, but need to double check the decoded value is accurate
|
||
}
|
||
|
||
}
|
||
else if (state->lastsynctype == 0 || state->lastsynctype == 1 || state->lastsynctype == 35 || state->lastsynctype == 36)
|
||
{
|
||
if (sys_id1)
|
||
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; NAC: %03X; NET_STS: %05X:%03X:%d.%d; ", datestr, timestr, sys_string, target_id, source_id, sys_id3, sys_id1, sys_id2, sys_id4, sys_id5);
|
||
else
|
||
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; NAC: %03X; ", datestr, timestr, sys_string, target_id, source_id, sys_id3);
|
||
if (alg_id != 0 && alg_id != 0x80)
|
||
{
|
||
char ess_str[30];
|
||
sprintf (ess_str, "ENC; ALG: %02X; KID: %04X; ", alg_id, key_id);
|
||
strcat(event_string, ess_str);
|
||
}
|
||
if (svc_opts & 0x80)
|
||
strcat (event_string, "Emergency; ");
|
||
if (state->gi[slot] == 0)
|
||
strcat (event_string, "Group; ");
|
||
else if (state->gi[slot] == 1)
|
||
strcat (event_string, "Private; ");
|
||
}
|
||
|
||
else if (state->lastsynctype == 28 || state->lastsynctype == 29)
|
||
{
|
||
if (sys_id1)
|
||
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; RAN: %02d; SYS: %d.%d; ", datestr, timestr, sys_string, target_id, source_id, sys_id3, sys_id1, sys_id2);
|
||
else
|
||
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; RAN: %02d; ", datestr, timestr, sys_string, target_id, source_id, sys_id3);
|
||
if (enc)
|
||
strcat(event_string, "ENC; ");
|
||
if (alg_id != 0)
|
||
{
|
||
char ess_str[30];
|
||
sprintf (ess_str, "ALG: %d; KID: %02X; ", alg_id, key_id);
|
||
strcat(event_string, ess_str);
|
||
}
|
||
if (state->gi[slot] == 0)
|
||
strcat (event_string, "Group; ");
|
||
else if (state->gi[slot] == 1)
|
||
strcat (event_string, "Private; ");
|
||
}
|
||
|
||
if (t_name_loaded)
|
||
{
|
||
char group[420];
|
||
sprintf (group, "TName: %s; Mode: %s; ", t_name, t_mode);
|
||
strcat (event_string, group);
|
||
}
|
||
if (s_name_loaded)
|
||
{
|
||
char private[420];
|
||
sprintf (private, "SName: %s; Mode: %s; ", s_name, s_mode);
|
||
strcat (event_string, private);
|
||
}
|
||
|
||
sprintf (event_struct->Event_History_Items[0].event_string, "%s", event_string);
|
||
|
||
if (timestr != NULL)
|
||
{
|
||
free (timestr);
|
||
timestr = NULL;
|
||
}
|
||
if (datestr != NULL)
|
||
{
|
||
free (datestr);
|
||
datestr = NULL;
|
||
}
|
||
}
|
||
|
||
void watchdog_event_datacall (dsd_opts * opts, dsd_state * state, uint32_t src, uint32_t dst, char * data_string, uint8_t slot)
|
||
{
|
||
UNUSED(opts);
|
||
state->event_history_s[slot].Event_History_Items[0].write = 0;
|
||
state->event_history_s[slot].Event_History_Items[0].systype = state->lastsynctype;
|
||
state->event_history_s[slot].Event_History_Items[0].subtype = 6; //data
|
||
state->event_history_s[slot].Event_History_Items[0].gi = state->gi[slot];
|
||
state->event_history_s[slot].Event_History_Items[0].enc = 0;
|
||
state->event_history_s[slot].Event_History_Items[0].enc_alg = 0;
|
||
state->event_history_s[slot].Event_History_Items[0].enc_key = 0;
|
||
state->event_history_s[slot].Event_History_Items[0].mi = 0;
|
||
state->event_history_s[slot].Event_History_Items[0].svc = 0;
|
||
state->event_history_s[slot].Event_History_Items[0].source_id = src;
|
||
state->event_history_s[slot].Event_History_Items[0].target_id = dst;
|
||
state->event_history_s[slot].Event_History_Items[0].channel = 0;
|
||
state->event_history_s[slot].Event_History_Items[0].event_time = time(NULL);
|
||
|
||
//date and time strings //getTimeN(time(NULL)); //getDateN(time(NULL));
|
||
char * timestr = getTimeN(time(NULL));
|
||
char * datestr = getDateN(time(NULL));
|
||
|
||
char event_string[2000]; memset (event_string, 0, sizeof(event_string));
|
||
sprintf (event_string, "%s %s ", datestr, timestr);
|
||
strcat (event_string, data_string); //may need to check for potential overflow of this
|
||
sprintf (state->event_history_s[slot].Event_History_Items[0].event_string, "%s", event_string); //could change this to a strncpy to prevent potential overflow
|
||
|
||
if (timestr != NULL)
|
||
{
|
||
free (timestr);
|
||
timestr = NULL;
|
||
}
|
||
if (datestr != NULL)
|
||
{
|
||
free (datestr);
|
||
datestr = NULL;
|
||
}
|
||
|
||
//call alert on data calls
|
||
if (opts->call_alert)
|
||
beeper (opts, state, slot, 80, 20, 3);
|
||
}
|