/*------------------------------------------------------------------------------- * dsd_ncurses.c * DSD-FME ncurses terminal printer with menu system * * ASCII art generated by: * https://fsymbols.com/generators/carty/ * * LWVMOBILE * 2022-08 DSD-FME Florida Man Edition *-----------------------------------------------------------------------------*/ #include "dsd.h" #include "git_ver.h" uint32_t temp_freq = -1; //struct for checking existence of directory to write to struct stat st_wav = {0}; int reset = 0; int tg; int tgR; int tgn; int rd; int rdR; int rn; int nc; int src; int lls = -1; int dcc = -1; int i = 0; char versionstr[25]; unsigned long long int call_matrix[33][6]; char * FM_bannerN[9] = { " ", " ██████╗ ██████╗██████╗    ███████╗███╗ ███╗███████╗ ", " ██╔══██╗██╔════╝██╔══██╗   ██╔════╝████╗ ████║██╔════╝ ", " ██║ ██║╚█████╗ ██║ ██║   █████╗ ██╔████╔██║█████╗ ", " ██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ ", " ██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗ ", " ╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝ ", " ", " " }; char * SyncTypes[44] = { "P25P1", "P25P1", "X2TDMA DATA", "X2TDMA DATA", "X2TDMA VOICE", "X2TDMA VOICE", "DSTAR", //voice "DSTAR", //voice "NXDN VOICE", "NXDN VOICE", "DMR", //10 "DMR", "DMR", "DMR", "EDACS/PV", "EDACS/PV", "NXDN VOICE", //DATA "NXDN VOICE", //DATA "DSTAR", //header "DSTAR", //header "dPMR", //20 "dPMR", "dPMR", "dPMR", "dPMR", "dPMR", "dPMR", "dPMR", "NXDN", "NXDN", "YSF", //30 "YSF", //31 "DMR", "DMR", "DMR", "P25P2", "P25P2", "EDACS/PV", //37 "EDACS/PV", //38 "", "" }; char * DMRBusrtTypes[32] = { "PI ", "VLC ", "TLC ", "CSBK ", "MBCH ", "MBCC ", "DATA ", "R12D ", "R34D ", "IDLE ", "R1_D ", "ERR ", "DUID ERR ", "R-S ERR ", "CRC ERR ", "NULL ", "VOICE", " ", "INIT ", "INIT ", "PTT", //20 MAC "VOICE", //21 MAC_ACTIVE "HANGTIME", //22 MAC "PTT END", //23 MAC "IDLE", //24 MAC "HDU", "VOICE", //26 LDU1 "VOICE", //27 LDU2 "TDU/LC", "TSBK", "SIGNAL", //MAC_SIGNAL "SIGNAL" //MAC_SIGNAL }; //Sorry Remus :( void beeper (dsd_opts * opts, dsd_state * state, int lr) { UNUSED(state); int i, j, n; //use lr as left or right channel designation in stereo config float samp_f[160]; //mono float sample float samp_fs[320]; //stereo float sample short samp_s[160]; //mono short sample short samp_ss[320]; //stereo short sample short samp_su[960]; //mono short upsample short outbuf[6]; //temp storage for upsample n = 0; //rolling sine wave 'degree' //each j increment is 20 ms at 160 samples / 8 kHz for (j = 0; j < 3; j++) { //'zero' out stereo mix samples memset (samp_fs, 0.1f, sizeof(samp_fs)); memset (samp_ss, 0, sizeof(samp_ss)); //generate a tone (ID=45, AD=103, rolling n value) soft_tonef(samp_f, n, 45, 103); //convert float to short if required if (opts->floating_point == 0) { mbe_floattoshort(samp_f, samp_s); for (i = 0; i < 160; i++) { samp_s[i] *= 4000; //apply gain samp_ss[(i*2)+lr] = samp_s[i]; } } //load returned tone sample into appropriate channel -- left = +0; right = +1; for (i = 0; i < 160; i++) samp_fs[(i*2)+lr] = samp_f[i]; //play sample 3 times (20ms x 3 = 60ms) if (opts->audio_out_type == 0) //Pulse Audio { if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1) pa_simple_write(opts->pulse_digi_dev_out, samp_fs, 320*4, NULL); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1) pa_simple_write(opts->pulse_digi_dev_out, samp_f, 160*4, NULL); if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0) pa_simple_write(opts->pulse_digi_dev_out, samp_ss, 320*2, NULL); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0) pa_simple_write(opts->pulse_digi_dev_out, samp_s, 160*2, NULL); } else if (opts->audio_out_type == 1) //STDOUT { if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1) write(opts->audio_out_fd, samp_fs, 320*4); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1) write(opts->audio_out_fd, samp_f, 160*4); if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0) write(opts->audio_out_fd, samp_ss, 320*2); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0) write(opts->audio_out_fd, samp_s, 160*2); } else if (opts->audio_out_type == 2) //OSS Variable Output (no float) { if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0) write(opts->audio_out_fd, samp_ss, 320*2); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0) write(opts->audio_out_fd, samp_s, 160*2); } else if (opts->audio_out_type == 5) //OSS 48k/1 configuration with upsample { short prev = 0; for (i = 0; i < 160; i++) { upsampleS (samp_s[i], prev, outbuf); samp_su[(i*6)+0] = outbuf[0]; samp_su[(i*6)+1] = outbuf[1]; samp_su[(i*6)+2] = outbuf[2]; samp_su[(i*6)+3] = outbuf[3]; samp_su[(i*6)+4] = outbuf[4]; samp_su[(i*6)+5] = outbuf[5]; } write (opts->audio_out_fd, samp_su, 960*2); } } } char * getDateN(void) { #ifdef AERO_BUILD char datename[80]; #else char datename[99]; #endif char * curr2; struct tm * to; time_t t; t = time(NULL); to = localtime( & t); strftime(datename, sizeof(datename), "%Y-%m-%d", to); curr2 = strtok(datename, " "); return curr2; } time_t nowN; char * getTimeN(void) //get pretty hh:mm:ss timestamp { time_t t = time(NULL); char * curr; char * stamp = asctime(localtime( & t)); curr = strtok(stamp, " "); curr = strtok(NULL, " "); curr = strtok(NULL, " "); curr = strtok(NULL, " "); return curr; } //this version is broken now in Cygwin with the 80 value, reverted back char * getDateC(time_t t) { char datename[99]; char * curr2; struct tm * to; to = localtime( & t); strftime(datename, sizeof(datename), "%Y-%m-%d", to); curr2 = strtok(datename, " "); return curr2; } char * getTimeC(time_t t) //get pretty hh:mm:ss timestamp { char * curr; char * stamp = asctime(localtime( & t)); curr = strtok(stamp, " "); curr = strtok(NULL, " "); curr = strtok(NULL, " "); curr = strtok(NULL, " "); return curr; } //testing a few things, going to put this into ncursesMenu #define WIDTH 36 #define HEIGHT 25 int startx = 0; int starty = 0; char *choicesc[] = { "Return", "Save Decoded Audio WAV (Legacy Mode)", "Save Signal to Symbol Capture Bin", "Toggle Muting Encrypted Traffic ", "Save Per Call Decoded WAV (AUTO/TDMA and NXDN)", "Setup and Start RTL Input ", "Retune RTL Dongle ", "Toggle C4FM/QPSK (P2 TDMA CC)", "Toggle C4FM/QPSK (P1 FDMA CC)", "Start TCP Direct Link Audio", "Configure RIGCTL", "Stop All Decoded WAV Saving", "Read OP25/FME Symbol Capture Bin", "Replay Last Symbol Capture Bin", "Stop & Close Symbol Capture Bin Playback", "Stop & Close Symbol Capture Bin Saving", "Toggle Call Alert Beep ", "Resume Decoding" }; //make tweaks for TDMA and AUTO? char *choices[] = { "Resume Decoding", "Decode AUTO", "Decode TDMA", "Decode DSTAR", "Decode M17", "Decode EDACS/PV", "Decode P25p2", "Decode dPMR", "Decode NXDN48", "Decode NXDN96", "Decode DMR", "Decode YSF", "Toggle Signal Inversion", "Key Entry", "Reset Call History", "Toggle Payloads to Console", "Manually Set p2 Parameters", //16 "Input & Output Options", "LRRP Data to File", "Exit DSD-FME", }; int n_choices = sizeof(choices) / sizeof(char *); // int n_choicesb = sizeof(choicesb) / sizeof(char *); int n_choicesc = sizeof(choicesc) / sizeof(char *); void print_menu(WINDOW *menu_win, int highlight) { int x, y, i; x = 2; y = 2; box(menu_win, 0, 0); for(i = 0; i < n_choices; ++i) { if(highlight == i + 1) /* High light the present choice */ { wattron(menu_win, A_REVERSE); mvwprintw(menu_win, y, x, "%s", choices[i]); wattroff(menu_win, A_REVERSE); } else mvwprintw(menu_win, y, x, "%s", choices[i]); ++y; } wrefresh(menu_win); } void print_menuc(WINDOW *menu_win, int highlight) { int x, y, i; x = 2; y = 2; box(menu_win, 0, 0); for(i = 0; i < n_choicesc; ++i) { if(highlight == i + 1) /* High light the present choice */ { wattron(menu_win, A_REVERSE); mvwprintw(menu_win, y, x, "%s", choicesc[i]); wattroff(menu_win, A_REVERSE); } else mvwprintw(menu_win, y, x, "%s", choicesc[i]); ++y; } wrefresh(menu_win); } //end Testing void ncursesOpen (dsd_opts * opts, dsd_state * state) { //this is primarily used to push a quick audio blip through OSS so it will show up in the mixer immediately if (opts->audio_out_type == 2 || opts->audio_out_type == 5) beeper (opts, state, 0); // state->menuopen = 1; //flag the menu is open, stop processing getFrameSync mbe_printVersion (versionstr); setlocale(LC_ALL, ""); initscr(); //Initialize NCURSES screen window start_color(); #ifdef PRETTY_COLORS init_pair(1, COLOR_YELLOW, COLOR_BLACK); //Yellow/Amber for frame sync/control channel, NV style init_pair(2, COLOR_RED, COLOR_BLACK); //Red for Terminated Calls init_pair(3, COLOR_GREEN, COLOR_BLACK); //Green for Active Calls init_pair(4, COLOR_CYAN, COLOR_BLACK); //Cyan for Site Extra and Patches init_pair(5, COLOR_MAGENTA, COLOR_BLACK); //Magenta for no frame sync/signal init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme #else init_pair(1, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(2, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(3, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(4, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(5, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme #endif noecho(); cbreak(); } //ncursesMenu void ncursesMenu (dsd_opts * opts, dsd_state * state) { //update sync time on cc sync so we don't immediately go CC hunting when exiting the menu state->last_cc_sync_time = time(NULL); //close pulse output if not null output if (opts->audio_out == 1 && opts->audio_out_type == 0) { closePulseOutput (opts); } //close OSS output if (opts->audio_out_type == 2 || opts->audio_out_type == 5) { close (opts->audio_out_fd); } if (opts->audio_in_type == 0) //close pulse input if it is the specified input method { closePulseInput(opts); } if (opts->audio_in_type == 3) { #ifdef USE_RTLSDR rtl_clean_queue(); #endif } if (opts->audio_in_type == 8) //close TCP input SF file so we don't buffer audio while not decoding { sf_close(opts->tcp_file_in); } if (opts->audio_in_type == 5) //close UDP input SF file so we don't buffer audio while not decoding { // sf_close(opts->udp_file_in); //disable for testing } state->payload_keyid = 0; state->payload_keyidR = 0; //zero out to fix call history 'scrolling' bug when changing decoding types state->nxdn_last_tg = 0; state->nxdn_last_ran = -1; //0 state->nxdn_last_rid = 0; //0 WINDOW *menu_win; WINDOW *test_win; WINDOW *entry_win; WINDOW *info_win; int highlight = 1; int highlightc = 1; int choice = 0; int choicec = 0; int c; int e; startx = 2; starty = 1; menu_win = newwin(HEIGHT, WIDTH, starty, startx); keypad(menu_win, TRUE); mvprintw(0, 0, " Use arrow keys to go up and down, Press ENTER to select a choice."); refresh(); print_menu(menu_win, highlight); while(1) { c = wgetch(menu_win); switch(c) { case KEY_UP: if(highlight == 1) highlight = n_choices; else --highlight; break; case KEY_DOWN: if(highlight == n_choices) highlight = 1; else ++highlight; break; case 10: choice = highlight; break; default: //mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c); refresh(); break; } print_menu(menu_win, highlight); if (highlight == 2) { info_win = newwin(7, WIDTH+18, starty, startx+20); box (info_win, 0, 0); mvwprintw(info_win, 2, 2, " AUTO Decoding Class Supports the following:"); mvwprintw(info_win, 3, 2, " P25p1, YSF, DSTAR, X2-TDMA and DMR"); mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 4800bps (no H8D-QPSK)"); wrefresh(info_win); } if (highlight == 3) { info_win = newwin(7, WIDTH+18, starty, startx+20); box (info_win, 0, 0); mvwprintw(info_win, 2, 2, " TDMA Trunking Class Supports the following:"); mvwprintw(info_win, 3, 2, " P25p1 Voice/Control, P25p2 Traffic, and DMR"); mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 4800 or 6000 (no H8D-QPSK)"); wrefresh(info_win); } if (highlight == 7) { info_win = newwin(7, WIDTH+18, starty, startx+20); box (info_win, 0, 0); mvwprintw(info_win, 2, 2, " P25p2 Control (MAC_SIGNAL) or Single Voice Freq."); mvwprintw(info_win, 3, 2, " NOTE: Manually set WACN/SYSID/CC on Voice Only"); mvwprintw(info_win, 4, 2, " C4FM or QPSK @ 6000 (no H8D-QPSK)"); wrefresh(info_win); } //Input Output Options if (choice == 18) { //test making a new window while other window is open test_win = newwin(HEIGHT-1, WIDTH+9, starty+5, startx+5); keypad(menu_win, FALSE); keypad(test_win, TRUE); mvprintw(0, 0, "Input & Output Options "); refresh(); print_menuc(test_win, highlightc); while(1) { e = wgetch(test_win); switch(e) { case KEY_UP: if(highlightc == 1) highlightc = n_choicesc; else --highlightc; break; case KEY_DOWN: if(highlightc == n_choicesc) highlightc = 1; else ++highlightc; break; case 10: choicec = highlightc; break; default: //mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c); refresh(); break; } print_menuc(test_win, highlightc); if (choicec == 2) { sprintf (opts->wav_out_file, "%s %s DSD-FME-DECODED.wav", getDateN(), getTimeN()); openWavOutFile (opts, state); } if (choicec == 3) { //read in filename for symbol capture bin entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter FME Symbol Capture Bin Filename"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%s", opts->symbol_out_file); //&opts->symbol_out_file noecho(); openSymbolOutFile (opts, state); } if (choicec == 4) { //toggle all mutes if (opts->unmute_encrypted_p25 == 0) { opts->unmute_encrypted_p25 = 1; } else opts->unmute_encrypted_p25 = 0; if (opts->dmr_mute_encL == 0) { opts->dmr_mute_encL = 1; } else opts->dmr_mute_encL = 0; if (opts->dmr_mute_encR == 0) { opts->dmr_mute_encR = 1; } else opts->dmr_mute_encR = 0; } if (choicec == 5) { char wav_file_directory[1024]; sprintf (wav_file_directory, "%s", opts->wav_out_dir); wav_file_directory[1023] = '\0'; if (stat(wav_file_directory, &st_wav) == -1) { fprintf (stderr, "%s wav file directory does not exist\n", wav_file_directory); fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory); mkdir(wav_file_directory, 0700); } opts->dmr_stereo_wav = 1; //catch all in case of no file name set, won't crash or something sprintf (opts->wav_out_file, "./%s/DSD-FME-X1.wav", opts->wav_out_dir); // sprintf (opts->wav_out_fileR, "./%s/DSD-FME-X2.wav", opts->wav_out_dir); // openWavOutFileL (opts, state); openWavOutFileR (opts, state); } if (choicec == 6) { int confirm = 0; #ifdef USE_RTLSDR entry_win = newwin(6, WIDTH+6, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RTL Device Index Number"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_dev_index); noecho(); entry_win = newwin(6, WIDTH+6, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RTL Device PPM Error"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtlsdr_ppm_error); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Frequency in Hz (851.8 MHz is 851800000 Hz) "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtlsdr_center_freq); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter BW (8, 12, 24, 48)(12 Recommended)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_bandwidth); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RTL Gain Value (0-49) (0 = AGC)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_gain_value); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RTL UDP Port - Optional (Default = 0)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_udp_port); noecho(); entry_win = newwin(8, WIDTH+22, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RTL RMS Squelch Level (NXDN/dPMR only)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_squelch_level); noecho(); entry_win = newwin(17, WIDTH+20, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Starting RTL Input. Cannot Release/Stop Until Exit."); mvwprintw(entry_win, 4, 2, " RTL Frequency: %d Hz", opts->rtlsdr_center_freq); mvwprintw(entry_win, 5, 2, " RTL Device Index Number: %d", opts->rtl_dev_index); mvwprintw(entry_win, 6, 2, " RTL Device Bandwidth: %d kHz", opts->rtl_bandwidth); mvwprintw(entry_win, 7, 2, " RTL Device Gain: %d", opts->rtl_gain_value); mvwprintw(entry_win, 8, 2, " RTL Device UDP Port: %d", opts->rtl_udp_port); mvwprintw(entry_win, 9, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error); mvwprintw(entry_win, 10, 2, " RTL RMS Squelch: %d", opts->rtl_squelch_level); mvwprintw(entry_win, 12, 2, " Are You Sure?"); mvwprintw(entry_win, 13, 2, " 1 = Yes, 2 = No "); mvwprintw(entry_win, 14, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &confirm); noecho(); refresh(); //works well, but can't release dongle later, so its a one way trip until exit //TODO: Write function to release the dongle -- call cleanup_rtlsdr_stream() if (confirm == 1) { opts->audio_in_type = 3; //RTL input, only set this on confirm choicec = 18; //exit to decoder screen only if confirmed, otherwise, just go back } #endif } if (choicec == 7) //RTL DEV Retune { //read in new rtl frequency #ifdef USE_RTLSDR entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Frequency in Hz (851.8 MHz is 851800000 Hz) "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtlsdr_center_freq); noecho(); temp_freq = opts->rtlsdr_center_freq; #endif choicec = 18; } if (choicec == 8) { if (state->rf_mod == 0) { state->rf_mod = 1; state->samplesPerSymbol = 8; state->symbolCenter = 3; opts->mod_c4fm = 0; opts->mod_qpsk = 1; } else { state->rf_mod = 0; state->samplesPerSymbol = 10; state->symbolCenter = 4; opts->mod_c4fm = 1; opts->mod_qpsk = 0; } } if (choicec == 9) { if (state->rf_mod == 0) { state->rf_mod = 1; state->samplesPerSymbol = 10; state->symbolCenter = 4; opts->mod_c4fm = 0; opts->mod_qpsk = 1; } else { state->rf_mod = 0; state->samplesPerSymbol = 10; state->symbolCenter = 4; opts->mod_c4fm = 1; opts->mod_qpsk = 0; } } // if (choicec == 9) // { // if (opts->audio_out == 0) // { // opts->audio_out = 1; // opts->audio_out_type = 0; // // state->audio_out_buf_p = 0; // // state->audio_out_buf_pR = 0; // state->audio_out_idx = 0; // state->audio_out_idx2 = 0; // state->audio_out_idxR = 0; // state->audio_out_idx2R = 0; // } // else // { // opts->audio_out = 0; // opts->audio_out_type = 9; // // state->audio_out_buf_p = 0; // // state->audio_out_buf_pR = 0; // state->audio_out_idx = 0; // state->audio_out_idx2 = 0; // state->audio_out_idxR = 0; // state->audio_out_idx2R = 0; // } // } //TCP Audio Input if (choicec == 10) { //read in tcp hostname sprintf (opts->tcp_hostname, "%s", "localhost"); opts->tcp_portno = 7355; entry_win = newwin(8, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter TCP Direct Link Hostname:"); mvwprintw(entry_win, 3, 2, " (default is localhost)"); mvwprintw(entry_win, 4, 2, " "); mvwprintw(entry_win, 5, 3, " "); echo(); refresh(); wscanw(entry_win, "%s", opts->tcp_hostname); noecho(); //read in tcp port number entry_win = newwin(8, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter TCP Direct Link Port Number:"); mvwprintw(entry_win, 3, 2, " (default is 7355)"); mvwprintw(entry_win, 4, 2, " "); mvwprintw(entry_win, 5, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->tcp_portno); noecho(); opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno); if (opts->tcp_sockfd == 0) goto TCP_END; //successful connection, continue; opts->audio_in_type = 8; opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); opts->audio_in_file_info->samplerate=opts->wav_sample_rate; opts->audio_in_file_info->channels=1; opts->audio_in_file_info->seekable=0; opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE; opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0); if(opts->tcp_file_in == NULL) { fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL)); if (opts->audio_out_type == 0) { sprintf (opts->audio_in_dev, "%s", "pulse"); opts->audio_in_type = 0; } else opts->audio_in_type = 5; } state->audio_smoothing = 0; //disable smoothing to prevent random crackling/buzzing TCP_END: ; //do nothing } //RIGCTL if (choicec == 11) { //read in tcp hostname sprintf (opts->rigctlhostname, "%s", "localhost"); opts->rigctlportno = 4532; entry_win = newwin(8, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RIGCTL Hostname:"); mvwprintw(entry_win, 3, 2, " (default is localhost)"); mvwprintw(entry_win, 4, 2, " "); mvwprintw(entry_win, 5, 3, " "); echo(); refresh(); wscanw(entry_win, "%s", opts->rigctlhostname); noecho(); //read in tcp port number entry_win = newwin(8, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RIGCTL Port Number:"); mvwprintw(entry_win, 3, 2, " (default is 4532)"); mvwprintw(entry_win, 4, 2, " "); mvwprintw(entry_win, 5, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rigctlportno); noecho(); opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno); if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1; else opts->use_rigctl = 0; } // if (choicec == 10) // { // if (opts->ncurses_compact == 0) // { // opts->ncurses_compact = 1; // } // else opts->ncurses_compact = 0; // } // if (choicec == 11) // { // if (opts->ncurses_history == 0) // { // opts->ncurses_history = 1; // } // else opts->ncurses_history = 0; // } if (choicec == 12) { //flesh out all closewavs and sprint "" wav filenames closeWavOutFile (opts, state); closeWavOutFileL (opts, state); closeWavOutFileR (opts, state); //closeWavOutFileRaw (opts, state); sprintf (opts->wav_out_file, "%s", ""); sprintf (opts->wav_out_fileR, "%s", ""); opts->dmr_stereo_wav = 0; } if (choicec == 13) //lucky number 13 for OP25 Symbol Capture Bin Files { //read in filename for symbol capture bin entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter OP25 Symbol Capture Bin Filename"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%s", opts->audio_in_dev); //&opts->audio_in_dev noecho(); //do the thing with the thing struct stat stat_buf; if (stat(opts->audio_in_dev, &stat_buf) != 0) { fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); goto SKIP; } if (S_ISREG(stat_buf.st_mode)) { opts->symbolfile = fopen(opts->audio_in_dev, "r"); opts->audio_in_type = 4; //symbol capture bin files } SKIP: choicec = 18; } if (choicec == 14) //replay last file { struct stat stat_buf; if (stat(opts->audio_in_dev, &stat_buf) != 0) { fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); goto SKIPR; } if (S_ISREG(stat_buf.st_mode)) { opts->symbolfile = fopen(opts->audio_in_dev, "r"); opts->audio_in_type = 4; //symbol capture bin files } SKIPR: choicec = 18; //exit } if (choicec == 15) //stop/close last file PLAYBACK { if (opts->symbolfile != NULL) { if (opts->audio_in_type == 4) //check first, or issuing a second fclose will crash the SOFTWARE { fclose(opts->symbolfile); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once } } if (opts->audio_out_type == 0) opts->audio_in_type = 0; //set after closing to prevent above crash condition else (opts->audio_in_type = 5); choicec = 18; //exit } if (choicec == 16) //stop/close last file RECORDING { if (opts->symbol_out_f) { closeSymbolOutFile (opts, state); sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file); //swap output bin filename to input for quick replay } choicec = 18; //exit } //toggle call alert beep if (choicec == 17) { if (opts->call_alert == 0) { opts->call_alert = 1; } else opts->call_alert = 0; } if (choicec != 0 && choicec != 18 ) //return to last menu { //return choice = 0; choicec = 0; keypad(test_win, FALSE); keypad(menu_win, TRUE); delwin(test_win); print_menu(menu_win, highlight); //wrefresh(menu_win); break; } if (choicec == 18) //exit both menus { //exit choice = 1; choicec = 0; keypad(test_win, FALSE); keypad(menu_win, TRUE); delwin(test_win); print_menu(menu_win, highlight); break; } } clrtoeol(); //clear to end of line? refresh(); } //Privacy Key Entry if (choice == 14) { state->payload_keyid = 0; state->payload_keyidR = 0; short int option = 0; entry_win = newwin(14, WIDTH+6, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, "Key Type Selection"); mvwprintw(entry_win, 3, 2, " "); mvwprintw(entry_win, 4, 2, "1 - Basic Privacy "); mvwprintw(entry_win, 5, 2, "2 - **tera Privacy "); mvwprintw(entry_win, 6, 2, "3 - NXDN/dPMR Scrambler "); mvwprintw(entry_win, 7, 2, "4 - Force BP/Scr Key Priority "); mvwprintw(entry_win, 8, 3, "-------------------------------- "); mvwprintw(entry_win, 9, 2, "5 - RC4 Key "); mvwprintw(entry_win, 10, 2, "6 - Force DMR RC4 Priority/LE "); mvwprintw(entry_win, 11, 3, " "); echo(); refresh(); wscanw(entry_win, "%hd", &option); //%d noecho(); opts->dmr_mute_encL = 0; opts->dmr_mute_encR = 0; if (option == 1) { state->K = 0; entry_win = newwin(6, WIDTH+6, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, "Basic Privacy Key Number (DEC):"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%lld", &state->K); noecho(); if (state->K > 255) state->K = 255; state->keyloader = 0; //turn off keyloader } if (option == 2) { state->K1 = 0; state->K2 = 0; state->K3 = 0; state->K4 = 0; state->H = 0; entry_win = newwin(7, WIDTH+8, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value (HEX) "); mvwprintw(entry_win, 3, 2, " 10 Char or First 16 for 32/64"); mvwprintw(entry_win, 4, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->H); noecho(); state->K1 = state->H; entry_win = newwin(7, WIDTH+8, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 2 (HEX) "); mvwprintw(entry_win, 3, 2, " Second 16 Chars or Zero"); mvwprintw(entry_win, 4, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->K2); noecho(); entry_win = newwin(7, WIDTH+8, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 3 (HEX) "); mvwprintw(entry_win, 3, 2, " Third 16 Chars or Zero"); mvwprintw(entry_win, 4, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->K3); noecho(); entry_win = newwin(7, WIDTH+8, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 4 (HEX) "); mvwprintw(entry_win, 3, 2, " Fourth 16 Chars or Zero"); mvwprintw(entry_win, 4, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->K4); noecho(); state->keyloader = 0; //turn off keyloader } if (option == 3) { state->R = 0; entry_win = newwin(6, WIDTH+6, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, "NXDN/dPMR Scrambler Key Value (DEC):"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%lld", &state->R); noecho(); if (state->R > 0x7FFF) state->R = 0x7FFF; state->keyloader = 0; //turn off keyloader } //toggle enforcement of basic privacy key over enc bit set on traffic if (option == 4) { if (state->M == 1 || state->M == 0x21) { state->M = 0; } else state->M = 1; } if (option == 5) { state->R = 0; entry_win = newwin(6, WIDTH+6, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, "RC4 Key Value (HEX):"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->R); noecho(); if (state->R > 0xFFFFFFFFFF) { state->R = 0xFFFFFFFFFF; } state->RR = state->R; //assign for both slots state->keyloader = 0; //turn off keyloader } //toggle enforcement of rc4 key over missing pi header/le on DMR if (option == 6) { if (state->M == 1 || state->M == 0x21) { state->M = 0; } else state->M = 0x21; } if (state->K == 0 && state->K1 == 0 && state->K2 == 0 && state->K3 == 0 && state->K4 == 0) { opts->dmr_mute_encL = 1; opts->dmr_mute_encR = 1; } break; } if (choice == 99) //UNUSED { //setup Auto parameters--default ones // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (opts->output_name, "Legacy Auto"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 1; opts->frame_x2tdma = 1; opts->frame_p25p1 = 1; opts->frame_p25p2 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 1; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 1; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; opts->unmute_encrypted_p25 = 0; break; } if (choice == 6) { //ProVoice Specifics // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 5; state->symbolCenter = 2; sprintf (opts->output_name, "EDACS/PV"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_p25p2 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 1; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 0; opts->mod_qpsk = 0; opts->mod_gfsk = 1; state->rf_mod = 2; break; } if (choice == 4) { //DSTAR // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (opts->output_name, "DSTAR"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 1; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_p25p2 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; // state->rf_mod = 2; opts->unmute_encrypted_p25 = 0; break; } if (choice == 3) //was 5, changed to 3 and also made it the TDMA class { //TDMA -- was P25p1 only // resetState (state); //use sparingly, may cause memory leak opts->use_heuristics = 1; if (opts->use_heuristics == 1) { initialize_p25_heuristics(&state->p25_heuristics); initialize_p25_heuristics(&state->inv_p25_heuristics); } opts->frame_p25p1 = 1; opts->frame_p25p2 = 1; opts->frame_dmr = 1; state->samplesPerSymbol = 10; state->symbolCenter = 4; state->rf_mod = 0; sprintf (opts->output_name, "TDMA"); opts->dmr_mono = 0; opts->dmr_stereo = 1; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 2; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; opts->unmute_encrypted_p25 = 0; break; } if (choice == 2) { //AUTO Stereo P25 1, 2, and DMR // resetState (state); //use sparingly, seems to cause issue when switching back to other formats if (opts->use_heuristics == 1) { initialize_p25_heuristics(&state->p25_heuristics); initialize_p25_heuristics(&state->inv_p25_heuristics); } opts->use_heuristics = 0; opts->frame_dmr = 1; state->samplesPerSymbol = 10; state->symbolCenter = 4; state->rf_mod = 0; sprintf (opts->output_name, "AUTO"); opts->dmr_mono = 0; opts->dmr_stereo = 1; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 2; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 1; opts->frame_p25p2 = 1; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 1; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; break; } if (choice == 7) { // resetState (state); //use sparingly, seems to cause issue when switching back to other formats state->samplesPerSymbol = 8; state->symbolCenter = 3; sprintf (opts->output_name, "P25p2"); opts->dmr_mono = 0; opts->dmr_stereo = 1; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 2; opts->frame_dmr = 0; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_p25p2 = 1; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; break; } if (choice == 8) { //dPMR // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 20; state->symbolCenter = 10; sprintf (opts->output_name, "dPMR"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 1; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; //opts->unmute_encrypted_p25 = 0; break; } if (choice == 9) { //NXDN48 // resetState (state); //use sparingly, may cause memory leak opts->frame_nxdn48 = 1; state->samplesPerSymbol = 20; state->symbolCenter = 10; state->rf_mod = 0; sprintf (opts->output_name, "NXDN48"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 1; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; //opts->unmute_encrypted_p25 = 0; // opts->mod_qpsk = 0; // opts->mod_gfsk = 0; // state->rf_mod = 0; } if (choice == 10) { //NXDN96 // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (opts->output_name, "NXDN96"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 1; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; //opts->unmute_encrypted_p25 = 0; } if (choice == 11) { //Decode DMR Stereo (was X2-TDMA) // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; // sprintf (opts->output_name, "X2-TDMA"); sprintf (opts->output_name, "DMR"); opts->dmr_mono = 0; opts->dmr_stereo = 1; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 2; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 1; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; //opts->unmute_encrypted_p25 = 0; } if (choice == 12) { //Decode YSF Fusion // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (opts->output_name, "YSF"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 1; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; } if (choice == 5) //was 3 { //Decode M17 // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (opts->output_name, "M17"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 1; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; } if (choice == 13) { //Set all signal for inversion or uninversion if (opts->inverted_dmr == 0) { opts->inverted_dmr = 1; opts->inverted_dpmr = 1; opts->inverted_x2tdma = 1; opts->inverted_ysf = 1; opts->inverted_m17 = 1; } else { opts->inverted_dmr = 0; opts->inverted_dpmr = 0; opts->inverted_x2tdma = 0; opts->inverted_ysf = 0; opts->inverted_m17 = 0; } } if (choice == 15) //reset call history (usually if janky output when switching modes) { for (short int k = 0; k <= 9; k++) { call_matrix[k][0] = 0; call_matrix[k][1] = 0; call_matrix[k][2] = 0; call_matrix[k][3] = 0; call_matrix[k][4] = 0; call_matrix[k][5] = 0; } src = 0; rn = 0; tgn = 0; dcc = -1; tg = 0; tgR = 0; rd = 0; rdR = 0; state->lastsrc = 0; state->lastsrcR = 0; state->lasttg = 0; state->lasttgR = 0; } if (choice == 16) //toggle payload printing { if (opts->payload == 0) { opts->payload = 1; fprintf(stderr, "Payload on\n"); } else { opts->payload = 0; fprintf(stderr, "Payload Off\n"); } } if (choice == 17) { //hardset P2 WACN, SYSID, and NAC entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Phase 2 WACN (HEX)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->p2_wacn); //%X if (state->p2_wacn > 0xFFFFF) { state->p2_wacn = 0xFFFFF; } noecho(); entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Phase 2 SYSID (HEX)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->p2_sysid); //%X if (state->p2_sysid > 0xFFF) { state->p2_sysid = 0xFFF; } noecho(); entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Phase 2 NAC/CC (HEX)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->p2_cc); //%X if (state->p2_cc > 0xFFF) { state->p2_cc = 0xFFF; } noecho(); //need handling to truncate larger than expected values //set our hardset flag to 1 if values inserted, else set to 0 so we can attempt to get them from TSBK/LCCH if (state->p2_wacn != 0 && state->p2_sysid != 0 && state->p2_cc != 0) { state->p2_hardset = 1; } else state->p2_hardset = 0; } if (choice == 19) { short int lrrpchoice = 0; entry_win = newwin(10, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enable or Disable LRRP Data File"); mvwprintw(entry_win, 3, 2, " 1 - ~/lrrp.txt (QGis)"); mvwprintw(entry_win, 4, 2, " 2 - ./DSDPlus.LRRP (LRRP.exe)"); mvwprintw(entry_win, 5, 2, " 3 - ./Custom Filename"); mvwprintw(entry_win, 6, 2, " 4 - Cancel/Stop"); mvwprintw(entry_win, 7, 2, " "); mvwprintw(entry_win, 8, 2, " "); echo(); refresh(); wscanw(entry_win, "%hd", &lrrpchoice); //%d noecho(); if (lrrpchoice == 1) { //find user home directory and append directory and filename. char * filename = "/lrrp.txt"; char * home_dir = getenv("HOME"); char * filepath = malloc(strlen(home_dir) + strlen(filename) + 1); strncpy (filepath, home_dir, strlen(home_dir) + 1); strncat (filepath, filename, strlen(filename) + 1); //assign home directory/filename to lrrp_out_file sprintf (opts->lrrp_out_file, "%s", filepath); //double check make sure this still works opts->lrrp_file_output = 1; } else if (lrrpchoice == 2) { sprintf (opts->lrrp_out_file, "DSDPlus.LRRP"); opts->lrrp_file_output = 1; } else if (lrrpchoice == 3) { //read in filename for symbol capture bin opts->lrrp_out_file[0] = 0; entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter LRRP Data Filename"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%s", opts->lrrp_out_file); //&opts->lrrp_out_file noecho(); if (opts->lrrp_out_file[0] != 0) //NULL { opts->lrrp_file_output = 1; } else { opts->lrrp_file_output = 0; sprintf (opts->lrrp_out_file, "%s", ""); opts->lrrp_out_file[0] = 0; } } else { opts->lrrp_file_output = 0; sprintf (opts->lrrp_out_file, "%s", ""); opts->lrrp_out_file[0] = 0; } } if (choice == 20) { exitflag = 1; break; } if(choice != 0 && choice != 20) /* User did a choice come out of the infinite loop */ break; } clrtoeol(); //clear to end of line? refresh(); state->menuopen = 0; //flag the menu is closed, resume processing getFrameSync //reopen pulse output with new parameters, if not null output type if (opts->audio_out == 1 && opts->audio_out_type == 0) { openPulseOutput (opts); } if (opts->audio_out_type == 2 || opts->audio_out_type == 5) { openOSSOutput (opts); } if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method { openPulseInput(opts); } //fix location of this statement to inside the if statement and add conditions if (opts->audio_in_type == 3) //open rtl input if it is the specified input method { ncursesPrinter (opts, state); //run one rep to clear menu boxes out #ifdef USE_RTLSDR if (opts->rtl_started == 0) { opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again open_rtlsdr_stream(opts); } rtl_clean_queue(); reset_dibit_buffer(state); //test and observe for any random issues, disable if needed #elif AERO_BUILD opts->audio_out_type = 5; //hopefully the audio stream is still/already open //shouldn't this be 5? Was set to 3 #else opts->audio_out_type = 0; //need to see if we need to open pulseoutput as well here? openPulseOutput (opts); #endif } if (opts->audio_in_type == 8) //re-open TCP input 'file' { opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0); } if (opts->audio_in_type == 5) //re-open UDP input 'file' { // opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0); } //update sync time on cc sync so we don't immediately go CC hunting when exiting the menu state->last_cc_sync_time = time(NULL); } //end Ncurses Menu void ncursesPrinter (dsd_opts * opts, dsd_state * state) { uint8_t idas = 0; int level = 0; int c = 0; if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN - { timeout(0); // c = getch(); // } //use rtl_dev_tune #ifdef USE_RTLSDR if (temp_freq == opts->rtlsdr_center_freq) { rtl_dev_tune (opts, temp_freq); temp_freq = -1; } #endif //Variable reset/set section //set lls sync types if (state->synctype >= 0 && state->synctype < 39) { lls = state->synctype; } //NXDN -- I really need to fix this better, but this is good enough for today if (state->nxdn_last_rid != 0 && state->nxdn_last_rid != src) { src = state->nxdn_last_rid; } if (state->nxdn_last_ran != -1 ) { rn = state->nxdn_last_ran; } if (state->nxdn_last_tg != 0 && state->nxdn_last_tg != tgn) { tgn = state->nxdn_last_tg; } //DMR CC if (state->color_code_ok && state->dmr_color_code != -1 && (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32 || lls == 33) ) { dcc = state->dmr_color_code; } //DMR SRC if ( (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32) ) //if ( (lls == 12 || lls == 11 || lls == 32) ) { //if (state->dmrburstL == 16 && state->lastsrc > 0) //state->currentslot == 0 && if (state->lastsrc > 0) { rd = state->lastsrc; } //if (state->dmrburstR == 16 && state->lastsrcR > 0) //state->currentslot == 1 && if (state->lastsrcR > 0) { rdR = state->lastsrcR; } } //DMR TG if ( (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32) ) //if ( (lls == 12 || lls == 11 || lls == 32) ) { //if (state->dmrburstL == 16 && state->lasttg > 0) //state->currentslot == 0 && if (state->lasttg > 0) { tg = state->lasttg; } //if (state->dmrburstR == 16 && state->lasttgR > 0) //state->currentslot == 1 && if (state->lasttgR > 0) { tgR = state->lasttgR; } } //P25 P1 and VCH0 if (state->p2_cc > 0) { nc = state->p2_cc; } if ( state->lasttg > 0 && (lls == 0 || lls == 1 || lls == 35 || lls == 36) ) { tg = state->lasttg; } if ( state->lastsrc > 0 && (lls == 0 || lls == 1 || lls == 35 || lls == 36) ) { rd = state->lastsrc; } //P25 P2 VCH2 if (state->lasttgR > 0 && (lls == 35 || lls == 36) ) { tgR = state->lasttgR; } if (state->lastsrcR > 0 && (lls == 35 || lls == 36) ) { rdR = state->lastsrcR; } //P25 P2 NAC to dcc for matrix shim if (state->p2_cc > 0 && (lls == 35 || lls == 36) ) { dcc = state->p2_cc; } //Call History Matrix Shuffling //Edacs - ProVoice if ( (lls == 14 || lls == 15 || lls == 37 || lls == 38) && state->carrier == 1) { if (state->edacs_vc_lcn != -1) { call_matrix[state->edacs_vc_lcn][0] = lls; call_matrix[state->edacs_vc_lcn][1] = state->edacs_vc_lcn; call_matrix[state->edacs_vc_lcn][2] = state->lasttg; call_matrix[state->edacs_vc_lcn][3] = state->lastsrc; call_matrix[state->edacs_vc_lcn][4] = 1; call_matrix[state->edacs_vc_lcn][5] = time(NULL); } } //DSTAR // if ( (lls == 6 || lls == 7 || lls == 18 || lls == 19) && (time(NULL) - call_matrix[9][5] > 5) && state->carrier == 1) // { // for (short int k = 0; k < 9; k++) // { // call_matrix[k][0] = call_matrix[k+1][0]; // call_matrix[k][1] = call_matrix[k+1][1]; // call_matrix[k][2] = call_matrix[k+1][2]; // call_matrix[k][3] = call_matrix[k+1][3]; // call_matrix[k][4] = call_matrix[k+1][4]; // call_matrix[k][5] = call_matrix[k+1][5]; // } // call_matrix[9][0] = lls; // call_matrix[9][1] = 1; // call_matrix[9][2] = 1; // call_matrix[9][3] = 1; // call_matrix[9][4] = 1; // call_matrix[9][5] = time(NULL); // } //NXDN -- I really need to fix this better, but this is good enough for today if ( call_matrix[9][2] != src && src != 0 && rn != -1 ) { for (short int k = 0; k < 9; k++) { call_matrix[k][0] = call_matrix[k+1][0]; call_matrix[k][1] = call_matrix[k+1][1]; call_matrix[k][2] = call_matrix[k+1][2]; call_matrix[k][3] = call_matrix[k+1][3]; call_matrix[k][4] = call_matrix[k+1][4]; call_matrix[k][5] = call_matrix[k+1][5]; } call_matrix[9][0] = lls; call_matrix[9][1] = rn; call_matrix[9][2] = src; call_matrix[9][3] = 0; call_matrix[9][4] = tgn; call_matrix[9][5] = time(NULL); //open wav file if enabled and both rd and tg are not 0 if (opts->dmr_stereo_wav == 1 && src != 0 ) //&& tgn != 0, some TG can be 0 on NXDN { //close old first, assign name based on time and radio, open wav file closeWavOutFileL (opts, state); sprintf (opts->wav_out_file, "./%s/%s %s NXDN - RAN %d - TGT %d - SRC %d.wav", opts->wav_out_dir, getDateN(), getTimeN(), rn, tgn, src); openWavOutFileL (opts, state); //testing for now, will want to move to per call later } if (opts->call_alert == 1) { beeper (opts, state, 0); } } //DMR MS if ( call_matrix[9][2] != rd && lls == 32) { for (short int k = 0; k < 10; k++) { call_matrix[k][0] = call_matrix[k+1][0]; call_matrix[k][1] = call_matrix[k+1][1]; call_matrix[k][2] = call_matrix[k+1][2]; call_matrix[k][3] = call_matrix[k+1][3]; call_matrix[k][4] = call_matrix[k+1][4]; call_matrix[k][5] = call_matrix[k+1][5]; } call_matrix[9][0] = lls; call_matrix[9][1] = tg; call_matrix[9][2] = rd; call_matrix[9][3] = 1; //hard set slot number call_matrix[9][4] = dcc; call_matrix[9][5] = time(NULL); //open wav file if enabled and both rd and tg are not 0 if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0) { //close old first, assign name based on time and radio, open wav file closeWavOutFileL (opts, state); sprintf (opts->wav_out_file, "./%s/%s %s MS - CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), getTimeN(), dcc, tg, rd); openWavOutFileL (opts, state); //testing for now, will want to move to per call later } if (opts->call_alert == 1 && rd != 0 && tg != 0) { //fprintf (stderr, "BEEP 0 MS LEFT\n"); beeper (opts, state, 0); state->dmr_end_alert[0] = 0; //new voice frame, okay to beep at the end of it } memset(state->dmr_alias_block_segment[0], 0, sizeof(state->dmr_alias_block_segment[0])); sprintf (state->dmr_embedded_gps[0], "%s", ""); } //DMR BS Slot 1 - matrix 0-4 if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) ) { for (short int k = 0; k < 4; k++) { call_matrix[k][0] = call_matrix[k+1][0]; call_matrix[k][1] = call_matrix[k+1][1]; call_matrix[k][2] = call_matrix[k+1][2]; call_matrix[k][3] = call_matrix[k+1][3]; call_matrix[k][4] = call_matrix[k+1][4]; call_matrix[k][5] = call_matrix[k+1][5]; } call_matrix[4][0] = lls; call_matrix[4][1] = tg; call_matrix[4][2] = rd; call_matrix[4][3] = 1; //hard set slot number call_matrix[4][4] = dcc; call_matrix[4][5] = time(NULL); //open wav file if enabled and both rd and tg are not 0 if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0) { //close old first, assign name based on time and radio, open wav file closeWavOutFileL (opts, state); sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), getTimeN(), dcc, tg, rd); openWavOutFileL (opts, state); //testing for now, will want to move to per call later } if (opts->call_alert == 1 && rd != 0 && tg != 0) { //fprintf (stderr, "BEEP 0 BS LEFT\n"); beeper (opts, state, 0); state->dmr_end_alert[0] = 0; //new voice frame, okay to beep at the end of it } memset(state->dmr_alias_block_segment[0], 0, sizeof(state->dmr_alias_block_segment[0])); sprintf (state->dmr_embedded_gps[0], "%s", ""); } //DMR BS Slot 2 - matrix 5-9 if ( call_matrix[9][2] != rdR && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) ) { for (short int k = 5; k < 9; k++) { call_matrix[k][0] = call_matrix[k+1][0]; call_matrix[k][1] = call_matrix[k+1][1]; call_matrix[k][2] = call_matrix[k+1][2]; call_matrix[k][3] = call_matrix[k+1][3]; call_matrix[k][4] = call_matrix[k+1][4]; call_matrix[k][5] = call_matrix[k+1][5]; } call_matrix[9][0] = lls; call_matrix[9][1] = tgR; call_matrix[9][2] = rdR; call_matrix[9][3] = 2; //hard set slot number call_matrix[9][4] = dcc; call_matrix[9][5] = time(NULL); //open wav file if enabled and both rdR and tgR are not 0 if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0) { //close old first, assign name based on time and radio, open wav file closeWavOutFileR (opts, state); sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), getTimeN(), dcc, tgR, rdR); openWavOutFileR (opts, state); //testing for now, will want to move to per call later } if (opts->call_alert == 1 && rdR != 0 && tgR != 0) { //fprintf (stderr, "BEEP 1 BS RIGHT\n"); beeper (opts, state, 1); state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it } memset(state->dmr_alias_block_segment[1], 0, sizeof(state->dmr_alias_block_segment[1])); sprintf (state->dmr_embedded_gps[1], "%s", ""); } //P25 P1 if ( (lls == 0 || lls == 1) && call_matrix[9][2] != rd && nc > 0 && tg > 0 && state->dmrburstL == 26) { for (short int k = 0; k < 9; k++) { call_matrix[k][0] = call_matrix[k+1][0]; call_matrix[k][1] = call_matrix[k+1][1]; call_matrix[k][2] = call_matrix[k+1][2]; call_matrix[k][3] = call_matrix[k+1][3]; call_matrix[k][4] = call_matrix[k+1][4]; call_matrix[k][5] = call_matrix[k+1][5]; } call_matrix[9][0] = lls; call_matrix[9][1] = tg; call_matrix[9][2] = rd; call_matrix[9][3] = 0; call_matrix[9][4] = nc; call_matrix[9][5] = time(NULL); //open wav file if enabled and both rd and tg are not 0 if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0) { //close old first, assign name based on time and radio, open wav file closeWavOutFileL (opts, state); sprintf (opts->wav_out_file, "./%s/%s %s P1 - NAC %X - TGT %d - SRC %d.wav", opts->wav_out_dir, getDateN(), getTimeN(), nc, tg, rd); openWavOutFileL (opts, state); //testing for now, will want to move to per call later } if (opts->call_alert == 1) { beeper (opts, state, 0); } } //Remus DMR End Call Alert Beep // if (opts->call_alert == 1) // { // if (state->dmrburstL == 2 && state->dmr_end_alert[0] == 0) //if TLC and flag not tripped // { // beeper (opts, state, 0); // state->dmr_end_alert[0] = 1; //don't play again until new voice frames // state->lasttg = 0; // state->lastsrc = 0; // rd = 0; // tg = 0; // } // if (state->dmrburstR == 2 && state->dmr_end_alert[1] == 0) //if TLC and flag not tripped // { // beeper (opts, state, 1); // state->dmr_end_alert[1] = 1; //don't play again until new voice frames // state->lasttgR = 0; // state->lastsrcR = 0; // rdR = 0; // tgR = 0; // } // } //Start Printing Section erase(); #ifdef AERO_BUILD if (opts->ncurses_compact == 1) { printw ("------------------------------------------------------------------------------\n"); printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20230729)"); printw ("------------------------------------------------------------------------------\n"); } #elif LIMAZULUTWEAKS if (opts->ncurses_compact == 1) { printw ("------------------------------------------------------------------------------\n"); printw ("| Digital Speech Decoder: LimaZulu Edition VI: Return of the Zulu \n"); printw ("------------------------------------------------------------------------------\n"); } #elif ZDEV_BUILD if (opts->ncurses_compact == 1) { printw ("------------------------------------------------------------------------------\n"); printw ("| Digital Speech Decoder: Florida Man Edition - zDEV %s \n", GIT_TAG); printw ("------------------------------------------------------------------------------\n"); } #else if (opts->ncurses_compact == 1) { printw ("------------------------------------------------------------------------------\n"); printw ("| Digital Speech Decoder: Florida Man Edition - AW (WIP) %s \n", GIT_TAG); printw ("------------------------------------------------------------------------------\n"); } #endif if (opts->ncurses_compact == 0) { attron(COLOR_PAIR(6)); for (short int i = 0; i < 7; i++) { printw("%s", FM_bannerN[i]); if (i == 1) printw (" ESC to Menu"); if (i == 2) printw (" 'q' to Quit "); if (i == 4) printw (" MBElib %s", versionstr); #ifdef AERO_BUILD if (i == 5) printw (" %s ", "Aero Build"); if (i == 6) printw (" AW (WIP) \n"); #elif ZDEV_BUILD if (i == 5) printw (" %s ", "AW (WIP)"); if (i == 6) printw (" %s \n", GIT_TAG); #else if (i == 5) printw (" %s ", "AW (WIP)"); if (i == 6) printw (" %s \n", GIT_TAG); #endif else printw ("\n"); } attroff(COLOR_PAIR(6)); //6 attron(COLOR_PAIR(4)); } //fix color/pair issue when compact and trunking enabled if (opts->ncurses_compact == 1 && opts->p25_trunk == 1) attron(COLOR_PAIR(4)); printw ("--Input Output----------------------------------------------------------------\n"); if (opts->audio_in_type == 0) { printw ("| Pulse Audio Input: %i kHz; %i Channel;\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); } if (opts->audio_in_type == 5) { printw ("| OSS Audio Input: %i kHz; 1 Channel;\n", SAMPLE_RATE_IN/1000); } if (opts->audio_in_type == 4) { printw ("| Symbol Bin Input: %s \n", opts->audio_in_dev); } if (opts->audio_in_type == 8) { printw ("| Direct TCP Input: Port: %d; Sample Rate: %d; \n", opts->tcp_portno, opts->wav_sample_rate); } if (opts->audio_in_type == 2) { printw ("| Direct WAV File Input: %s; Sample Rate: %d; \n", opts->audio_in_dev, opts->wav_sample_rate); } if (opts->audio_in_type == 1) { printw ("| STDIN Standard Input: - Menu Disabled when using STDIN!\n"); // printw ("| NCURSES Menu Disabled when using STDIN! - Use CTRL + C to Close. \n"); } if (opts->audio_in_type == 3) { printw ("| RTL: %d;", opts->rtl_dev_index); if (opts->rtl_gain_value == 0) printw (" Gain: AGC;"); else printw (" Gain: %idB;", opts->rtl_gain_value); printw (" PPM: %i;", opts->rtlsdr_ppm_error); printw (" SQ: %i;", opts->rtl_squelch_level); printw (" RMS: %04li;", opts->rtl_rms); printw (" BW: %i kHz;", opts->rtl_bandwidth); printw (" FRQ: %i;", opts->rtlsdr_center_freq); if (opts->rtl_udp_port != 0) printw ("\n| External RTL Tuning on UDP Port: %i", opts->rtl_udp_port); printw ("\n"); } if (opts->audio_out_type == 0) { printw ("| Pulse 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->floating_point == 1) printw (" FBG: %02.0f%%;", opts->audio_gain*2); if (opts->audio_gain == 0) printw (" (+/-) Auto"); if (opts->audio_gain > 0) printw (" (+/-) Manual"); // if (state->audio_smoothing == 1 && opts->floating_point == 0) printw (" Smoothing On;"); //only on short printw (" \n"); } if ( opts->audio_out_type == 0 && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) ) { printw ("| Pulse Audio Output: %i kHz; %i Ch; RMS: %04ld Analog", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->rtl_rms); 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 (state->audio_smoothing == 1 && opts->floating_point == 0) printw (" Smoothing On;"); //only on short if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) || opts->frame_provoice == 1) printw (" - Analog RMS: %04ld ", opts->rtl_rms); printw (" \n"); } if (opts->monitor_input_audio == 1) { printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected (WIP)\n"); } if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0) { printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir); } if (opts->wav_out_file_raw[0] != 0 && opts->audio_in_type == 0) { printw ("| Appending Raw Sig Audio WAV to file %s\n", opts->wav_out_file_raw); } if (opts->symbol_out_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: %s\n", opts->wav_out_file); } if (opts->dmr_stereo_wav == 1) //opts->wav_out_file[0] != 0 && { printw ("| Per Call - %s\n", opts->wav_out_file); if (opts->dmr_stereo == 1) printw ("| Per Call - %s\n", opts->wav_out_fileR); } if (opts->use_rigctl == 1) { printw ("| RIGCTL Remote Control Client Established on Port [%d]\n", opts->rigctlportno); } #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 if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n"); if (state->M == 1) { if (state->R != 0) printw ("| Forcing Key Priority -- NXDN Sc Key: %05lld \n", state->R); if (state->K != 0) printw ("| Forcing Key Priority -- Moto BP Key: %03lld \n", state->K); if (state->K1 != 0) printw ("| Forcing Key Priority -- tera BP Key: %016llX \n", state->K1); if (state->K != 0 && state->K1 != 0) printw ("| Warning! Multiple DMR Key Types Loaded! \n"); //warning may not be required } if (state->M == 0x21) { if (state->R != 0) printw ("| Forcing Key Priority -- RC4 Key: %010llX \n", state->R); } if (opts->scanner_mode == 1) { printw ("| Fast Scan Mode Enabled "); 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 reset = 1; } printw ("--Audio Decode----------------------------------------------------------------\n"); printw ("| Demod/Rate: "); if (opts->mod_qpsk == 1) printw ("[QPSK]"); if (opts->mod_c4fm == 1) printw ("[C4FM]"); if (opts->mod_gfsk == 1) printw ("[GFSK]"); printw ( "[%d] \n", (48000*opts->wav_interpolator)/state->samplesPerSymbol); printw ("| Decoding: [%s] \n", opts->output_name); printw ("| In Level: [%02d%%] \n", level); if (opts->dmr_stereo == 0) { printw ("| Voice Error: [%i][%i]", state->errs, state->errs2); if (opts->slot1_on == 0) printw (" OFF"); if (opts->slot1_on == 1) printw (" ON"); printw ("\n"); } if (opts->dmr_stereo == 1) { printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2); if (opts->slot1_on == 0) printw (" OFF"); if (opts->slot1_on == 1) printw (" ON"); printw ("\n"); printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R); if (opts->slot2_on == 0) printw (" OFF"); if (opts->slot2_on == 1) printw (" ON"); 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 (" "); 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 { // for (i = 0; i < 9; i++) // printw ("%c", state->m17_dst_csd[i]); 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 { // for (i = 0; i < 9; i++) // printw ("%c", state->m17_src_csd[i]); printw("%s", state->m17_src_str); } printw ("\n"); printw ("| "); //fill in any extra info, like Meta (IV, etc) if (state->m17_enc == 2) { printw (" Scrambler - Type: %d", state->m17_enc_st); } if (state->m17_enc == 1) { printw (" AES-CTR - IV: "); //display packed meta as IV for (i = 0; i < 14; i++) printw ("%02X", state->m17_meta[i]); } if (state->m17_enc == 3) { printw (" Reserved Enc - Type: %d", state->m17_enc_st); } printw ("\n"); } //YSF if (lls == 30 || lls == 31) { // printw ("\n"); printw ("| "); printw ("Fusion - "); //insert data type and frame information if (state->ysf_dt == 0) printw("V/D1 "); if (state->ysf_dt == 1) printw("DATA "); if (state->ysf_dt == 2) printw("V/D2 "); if (state->ysf_dt == 3) printw("VWFR "); printw (" "); if (state->ysf_cm == 0) printw("Group/CQ "); if (state->ysf_cm == 3) printw("Private "); if (state->ysf_cm == 1) printw("Radio ID "); if (state->ysf_cm == 2) printw("Reserved "); if (state->ysf_fi == 0) printw("HC "); if (state->ysf_fi == 1) printw("CC "); if (state->ysf_fi == 2) printw("TC "); if (state->ysf_fi == 3) printw("XX "); printw ("\n"); printw ("| "); //NOTE: In Radio ID Mode, the DST will be split on Destination and Source Radio ID values printw ("DST: %s ", state->ysf_tgt); printw ("SRC: %s ", state->ysf_src); printw ("\n"); printw ("| "); printw ("UPL: %s ", state->ysf_upl); printw ("DNL: %s ", state->ysf_dnl); printw ("\n"); printw ("| "); printw ("RM1: %s ", state->ysf_rm1); printw ("RM2: %s ", state->ysf_rm2); printw ("\n"); printw ("| "); printw ("RM3: %s ", state->ysf_rm3); printw ("RM4: %s ", state->ysf_rm4); //these texts can get pretty long and out of sorts, and lots of 0x20 spaces //just going to leave these to only be in the console output // printw ("\n"); // printw ("| "); // printw ("TXT: "); // for (i = 4; i < 8; i++) // { // for (int j = 0; j < 20; j++) // { // //no spaces and no asterisks // if (state->ysf_txt[i][j] != 0x2A) // printw ("%c", state->ysf_txt[i][j]); // } // // printw (" "); //just a single space between each 'block' // } printw ("\n"); } //NXDN if (lls == 28 || lls == 29) { if (strcmp (state->nxdn_location_category, "Type-D") == 0) idas = 1; if (opts->p25_trunk == 1) { printw ("| "); if (opts->p25_is_tuned == 0) { if (idas == 0) printw ("Monitoring RCCH Channel"); //Control Channel if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2 Channel if (state->p25_cc_freq != 0) { printw (" - Frequency: %.06lf Mhz ", (double)state->p25_cc_freq/1000000); } } else if (opts->p25_is_tuned == 1) { if (idas == 0) printw ("Monitoring RTCH Channel"); //Traffic Channel if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2 if (state->p25_vc_freq[0] != 0) { printw (" - Frequency: %.06lf Mhz ", (double)state->p25_vc_freq[0]/1000000); } } printw ("\n"); } printw ("| "); // #ifdef LIMAZULUTWEAKS if (idas == 0) printw ("NXDN - RAN: %02d; ", state->nxdn_last_ran); if (idas == 1) printw ("IDAS - Area: %02d; ", state->nxdn_last_ran); // #else // if (idas == 0) printw ("NXDN - RAN: [%02d] ", rn); // if (idas == 1) printw ("IDAS - Area: [%02d] ", rn); // #endif if (state->nxdn_location_site_code != 0) { printw ("Cat: %s; ", state->nxdn_location_category); printw ("Sys Code: %d; ", state->nxdn_location_sys_code); printw ("Site Code: %d; ", state->nxdn_location_site_code); } //if system supports Direct Frequency Assignment if (state->nxdn_rcn == 1) printw ("DFA "); printw ("\n"); printw ("| "); printw ("TGT: [%5d] ", tgn); printw ("SRC: [%5d] ", src); if (state->nxdn_alias_block_segment[0][0] > 0) { printw ("ALIAS: ["); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { printw ("%s", state->nxdn_alias_block_segment[i][j]); } } printw ("]"); } //Group Name Labels from CSV import for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == tgn) { attron(COLOR_PAIR(4)); printw (" [%s]", state->group_array[k].groupName); printw ("[%s] ", state->group_array[k].groupMode); } else if (state->group_array[k].groupNumber == src) { attron(COLOR_PAIR(4)); printw (" [%s]", state->group_array[k].groupName); printw ("[%s] ", state->group_array[k].groupMode); } if (state->carrier == 1) { attron(COLOR_PAIR(3)); } } if (state->carrier == 1) { printw(" %s ", state->nxdn_call_type); } printw ("\n|"); if (state->nxdn_cipher_type > 0) { printw (" ALG: [0x%02X] KEY: [0x%02X] ", state->nxdn_cipher_type, state->nxdn_key); } if (state->nxdn_cipher_type == 0x1 && state->carrier == 1) { if (state->R == 0) attron(COLOR_PAIR(2)); printw ("Scrambler "); if (state->R == 0) attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); if (state->R != 0) { attron(COLOR_PAIR(1)); printw ("KEY VALUE: [%05lld] ", state->R ); printw ("SEED: [%04llX]", state->payload_miN); attron(COLOR_PAIR(3)); } } if (state->nxdn_cipher_type == 0x2 && state->carrier == 1) { attron(COLOR_PAIR(1)); printw ("IV: [%016llX] ", state->payload_miN); attron(COLOR_PAIR(2)); printw ("DES1 "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } if (state->nxdn_cipher_type == 0x3 && state->carrier == 1) { attron(COLOR_PAIR(1)); printw ("IV: [%016llX] ", state->payload_miN); attron(COLOR_PAIR(2)); printw ("AES-256 "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } if (state->nxdn_cipher_type > 0x3 && state->carrier == 1) { attron(COLOR_PAIR(2)); printw ("Unknown Encryption "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } //Active Trunking Channels (NXDN and IDAS) if (1 == 1) //opts->p25_trunk { printw ("\n"); printw ("| "); //active channel display attron(COLOR_PAIR(4)); for (int i = 0; i < 16; i++) { if (state->active_channel[i] != 0) printw ("%s", state->active_channel[i]); } if (state->carrier == 1) attron(COLOR_PAIR(3)); else attroff(COLOR_PAIR(4)); } printw("\n"); } //P25 and DMR BS/MS if ( lls == 0 || lls == 1 || lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32 || lls == 33 || lls == 34 || lls == 35 || lls == 36) { printw ("| "); if (lls > 1 && lls < 30) { printw ("DMR BS - DCC: %02i; ", dcc); // printw ("%s %s", state->dmr_branding, state->dmr_branding_sub); printw ("%s ", state->dmr_branding); printw ("%s", state->dmr_branding_sub); printw ("%s", state->dmr_site_parms); //site id, net id, etc if (state->dmr_rest_channel > 0) { printw ("Rest LSN: %02d; ", state->dmr_rest_channel); if (state->trunk_chan_map[state->dmr_rest_channel] != 0) { printw ("Freq: %.06lf Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000); } } else if (state->p25_cc_freq != 0) { printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000); } } else if (lls == 32 || lls == 33 || lls == 34) { printw ("DMR MS - DCC: %02i; ", dcc); } else if (lls == 0 || lls == 1) //P1 { printw ("P25p1 - %05llX:%03llX:%03llX; RFSS: %lld SITE: %lld ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); if (state->p25_cc_freq != 0) { printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000); } } else if (lls == 35 || lls == 36) //P2 { printw ("P25p2 - %05llX:%03llX:%03llX; RFSS: %lld SITE: %lld ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0) { attron(COLOR_PAIR(2)); printw (" Phase 2 Missing Parameters "); attron(COLOR_PAIR(3)); } else if (state->p2_wacn == 0xFFFFF || state->p2_sysid == 0xFFF || state->p2_cc == 0xFFF) { attron(COLOR_PAIR(2)); printw (" Phase 2 Invalid Parameters "); attron(COLOR_PAIR(3)); } else { if (state->p25_cc_freq != 0) { printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000); } } } printw ("\n"); //Slot 1 [0] printw ("| SLOT 1 - "); if (state->dmrburstL < 16 && state->carrier == 1 && state->lasttg > 0 && state->lastsrc > 0) { attron(COLOR_PAIR(2)); } printw ("TGT: [%8i] SRC: [%8i] ", state->lasttg, state->lastsrc); if (state->dmrburstL != 16 && state->carrier == 1 && state->lasttg > 0 && state->lastsrc > 0) { attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } printw ("%s | ", state->call_string[0]); printw ("%s ", DMRBusrtTypes[state->dmrburstL]); if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21)) printw ("*M*"); printw ("\n"); printw ("| V XTRA | "); //10 spaces if(state->dmrburstL == 16 && state->payload_algid == 0 && (state->dmr_so & 0xCF) == 0x40) //4F or CF mask? & 0xCF currently { attron(COLOR_PAIR(5)); printw (" **Pr** "); attroff(COLOR_PAIR(5)); attron(COLOR_PAIR(3)); } if(state->dmrburstL == 16 && state->payload_algid == 0 && state->K > 0 && state->dmr_fid == 0x10 && (state->dmr_so & 0xCF) == 0x40) { attron(COLOR_PAIR(1)); printw ("Pr Key [%3lld] ", state->K); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(3)); } if(state->dmrburstL == 16 && state->payload_algid == 0 && state->H > 0 && state->dmr_fid == 0x68 && ((state->dmr_so & 0xCF) == 0x40) ) { attron(COLOR_PAIR(1)); printw ("**tera Pr Key [%010llX] ", state->H); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(3)); } //ALG, KeyID, MI //was key_id if(state->dmrburstL == 16 && state->payload_algid > 0 && (state->dmr_so & 0xCF) == 0x40) { attron(COLOR_PAIR(1)); printw ("ALG: 0x%02X KEY: 0x%02X MI: 0x%08X ", state->payload_algid, state->payload_keyid, state->payload_mi); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(3)); } //P25 FDMA/TDMA if(state->dmrburstL > 19 && state->payload_algid > 0 && state->payload_algid != 0x80) { attron(COLOR_PAIR(1)); printw ("ALG: 0x%02X KEY: 0x%04X MI: 0x%016llX ", state->payload_algid, state->payload_keyid, state->payload_miP); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(3)); } //Anytone 0x01 will never show here since its converted to 0x21 for handling if (state->payload_algid == 0xAA || state->payload_algid == 0x21 || state->payload_algid == 0x01) { attron(COLOR_PAIR(1)); printw("RC4 "); if (state->R != 0) { printw("Key: %010llX ", state->R); } attron(COLOR_PAIR(3)); } if (state->payload_algid == 0x81 || state->payload_algid == 0x22) { attron(COLOR_PAIR(1)); printw("DES1 "); attron(COLOR_PAIR(3)); } if (state->payload_algid == 0x82) { attron(COLOR_PAIR(1)); printw("DES2 "); attron(COLOR_PAIR(3)); } if (state->payload_algid == 0x83) { attron(COLOR_PAIR(1)); printw("DES3 "); attron(COLOR_PAIR(3)); } if (state->payload_algid == 0x85 || state->payload_algid == 0x24) { attron(COLOR_PAIR(1)); printw("AES-128"); attron(COLOR_PAIR(3)); } if (state->payload_algid == 0x84 || state->payload_algid == 0x25 || state->payload_algid == 0x05) { attron(COLOR_PAIR(1)); printw("AES-256"); attron(COLOR_PAIR(3)); } if (state->payload_algid == 0x02) { attron(COLOR_PAIR(1)); printw("Hytera Full Encrypt"); attron(COLOR_PAIR(3)); } //Not always correct, or correct at all, depends on context //this is already in the call_string anyways // if(state->dmrburstL == 16 && state->dmr_so == 0x40 && state->R == 0) //0100 0000 // { // attron(COLOR_PAIR(2)); // printw (" **ENC** "); // attroff(COLOR_PAIR(2)); // attron(COLOR_PAIR(3)); // } // if(state->dmrburstL == 16 && state->dmr_so == 0x80) // { // attron(COLOR_PAIR(2)); // printw (" **Emergency** "); // attroff(COLOR_PAIR(2)); // attron(COLOR_PAIR(3)); // } // if(state->dmrburstL == 16 && state->dmr_so == 0x30) //0010 0000 // { // attron(COLOR_PAIR(2)); // printw (" **Private Call** "); // attroff(COLOR_PAIR(2)); // attron(COLOR_PAIR(3)); // } printw ("\n"); //printw ("| | "); //10 spaces printw ("| D XTRA | "); attron(COLOR_PAIR(4)); if(state->dmrburstL == 16) //only during call { attron(COLOR_PAIR(4)); //Embedded GPS (not LRRP) printw ("%s ", state->dmr_embedded_gps[0]); //Embedded Talker Alias Blocks for (int i = 0; i < 4; i++) { for (int j = 0; j < 7; j++) { printw ("%s", state->dmr_alias_block_segment[0][i][j]); } } attroff(COLOR_PAIR(5)); if (state->carrier == 1) { attron(COLOR_PAIR(3)); } } //LRRP if(state->dmrburstL != 16) //only during data and no trunking { attron(COLOR_PAIR(4)); printw ("%s", state->dmr_lrrp_gps[0]); } //Group Name Labels from CSV import if (state->dmrburstL == 16 || state->dmrburstL > 19) { for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == state->lasttg) { attron(COLOR_PAIR(4)); printw (" [%s]", state->group_array[k].groupName); printw ("[%s] ", state->group_array[k].groupMode); if (state->carrier == 1) { attron(COLOR_PAIR(3)); } } } } if (state->carrier == 1) attron(COLOR_PAIR(3)); else attroff(COLOR_PAIR(4)); printw ("\n"); //Slot 2 [1] //Don't print on MS mode if (lls < 30 || lls == 35 || lls == 36) { printw ("| SLOT 2 - "); if (state->dmrburstR < 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) { attron(COLOR_PAIR(2)); } printw ("TGT: [%8i] SRC: [%8i] ", state->lasttgR, state->lastsrcR); if (state->dmrburstR != 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) { attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } printw ("%s | ", state->call_string[1]); printw ("%s ", DMRBusrtTypes[state->dmrburstR]); if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*"); printw ("\n"); printw ("| V XTRA | "); //10 spaces if(state->dmrburstR == 16 && state->payload_algidR == 0 && (state->dmr_soR & 0xCF) == 0x40) //4F or CF mask? { attron(COLOR_PAIR(5)); printw (" **Pr** "); attroff(COLOR_PAIR(5)); attron(COLOR_PAIR(3)); } if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->K > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x10) { attron(COLOR_PAIR(1)); printw ("Pr Key [%3lld] ", state->K); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(3)); } if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->H > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x68) { attron(COLOR_PAIR(1)); printw ("**tera Pr Key [%010llX] ", state->H); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(3)); } //ALG, KeyID, MI 2 //was keyidR if(state->dmrburstR == 16 && state->payload_algidR > 0 && (state->dmr_soR & 0xCF) == 0x40) { attron(COLOR_PAIR(1)); printw ("ALG: 0x%02X KEY: 0x%02X MI: 0x%08X ", state->payload_algidR, state->payload_keyidR, state->payload_miR); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(3)); } //P25-P1 and P2 if(state->dmrburstR > 19 && state->payload_algidR > 0 && state->payload_algidR != 0x80) { attron(COLOR_PAIR(1)); printw ("ALG: 0x%02X KEY: 0x%04X MI: 0x%016llX ", state->payload_algidR, state->payload_keyidR, state->payload_miN); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(3)); } //Anytone 0x01 will never show here since its converted to 0x21 for handling if (state->payload_algidR == 0xAA || state->payload_algidR == 0x21 || state->payload_algidR == 0x01) { attron(COLOR_PAIR(1)); printw("RC4 "); if (state->RR != 0) { printw("Key: %010llX ", state->RR); } attron(COLOR_PAIR(3)); } if (state->payload_algidR == 0x81 || state->payload_algidR == 0x22) { attron(COLOR_PAIR(1)); printw("DES1 "); attron(COLOR_PAIR(3)); } if (state->payload_algidR == 0x82) { attron(COLOR_PAIR(1)); printw("DES2 "); attron(COLOR_PAIR(3)); } if (state->payload_algidR == 0x83) { attron(COLOR_PAIR(1)); printw("DES3 "); attron(COLOR_PAIR(3)); } if (state->payload_algidR == 0x85 || state->payload_algidR == 0x24) { attron(COLOR_PAIR(1)); printw("AES-128"); attron(COLOR_PAIR(3)); } if (state->payload_algidR == 0x84 || state->payload_algidR == 0x25 || state->payload_algidR == 0x05) { attron(COLOR_PAIR(1)); printw("AES-256"); attron(COLOR_PAIR(3)); } if (state->payload_algidR == 0x02) { attron(COLOR_PAIR(1)); printw("Hytera Full Encrypt"); attron(COLOR_PAIR(3)); } //Not always correct, or correct at all, depends on context //this is already in the call_string anyways // if(state->dmrburstR == 16 && state->dmr_soR == 0x40 && state->R == 0) //0100 0000 // { // attron(COLOR_PAIR(2)); // printw (" **ENC** "); // attroff(COLOR_PAIR(2)); // attron(COLOR_PAIR(3)); // } // if(state->dmrburstR == 16 && state->dmr_soR == 0x80) // { // attron(COLOR_PAIR(2)); // printw (" **Emergency** "); // attroff(COLOR_PAIR(2)); // attron(COLOR_PAIR(3)); // } // if(state->dmrburstR == 16 && state->dmr_soR == 0x30) //0010 0000 // { // attron(COLOR_PAIR(2)); // printw (" **Private Call** "); // attroff(COLOR_PAIR(2)); // attron(COLOR_PAIR(3)); // } printw ("\n"); //printw ("| | "); printw ("| D XTRA | "); attron(COLOR_PAIR(4)); if(state->dmrburstR == 16) //only during call { //Embedded GPS (not LRRP) attron(COLOR_PAIR(4)); printw ("%s ", state->dmr_embedded_gps[1]); //Embedded Talker Alias Blocks for (int i = 0; i < 4; i++) { for (int j = 0; j < 7; j++) { printw ("%s", state->dmr_alias_block_segment[1][i][j]); } } attroff(COLOR_PAIR(5)); if (state->carrier == 1) { attron(COLOR_PAIR(3)); } } //LRRP if(state->dmrburstR != 16) //only during data and no trunking { attron(COLOR_PAIR(4)); printw ("%s", state->dmr_lrrp_gps[1]); } //Group Name Labels from CSV import if (state->dmrburstR == 16 || state->dmrburstR > 19) { for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == state->lasttgR) { attron(COLOR_PAIR(4)); printw (" [%s]", state->group_array[k].groupName); printw ("[%s] ", state->group_array[k].groupMode); } if (state->carrier == 1) { attron(COLOR_PAIR(3)); } } } if (state->carrier == 1) attron(COLOR_PAIR(3)); else attroff(COLOR_PAIR(4)); printw ("\n"); if (1 == 1) //opts->p25_trunk == 1 { printw ("| | "); //Active Trunking Channels //active channel display attron(COLOR_PAIR(4)); for (int i = 0; i < 31; i++) //up to 31 idas channels { if (state->active_channel[i] != 0) printw ("%s", state->active_channel[i]); } if (state->carrier == 1) attron(COLOR_PAIR(3)); else attroff(COLOR_PAIR(4)); printw ("\n"); } if (1 == 1) //opts->p25_trunk == 1 { printw ("| | "); //Currently Tuned Frequency // Tuned Frequency Display if (state->p25_vc_freq[0] != 0) { attron(COLOR_PAIR(4)); printw ("Frequency: %.06lf MHz ", (double)state->p25_vc_freq[0]/1000000); } if (state->carrier == 1) attron(COLOR_PAIR(3)); else attroff(COLOR_PAIR(4)); printw ("\n"); } } // end if not MS } //end DMR BS Types //dPMR if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27) { printw ("| DCC: [%i] ", state->dpmr_color_code); printw ("TGT: [%s] SRC: [%s] ", state->dpmr_target_id, state->dpmr_caller_id); printw ("\n| "); if (state->dPMRVoiceFS2Frame.Version[0] == 3) { attron(COLOR_PAIR(2)); printw ("Scrambler "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); if (state->R != 0) { attron(COLOR_PAIR(1)); printw ("KEY VALUE: [%05lld] ", state->R ); //printw ("SEED: [%04llX]", state->payload_miN); attron(COLOR_PAIR(3)); } } printw ("\n"); } //EDACS and ProVoice if (lls == 14 || lls == 15 || lls == 37 || lls == 38) { attroff (COLOR_PAIR(3)); //colors off for EDACS if (state->edacs_site_id != 0) { if (opts->p25_is_tuned == 0) { printw ("| Monitoring Control Channel\n"); } else { printw ("| Monitoring Voice Channel - LCN [%02d]\n", state->edacs_tuned_lcn); //since we are tuned, keep updating the time so it doesn't disappear during call call_matrix[state->edacs_tuned_lcn][5] = time(NULL); } printw ("| SITE [%03lld][%02llX]", state->edacs_site_id, state->edacs_site_id); if (state->ea_mode == 1) { printw (" Extended Addressing"); } else printw (" Standard/Networked"); if (state->esk_mask == 0xA0) { printw (" w/ ESK"); } else printw (" w/o ESK"); printw ("\n"); } for (i = 1; i <= state->edacs_lcn_count; i++) { //shim 443 afs in here for display purposes int a = (call_matrix[i][3] >> 7) & 0xF; int fs = call_matrix[i][3] & 0x7F; printw ("| - LCN [%02d][%.06lf] MHz", i, (double)state->trunk_lcn_freq[i-1]/1000000); //print Control Channel on LCN line with the current Control Channel if ( (i) == state->edacs_cc_lcn) { attron (COLOR_PAIR(1)); //yellow printw (" Control Channel"); attroff (COLOR_PAIR(1)); } //print active calls on corresponding LCN line if ((i != state->edacs_cc_lcn) && time(NULL) - call_matrix[i][5] < 2) { attron (COLOR_PAIR(3)); if (state->ea_mode == 1) printw (" TG [%5lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] ); else printw (" AFS [%3llX][%02d-%03d]", call_matrix[i][3], a, fs ); for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == call_matrix[i][2]) { printw (" [%s]", state->group_array[k].groupName); printw ("[%s]", state->group_array[k].groupMode); } } attroff (COLOR_PAIR(3)); } //print dying or dead calls in red for x seconds longer if ( (i != state->edacs_cc_lcn) && (time(NULL) - call_matrix[i][5] >= 2) && (time(NULL) - call_matrix[i][5] < 5) ) { attron (COLOR_PAIR(2)); if (state->ea_mode == 1) printw (" TG [%5lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] ); else printw (" AFS [%3llX][%02d-%03d]", call_matrix[i][3], a, fs ); for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == call_matrix[i][2]) { printw (" [%s]", state->group_array[k].groupName); printw ("[%s]", state->group_array[k].groupMode); } } attroff (COLOR_PAIR(2)); } if (i == state->edacs_tuned_lcn && opts->p25_is_tuned == 1) printw (" **T**"); //asterisk which lcn is opened printw ("\n"); } if (state->carrier == 1) { attron (COLOR_PAIR(3)); } } //fence bottom printw ("------------------------------------------------------------------------------\n"); //colors off if (state->carrier == 1){ //same as above attroff(COLOR_PAIR(3)); } //only print call history if enabled if (opts->ncurses_history == 1) { attron(COLOR_PAIR(4)); //cyan for history printw ("--Call History----------------------------------------------------------------\n"); for (short int j = 0; j < 10; j++) { //only print if a valid time was assigned to the matrix, and not EDACS/PV, and source is not zero if ( ((time(NULL) - call_matrix[9-j][5]) < 999999) && call_matrix[9-j][0] != 14 && call_matrix[9-j][0] != 15 && call_matrix[9-j][0] != 37 && call_matrix[9-j][0] != 38 && call_matrix[9-j][2] != 0) // { // printw ("| %s ", SyncTypes[call_matrix[9-j][0]]); //sync type printw ("| "); printw ("%s ", getDateC(call_matrix[9-j][5]) ); printw ("%s ", getTimeC(call_matrix[9-j][5]) ); if (lls == 28 || lls == 29) { if (idas == 0) printw ("RAN [%02lld] ", call_matrix[9-j][1]); if (idas == 1) printw ("Area [%02lld] ", call_matrix[9-j][1]); printw ("TG [%5lld] ", call_matrix[9-j][4]); printw ("RID [%5lld] ", call_matrix[9-j][2]); } //dPMR if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27) { printw ("TGT [%8lld] ", call_matrix[9-j][1]); printw ("SRC [%8lld] ", call_matrix[9-j][2]); printw ("DCC [%2lld] ", call_matrix[9-j][4]); } //P25 if (call_matrix[9-j][0] == 0 || call_matrix[9-j][0] == 1 || call_matrix[9-j][0] == 35 || call_matrix[9-j][0] == 36) { printw ("TGT [%8lld] ", call_matrix[9-j][1]); printw ("SRC [%8lld] ", call_matrix[9-j][2]); printw ("NAC [0x%03llX] ", call_matrix[9-j][4]); } //DMR BS Types if (call_matrix[9-j][0] == 12 || call_matrix[9-j][0] == 13 || call_matrix[9-j][0] == 10 || call_matrix[9-j][0] == 11 ) { // printw ("S[%lld] ", call_matrix[9-j][3]); //%d printw ("TGT [%8lld] ", call_matrix[9-j][1]); printw ("SRC [%8lld] ", call_matrix[9-j][2]); printw ("DCC [%02lld] ", call_matrix[9-j][4]); } //DMR MS Types if (call_matrix[9-j][0] == 32 || call_matrix[9-j][0] == 33 || call_matrix[9-j][0] == 34 ) { // printw ("S[%lld] ", call_matrix[9-j][3]); printw ("TGT [%8lld] ", call_matrix[9-j][1]); printw ("SRC [%8lld] ", call_matrix[9-j][2]); printw ("DCC [%02lld] ", call_matrix[9-j][4]); } // #ifdef LIMAZULUTWEAKS //Group Name Labels from CSV import for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == call_matrix[9-j][1]) { attron(COLOR_PAIR(4)); printw ("[%s]", state->group_array[k].groupName); printw ("[%s] ", state->group_array[k].groupMode); } else if (state->group_array[k].groupNumber == call_matrix[9-j][2]) { attron(COLOR_PAIR(4)); printw ("[%s]", state->group_array[k].groupName); printw ("[%s] ", state->group_array[k].groupMode); } } // #endif printw ("\n"); } //EDACS and ProVoice, outside of timestamp loop if (call_matrix[j][0] == 14 || call_matrix[j][0] == 15 || call_matrix[j][0] == 37 || call_matrix[j][0] == 38 ) { if (call_matrix[j][3] != 0) { printw ("| "); printw ("%s ", getDateC(call_matrix[j][5]) ); printw ("%s ", getTimeC(call_matrix[j][5]) ); printw ("LCN [%2lld] ", call_matrix[j][1]); printw ("Group [%8lld] ", call_matrix[j][2]); printw ("Source [%8lld] ", call_matrix[j][3]); //test for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == call_matrix[j][2]) { attron(COLOR_PAIR(4)); printw ("[%s] ", state->group_array[k].groupName); } else if (state->group_array[k].groupNumber == call_matrix[j][3]) { attron(COLOR_PAIR(4)); printw ("[%s] ", state->group_array[k].groupName); } } //end test printw ("\n"); } } } //end Call History //fence bottom printw ("------------------------------------------------------------------------------\n"); attroff(COLOR_PAIR(4)); //cyan for history } refresh(); //keyboard shortcuts - codes same as ascii codes if (c == 27) //esc key, open menu { ncursesMenu (opts, state); //just a quick test } //toggling when 48k/1 OSS still has some lag -- needed to clear out the buffer when switching if (c == 49) // '1' key, toggle slot1 on { //switching, but want to control each seperately plz if (opts->slot1_on == 1) { opts->slot1_on = 0; opts->slot_preference = 1; //slot 2 //clear any previously buffered audio state->audio_out_float_buf_p = state->audio_out_float_buf + 100; state->audio_out_buf_p = state->audio_out_buf + 100; memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); memset (state->audio_out_buf, 0, 100 * sizeof (short)); state->audio_out_idx2 = 0; state->audio_out_idx = 0; } else if (opts->slot1_on == 0) { opts->slot1_on = 1; if (opts->audio_out_type == 5) //OSS 48k/1 { opts->slot_preference = 0; //slot 1 opts->slot2_on = 0; //turn off slot 2 } } } if (c == 50) // '2' key, toggle slot2 on { //switching, but want to control each seperately plz if (opts->slot2_on == 1) { opts->slot2_on = 0; opts->slot_preference = 0; //slot 1 //clear any previously buffered audio state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100; state->audio_out_buf_pR = state->audio_out_bufR + 100; memset (state->audio_out_float_bufR, 0, 100 * sizeof (float)); memset (state->audio_out_bufR, 0, 100 * sizeof (short)); state->audio_out_idx2R = 0; state->audio_out_idxR = 0; } else if (opts->slot2_on == 0) { opts->slot2_on = 1; if (opts->audio_out_type == 5) //OSS 48k/1 { opts->slot_preference = 1; //slot 2 opts->slot1_on = 0; //turn off slot 1 } } } if (c == 43) //+ key, increment audio_gain { if (opts->audio_gain < 50) opts->audio_gain++; state->aout_gain = opts->audio_gain; state->aout_gainR = opts->audio_gain; opts->audio_gainR = opts->audio_gain; } if (c == 45) //- key, decrement audio_gain { if (opts->audio_gain > 0) opts->audio_gain--; state->aout_gain = opts->audio_gain; state->aout_gainR = opts->audio_gain; //reset to default on 0 for auto if (opts->audio_gain == 0) { state->aout_gain = 25; state->aout_gainR = 25; } opts->audio_gainR = opts->audio_gain; } if (c == 122) //'z' key, toggle payload to console { if (opts->payload == 1) opts->payload = 0; else opts->payload = 1; } if (c == 99) //'c' key, toggle compact mode { if (opts->ncurses_compact == 1) opts->ncurses_compact = 0; else opts->ncurses_compact = 1; } if (c == 116) //'t' key, toggle trunking { if (opts->p25_trunk == 1) opts->p25_trunk = 0; else opts->p25_trunk = 1; } if (c == 121) //'y' key, toggle scanner mode { if (opts->scanner_mode == 1) opts->scanner_mode = 0; else opts->scanner_mode = 1; opts->p25_trunk = 0; //turn off trunking mode } if (c == 97) //'a' key, toggle call alert beep { if (opts->call_alert == 1) opts->call_alert = 0; else opts->call_alert = 1; } if (c == 104) //'h' key, toggle history { if (opts->ncurses_history == 1) opts->ncurses_history = 0; else opts->ncurses_history = 1; } if (c == 113) //'q' key, quit { exitflag = 1; } if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr) { if (state->M == 1 || state->M == 0x21) state->M = 0; else state->M = 1; } if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry { if (state->M == 1 || state->M == 0x21) state->M = 0; else state->M = 0x21; } if (c == 105) //'i' key, toggle signal inversion on inverted types { //Set all signal for inversion or uninversion if (opts->inverted_dmr == 0) { opts->inverted_dmr = 1; opts->inverted_dpmr = 1; opts->inverted_x2tdma = 1; opts->inverted_ysf = 1; opts->inverted_m17 = 1; } else { opts->inverted_dmr = 0; opts->inverted_dpmr = 0; opts->inverted_x2tdma = 0; opts->inverted_ysf = 0; opts->inverted_m17 = 0; } } if (c == 109) //'m' key, toggle qpsk/c4fm - everything but phase 2 { if (state->rf_mod == 0) { opts->mod_c4fm = 0; opts->mod_qpsk = 1; opts->mod_gfsk = 0; state->rf_mod = 1; state->samplesPerSymbol = 10; state->symbolCenter = 4; } else { opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; state->samplesPerSymbol = 10; state->symbolCenter = 4; } } if (c == 77) //'M' key, toggle qpsk - phase 2 6000 sps { if (state->rf_mod == 0) { opts->mod_c4fm = 0; opts->mod_qpsk = 1; opts->mod_gfsk = 0; state->rf_mod = 1; state->samplesPerSymbol = 8; state->symbolCenter = 3; } else { opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; state->samplesPerSymbol = 8; state->symbolCenter = 3; } } if (c == 82) //'R', save symbol capture bin with date/time string as name { sprintf (opts->symbol_out_file, "%s %s.bin", getDateN(), getTimeN()); openSymbolOutFile (opts, state); } if (c == 114) //'r' key, stop capturing symbol capture bin file { if (opts->symbol_out_f) { closeSymbolOutFile (opts, state); sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file); } } #ifdef AERO_BUILD //do nothing #else if (c == 32) //'space bar' replay last bin file (rework to do wav files too?) { struct stat stat_buf; if (stat(opts->audio_in_dev, &stat_buf) != 0) { fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); goto SKIPR; } if (S_ISREG(stat_buf.st_mode)) { opts->symbolfile = fopen(opts->audio_in_dev, "r"); opts->audio_in_type = 4; //symbol capture bin files } SKIPR: ; //do nothing } #endif if (c == 80) //'P' key - start per call wav files { char wav_file_directory[1024]; sprintf (wav_file_directory, "./%s", opts->wav_out_dir); wav_file_directory[1023] = '\0'; if (stat(wav_file_directory, &st_wav) == -1) { fprintf (stderr, "-T %s wav file directory does not exist\n", wav_file_directory); fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory); mkdir(wav_file_directory, 0700); } opts->dmr_stereo_wav = 1; //catch all in case of no file name set, won't crash or something sprintf (opts->wav_out_file, "./%s/DSD-FME-T1.wav", opts->wav_out_dir); sprintf (opts->wav_out_fileR, "./%s/DSD-FME-T2.wav", opts->wav_out_dir); openWavOutFileL (opts, state); openWavOutFileR (opts, state); } //this one could cause issues, but seems okay if (c == 112) //'p' key - stop all per call wav files { //hope this one doesn't cause random crashing or garbage writing closeWavOutFile (opts, state); closeWavOutFileL (opts, state); closeWavOutFileR (opts, state); sprintf (opts->wav_out_file, "%s", ""); sprintf (opts->wav_out_fileR, "%s", ""); opts->dmr_stereo_wav = 0; } // #ifdef AERO_BUILD //this might be okay on Aero as well, will need to look into and/or test // #else if (c == 115) //'s' key, stop playing wav or symbol in files { if (opts->symbolfile != NULL) { if (opts->audio_in_type == 4) { fclose(opts->symbolfile); } } if (opts->audio_in_type == 2) //wav input file { sf_close(opts->audio_in_file); } if (opts->audio_out_type == 0) { opts->audio_in_type = 0; openPulseInput(opts); } else opts->audio_in_type = 5; //exitflag = 1; } #endif //makes buzzing sound when locked out in new audio config and short, probably something to do with processaudio running or not running if (state->lasttg != 0 && opts->frame_provoice != 1 && c == 33) //SHIFT+'1' key (exclamation point), lockout slot 1 or conventional tg from tuning/playback during session { state->group_array[state->group_tally].groupNumber = state->lasttg; sprintf (state->group_array[state->group_tally].groupMode, "%s", "B"); sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT"); state->group_tally++; //if we have an opened group file, let's write a group lock out into it to make it permanent if (opts->group_in_file[0] != 0) //file is available { FILE * pFile; //file pointer //open file by name that is supplied in the ncurses terminal, or cli pFile = fopen (opts->group_in_file, "a"); fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttg, state->payload_algid); fclose (pFile); } //extra safeguards due to sync issues with NXDN memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); memset (state->active_channel, 0, sizeof(state->active_channel)); //reset dmr blocks dmr_reset_blocks (opts, state); //zero out additional items state->lasttg = 0; state->lasttgR = 0; state->lastsrc = 0; state->lastsrcR = 0; state->payload_algid = 0; state->payload_algidR = 0; state->payload_keyid = 0; state->payload_keyidR = 0; state->payload_mi = 0; state->payload_miR = 0; state->payload_miP = 0; state->payload_miN = 0; opts->p25_is_tuned = 0; state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0; //tune back to the control channel //RIGCTL if (opts->p25_trunk == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, state->p25_cc_freq); //rtl #ifdef USE_RTLSDR if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq); #endif state->last_cc_sync_time = time(NULL); //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } } if (state->lasttgR != 0 && opts->frame_provoice != 1 && c == 64) //SHIFT+'2' key (@ at sign), lockout slot 2 tdma tgR from tuning/playback during session { state->group_array[state->group_tally].groupNumber = state->lasttgR; sprintf (state->group_array[state->group_tally].groupMode, "%s", "B"); sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT"); state->group_tally++; //if we have an opened group file, let's write a group lock out into it to make it permanent if (opts->group_in_file[0] != 0) //file is available { FILE * pFile; //file pointer //open file by name that is supplied in the ncurses terminal, or cli pFile = fopen (opts->group_in_file, "a"); fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttgR, state->payload_algidR); fclose (pFile); } //extra safeguards due to sync issues with NXDN memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); memset (state->active_channel, 0, sizeof(state->active_channel)); //reset dmr blocks dmr_reset_blocks (opts, state); //zero out additional items state->lasttg = 0; state->lasttgR = 0; state->lastsrc = 0; state->lastsrcR = 0; state->payload_algid = 0; state->payload_algidR = 0; state->payload_keyid = 0; state->payload_keyidR = 0; state->payload_mi = 0; state->payload_miR = 0; state->payload_miP = 0; state->payload_miN = 0; opts->p25_is_tuned = 0; state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0; //tune back to the control channel //RIGCTL if (opts->p25_trunk == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, state->p25_cc_freq); //rtl #ifdef USE_RTLSDR if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq); #endif state->last_cc_sync_time = time(NULL); //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } } // if (c == 48) //'0' key, toggle upsampled audio smoothing // { // if (state->audio_smoothing == 1) state->audio_smoothing = 0; // else state->audio_smoothing = 1; // } if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode { if (opts->trunk_use_allow_list == 1) opts->trunk_use_allow_list = 0; else opts->trunk_use_allow_list = 1; } if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls { if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0; else opts->trunk_tune_private_calls = 1; } if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls { if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0; else opts->trunk_tune_data_calls = 1; } if (opts->p25_trunk == 1 && c == 101) //'e' key, toggle tune enc calls (P25 only on certain grants) { if (opts->trunk_tune_enc_calls == 1) opts->trunk_tune_enc_calls = 0; else opts->trunk_tune_enc_calls = 1; } if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls { if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0; else opts->trunk_tune_group_calls = 1; } if (c == 70) //'F' key - toggle agressive sync/crc failure/ras { if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1; else opts->aggressive_framesync = 0; } if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc. { //dmr trunking/ncurses stuff state->dmr_rest_channel = -1; //init on -1 state->dmr_mfid = -1; // //dmr mfid branding and site parms sprintf(state->dmr_branding_sub, "%s", ""); sprintf(state->dmr_branding, "%s", ""); sprintf (state->dmr_site_parms, "%s", ""); //DMR Location Area - DMRLA B***S*** opts->dmr_dmrla_is_set = 0; opts->dmr_dmrla_n = 0; //reset NXDN info state->nxdn_location_site_code = 0; state->nxdn_location_sys_code = 0; sprintf (state->nxdn_location_category, "%s", " "); state->nxdn_last_ran = -1; //0 state->nxdn_ran = 0; //0 state->nxdn_rcn = 0; state->nxdn_base_freq = 0; state->nxdn_step = 0; state->nxdn_bw = 0; } //Debug/Troubleshooting Option if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z) { // opts->p25_is_tuned = 0; state->last_cc_sync_time = 0; state->last_vc_sync_time = 0; noCarrier(opts, state); } //attempt retry to TCP Audio server if (c == 56) // '8' key, try audio in type 8 (TCP Audio Server connection) using defaults OR whatever the user last specified { opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno); if (opts->tcp_sockfd != 0) { //reset audio input stream opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); opts->audio_in_file_info->samplerate=opts->wav_sample_rate; opts->audio_in_file_info->channels=1; opts->audio_in_file_info->seekable=0; opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE; opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0); if(opts->tcp_file_in == NULL) { fprintf(stderr, "Error, couldn't Connect to TCP with libsndfile: %s\n", sf_strerror(NULL)); } else { //close pulse input if it is currently open if (opts->audio_in_type == 0) closePulseInput(opts); fprintf (stderr, "TCP Socket Connected Successfully.\n"); opts->audio_in_type = 8; } } else fprintf (stderr, "TCP Socket Connection Error.\n"); } if (c == 57) //'9' key, try rigctl connection with default values { //use same or last specified host for TCP audio sink for connection memcpy (opts->rigctlhostname, opts->tcp_hostname, sizeof (opts->rigctlhostname) ); opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno); if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1; else opts->use_rigctl = 0; } //anything with an entry box will need the inputs and outputs stopped first //so probably just write a function to handle c input, and when c = certain values //needing an entry box, then stop all of those } //end ncursesPrinter void ncursesClose () { endwin(); }