/*------------------------------------------------------------------------------- * 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(); }