Files
dsd-fme/src/dsd_ncurses_printer.c
lwvmobile c6b2320cbd Ncurses:
Don't display the lines for Pulse Digital Output if it isn't opened (when using analog only -fA);
2025-05-17 15:00:09 -04:00

1670 lines
58 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*-------------------------------------------------------------------------------
* dsd_ncurses_printer.c
* DSD-FME ncurses open, printer, and close
*
* ASCII art generated by:
* https://fsymbols.com/generators/carty/
*
* LWVMOBILE
* 2025-05 DSD-FME Florida Man Edition
*
* ilyacodes
* 2024-03 EDACS-FME display improvements
*-----------------------------------------------------------------------------*/
#include "dsd.h"
#include "git_ver.h"
#include "synctype.h"
char mbeversionstr[25]; //MBElib version string
static unsigned long long int edacs_channel_tree[33][6];
char * FM_bannerN[9] = {
" ",
" ██████╗ ██████╗██████╗    ███████╗███╗ ███╗███████╗ ",
" ██╔══██╗██╔════╝██╔══██╗   ██╔════╝████╗ ████║██╔════╝ ",
" ██║ ██║╚█████╗ ██║ ██║   █████╗ ██╔████╔██║█████╗ ",
" ██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
" ██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗ ",
" ╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝ ",
" ",
" "
};
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 ncursesOpen (dsd_opts * opts, dsd_state * state)
{
UNUSED(opts); UNUSED(state);
// state->menuopen = 1; //flag the menu is open, stop processing getFrameSync
mbe_printVersion (mbeversionstr);
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
init_pair(7, COLOR_BLUE, COLOR_BLACK); //Blue on Black
init_pair(8, COLOR_BLACK, COLOR_WHITE); //Black on White
init_pair(9, COLOR_RED, COLOR_WHITE); //Red on White
init_pair(10, COLOR_BLUE, COLOR_WHITE); //Blue on White
#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
init_pair(7, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme
init_pair(8, COLOR_BLACK, COLOR_WHITE); //White Card Color Scheme
init_pair(9, COLOR_BLACK, COLOR_WHITE); //White Card Color Scheme
init_pair(10, COLOR_BLACK, COLOR_WHITE); //White Card Color Scheme
#endif
noecho();
cbreak();
//initialize this
memset (edacs_channel_tree, 0, sizeof(edacs_channel_tree));
}
static int lls = -1;
void
ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
uint8_t idas = 0;
int level = 0;
int c = 0;
int i = 0;
if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN -
{
timeout(0); //
c = getch(); //
}
//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;
if (state->ea_mode == 0 && state->lastsrc == 0x800) //this was from a grant update, so set this to 0
edacs_channel_tree[state->edacs_vc_lcn][3] = 0;
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 (" ENTER 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", mbeversionstr);
#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); //Adjust manually now with { and }
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 && opts->analog_only == 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
}
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: %010llX", 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: %010llX", 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
attron(COLOR_PAIR(4)); //cyan for history
printw ("--Latest Event History ([|])---Slot %d (\\)---Cycle (h)-Short/Long/Off----------\n", state->eh_slot+1);
if (opts->ncurses_history != 0)
{
for (uint16_t i = (state->eh_index+1); i < (state->eh_index+11); i++)
{
uint16_t string_size = 71; //short uniform size that doesn't exceed the fence
if (opts->ncurses_history == 2)
string_size = 1999; //full string size
uint8_t slot = state->eh_slot;
uint8_t color_pair = state->event_history_s[slot].Event_History_Items[i%255].color_pair; //this is the color pair assignment for this line
attron(COLOR_PAIR(4));
char text_string[2000]; memset (text_string, 0, sizeof(text_string));
sprintf (text_string, "%s", "BUMBLEBEETUNA");
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, string_size*sizeof(char));
text_string[string_size] = 0; //terminate string
printw ("| #%03d ", i%255);
attron(COLOR_PAIR(color_pair)); //this is where the custom color switch occurs for the event_string
printw ("%s\n", text_string);
attron(COLOR_PAIR(4));
}
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 ("|");
attron(COLOR_PAIR(4)); //feel free to change this to any value you want
printw (" %s\n", state->event_history_s[slot].Event_History_Items[i%255].text_message);
attron(COLOR_PAIR(4));
}
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].alias, 13) != 0)
{
printw ("|");
attron(COLOR_PAIR(4)); //feel free to change this to any value you want
printw (" Alias: %s \n", state->event_history_s[slot].Event_History_Items[i%255].alias);
attron(COLOR_PAIR(4));
}
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].gps_s, 13) != 0)
{
printw ("|");
attron(COLOR_PAIR(4)); //feel free to change this to any value you want
printw (" GPS: %s \n", state->event_history_s[slot].Event_History_Items[i%255].gps_s);
attron(COLOR_PAIR(4));
}
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].internal_str, 13) != 0)
{
printw ("|");
attron(COLOR_PAIR(4)); //feel free to change this to any value you want
printw (" DSD-FME: %s \n", state->event_history_s[slot].Event_History_Items[i%255].internal_str);
attron(COLOR_PAIR(4));
}
}
}
printw ("------------------------------------------------------------------------------\n");
attroff(COLOR_PAIR(4)); //cyan for history
refresh();
//handle input
ncurses_input_handler(opts, state, c);
}
void ncursesClose ()
{
endwin();
}