/*------------------------------------------------------------------------------- * dsd_ncurses.c * DSD-FME ncurses terminal printer with menu system * * ASCII art generated by: * https://fsymbols.com/generators/carty/ * * LWVMOBILE * 2022-08 DSD-FME Florida Man Edition * * ilyacodes * 2024-03 EDACS-FME display improvements *-----------------------------------------------------------------------------*/ #include "dsd.h" #include "git_ver.h" #ifdef USE_RTLSDR #include //use to list out all detected RTL dongles char vendor[256], product[256], serial[256], userdev[256]; int device_count = 0; #endif uint32_t temp_freq = -1; //struct for checking existence of directory to write to struct stat st_wav = {0}; static char alias_ch[10][50]; int reset = 0; char * timestr; 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 == 8) //UDP Audio { if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1) udp_socket_blaster (opts, state, 320*4, samp_fs); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1) udp_socket_blaster (opts, state, 160*4, samp_f); if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0) udp_socket_blaster (opts, state, 320*2, samp_ss); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0) udp_socket_blaster (opts, state, 160*2, samp_s); } else if (opts->audio_out_type == 1) //STDOUT { if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 1) write(opts->audio_out_fd, samp_fs, 320*4); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 1) write(opts->audio_out_fd, samp_f, 160*4); if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0) write(opts->audio_out_fd, samp_ss, 320*2); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0) write(opts->audio_out_fd, samp_s, 160*2); } else if (opts->audio_out_type == 2) //OSS Variable Output (no float) { if (opts->pulse_digi_out_channels == 2 && opts->floating_point == 0) write(opts->audio_out_fd, samp_ss, 320*2); if (opts->pulse_digi_out_channels == 1 && opts->floating_point == 0) write(opts->audio_out_fd, samp_s, 160*2); } else if (opts->audio_out_type == 5) //OSS 48k/1 configuration with upsample { short prev = 0; for (i = 0; i < 160; i++) { upsampleS (samp_s[i], prev, outbuf); samp_su[(i*6)+0] = outbuf[0]; samp_su[(i*6)+1] = outbuf[1]; samp_su[(i*6)+2] = outbuf[2]; samp_su[(i*6)+3] = outbuf[3]; samp_su[(i*6)+4] = outbuf[4]; samp_su[(i*6)+5] = outbuf[5]; } write (opts->audio_out_fd, samp_su, 960*2); } } } 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; //fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b char * getTimeN(void) //get pretty hhmmss timestamp { char * curr = (char *) malloc(9); time_t t = time(NULL); struct tm * ptm = localtime(& t); sprintf( curr, "%02d%02d%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec ); 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", "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); //causes crash in Cygwin when mixed input/output //terminate all values for (int i = 0; i < 10; i++) sprintf (alias_ch[i], "%s", ""); UNUSED(opts); UNUSED(state); // state->menuopen = 1; //flag the menu is open, stop processing getFrameSync mbe_printVersion (versionstr); setlocale(LC_ALL, ""); initscr(); //Initialize NCURSES screen window start_color(); #ifdef PRETTY_COLORS init_pair(1, COLOR_YELLOW, COLOR_BLACK); //Yellow/Amber for frame sync/control channel, NV style init_pair(2, COLOR_RED, COLOR_BLACK); //Red for Terminated Calls init_pair(3, COLOR_GREEN, COLOR_BLACK); //Green for Active Calls init_pair(4, COLOR_CYAN, COLOR_BLACK); //Cyan for Site Extra and Patches init_pair(5, COLOR_MAGENTA, COLOR_BLACK); //Magenta for no frame sync/signal init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme #else init_pair(1, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(2, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(3, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(4, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(5, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme #endif noecho(); cbreak(); } //ncursesMenu void ncursesMenu (dsd_opts * opts, dsd_state * state) { //update sync time on cc sync so we don't immediately go CC hunting when exiting the menu state->last_cc_sync_time = time(NULL); //close pulse output if not null output if (opts->audio_out == 1 && opts->audio_out_type == 0) { closePulseOutput (opts); } //close OSS output if (opts->audio_out_type == 2 || opts->audio_out_type == 5) { close (opts->audio_out_fd); } if (opts->audio_in_type == 0) //close pulse input if it is the specified input method { closePulseInput(opts); } if (opts->audio_in_type == 3) { #ifdef USE_RTLSDR rtl_clean_queue(); #endif } if (opts->audio_in_type == 8) //close TCP input SF file so we don't buffer audio while not decoding { sf_close(opts->tcp_file_in); } state->payload_keyid = 0; state->payload_keyidR = 0; //zero out 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(), timestr); 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, " RTL Device Index or Serial Number:"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_dev_index); noecho(); entry_win = newwin(6, WIDTH+6, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " RTL Device PPM Error:"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtlsdr_ppm_error); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Frequency in Hz (851.8 MHz is 851800000 Hz): "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtlsdr_center_freq); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " BW (8, 12, 24, 48)(12 Recommended): "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_bandwidth); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " RTL Gain Value (0-49) (0 = AGC): "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_gain_value); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " RTL UDP Port - Legacy/Optional (Default = 0): "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_udp_port); noecho(); entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " RTL Vol Multiplier (1,2,3) (Default = 1): "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_volume_multiplier); if (opts->rtl_volume_multiplier > 3 || opts->rtl_volume_multiplier < 0) opts->rtl_volume_multiplier = 1; noecho(); entry_win = newwin(8, WIDTH+22, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " RTL RMS Squelch Level (NXDN/dPMR/Analog/Raw only): "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtl_squelch_level); noecho(); //use to list out all detected RTL dongles device_count = rtlsdr_get_device_count(); if (!device_count) { fprintf(stderr, "No supported devices found.\n"); } else fprintf(stderr, "Found %d device(s):\n", device_count); for (int i = 0; i < device_count; i++) { rtlsdr_get_device_usb_strings(i, vendor, product, serial); fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial); sprintf (userdev, "%08d", opts->rtl_dev_index); //check by index first, then by serial if (opts->rtl_dev_index == i) { fprintf (stderr, "Selected Device #%d with Serial Number: %s \n", i, serial); break; } else if (strcmp (userdev, serial) == 0) { fprintf (stderr, "Selected Device #%d with Serial Number: %s \n", i, serial); opts->rtl_dev_index = i; break; } } entry_win = newwin(18, WIDTH+20, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Starting RTL Input. Cannot Release/Stop Until Exit."); mvwprintw(entry_win, 4, 2, " RTL Frequency: %d Hz", opts->rtlsdr_center_freq); mvwprintw(entry_win, 5, 2, " RTL Device Index Number: %d; SN:%s", opts->rtl_dev_index, serial); mvwprintw(entry_win, 6, 2, " RTL Device Bandwidth: %d kHz", opts->rtl_bandwidth); mvwprintw(entry_win, 7, 2, " RTL Device Gain: %d", opts->rtl_gain_value); mvwprintw(entry_win, 8, 2, " RTL Volume Multiplier: %d", opts->rtl_volume_multiplier); mvwprintw(entry_win, 9, 2, " RTL Device UDP Port: %d", opts->rtl_udp_port); mvwprintw(entry_win, 10, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error); mvwprintw(entry_win, 11, 2, " RTL RMS Squelch: %d", opts->rtl_squelch_level); mvwprintw(entry_win, 13, 2, " Are You Sure?"); mvwprintw(entry_win, 14, 2, " 1 = Yes, 2 = No "); mvwprintw(entry_win, 15, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &confirm); noecho(); refresh(); //works well, but can't release dongle later, so its a one way trip until exit //TODO: Write function to release the dongle -- call cleanup_rtlsdr_stream() if (confirm == 1) { opts->audio_in_type = 3; //RTL input, only set this on confirm choicec = 18; //exit to decoder screen only if confirmed, otherwise, just go back } #else UNUSED(confirm); #endif } if (choicec == 7) //RTL DEV Retune { //read in new rtl frequency #ifdef USE_RTLSDR entry_win = newwin(6, WIDTH+18, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Frequency in Hz (851.8 MHz is 851800000 Hz) "); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rtlsdr_center_freq); noecho(); temp_freq = opts->rtlsdr_center_freq; #endif choicec = 18; } if (choicec == 8) { if (state->rf_mod == 0) { state->rf_mod = 1; state->samplesPerSymbol = 8; state->symbolCenter = 3; opts->mod_c4fm = 0; opts->mod_qpsk = 1; } else { state->rf_mod = 0; state->samplesPerSymbol = 10; state->symbolCenter = 4; opts->mod_c4fm = 1; opts->mod_qpsk = 0; } } if (choicec == 9) { if (state->rf_mod == 0) { state->rf_mod = 1; state->samplesPerSymbol = 10; state->symbolCenter = 4; opts->mod_c4fm = 0; opts->mod_qpsk = 1; } else { state->rf_mod = 0; state->samplesPerSymbol = 10; state->symbolCenter = 4; opts->mod_c4fm = 1; opts->mod_qpsk = 0; } } // if (choicec == 9) // { // if (opts->audio_out == 0) // { // opts->audio_out = 1; // opts->audio_out_type = 0; // // state->audio_out_buf_p = 0; // // state->audio_out_buf_pR = 0; // state->audio_out_idx = 0; // state->audio_out_idx2 = 0; // state->audio_out_idxR = 0; // state->audio_out_idx2R = 0; // } // else // { // opts->audio_out = 0; // opts->audio_out_type = 9; // // state->audio_out_buf_p = 0; // // state->audio_out_buf_pR = 0; // state->audio_out_idx = 0; // state->audio_out_idx2 = 0; // state->audio_out_idxR = 0; // state->audio_out_idx2R = 0; // } // } //TCP Audio Input if (choicec == 10) { //read in tcp hostname sprintf (opts->tcp_hostname, "%s", "localhost"); opts->tcp_portno = 7355; entry_win = newwin(8, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter TCP Direct Link Hostname:"); mvwprintw(entry_win, 3, 2, " (default is localhost)"); mvwprintw(entry_win, 4, 2, " "); mvwprintw(entry_win, 5, 3, " "); echo(); refresh(); wscanw(entry_win, "%s", opts->tcp_hostname); noecho(); //read in tcp port number entry_win = newwin(8, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter TCP Direct Link Port Number:"); mvwprintw(entry_win, 3, 2, " (default is 7355)"); mvwprintw(entry_win, 4, 2, " "); mvwprintw(entry_win, 5, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->tcp_portno); noecho(); opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno); if (opts->tcp_sockfd == 0) goto TCP_END; //successful connection, continue; opts->audio_in_type = 8; opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); opts->audio_in_file_info->samplerate=opts->wav_sample_rate; opts->audio_in_file_info->channels=1; opts->audio_in_file_info->seekable=0; opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE; opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0); if(opts->tcp_file_in == NULL) { fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL)); if (opts->audio_out_type == 0) { sprintf (opts->audio_in_dev, "%s", "pulse"); opts->audio_in_type = 0; } else opts->audio_in_type = 5; } TCP_END: ; //do nothing } //RIGCTL if (choicec == 11) { //read in tcp hostname sprintf (opts->rigctlhostname, "%s", "localhost"); opts->rigctlportno = 4532; entry_win = newwin(8, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RIGCTL Hostname:"); mvwprintw(entry_win, 3, 2, " (default is localhost)"); mvwprintw(entry_win, 4, 2, " "); mvwprintw(entry_win, 5, 3, " "); echo(); refresh(); wscanw(entry_win, "%s", opts->rigctlhostname); noecho(); //read in tcp port number entry_win = newwin(8, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter RIGCTL Port Number:"); mvwprintw(entry_win, 3, 2, " (default is 4532)"); mvwprintw(entry_win, 4, 2, " "); mvwprintw(entry_win, 5, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &opts->rigctlportno); noecho(); opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno); if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1; else opts->use_rigctl = 0; } // if (choicec == 10) // { // if (opts->ncurses_compact == 0) // { // opts->ncurses_compact = 1; // } // else opts->ncurses_compact = 0; // } // if (choicec == 11) // { // if (opts->ncurses_history == 0) // { // opts->ncurses_history = 1; // } // else opts->ncurses_history = 0; // } if (choicec == 12) { //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; //Causes issues with Voice Wide if (opts->use_heuristics == 1) { initialize_p25_heuristics(&state->p25_heuristics); initialize_p25_heuristics(&state->inv_p25_heuristics); } opts->frame_p25p1 = 1; opts->frame_p25p2 = 1; opts->frame_dmr = 1; state->samplesPerSymbol = 10; state->symbolCenter = 4; state->rf_mod = 0; sprintf (opts->output_name, "TDMA"); opts->dmr_mono = 0; opts->dmr_stereo = 1; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 2; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; opts->unmute_encrypted_p25 = 0; break; } if (choice == 2) { //AUTO Stereo P25 1, 2, and DMR // resetState (state); //use sparingly, seems to cause issue when switching back to other formats if (opts->use_heuristics == 1) { initialize_p25_heuristics(&state->p25_heuristics); initialize_p25_heuristics(&state->inv_p25_heuristics); } // opts->use_heuristics = 0; opts->frame_dmr = 1; state->samplesPerSymbol = 10; state->symbolCenter = 4; state->rf_mod = 0; sprintf (opts->output_name, "AUTO"); opts->dmr_mono = 0; opts->dmr_stereo = 1; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 2; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 1; opts->frame_p25p2 = 1; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 1; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; break; } if (choice == 7) { // resetState (state); //use sparingly, seems to cause issue when switching back to other formats state->samplesPerSymbol = 8; state->symbolCenter = 3; sprintf (opts->output_name, "P25p2"); opts->dmr_mono = 0; opts->dmr_stereo = 1; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 2; opts->frame_dmr = 0; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_p25p2 = 1; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; break; } if (choice == 8) { //dPMR // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 20; state->symbolCenter = 10; sprintf (opts->output_name, "dPMR"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 1; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; //opts->unmute_encrypted_p25 = 0; break; } if (choice == 9) { //NXDN48 // resetState (state); //use sparingly, may cause memory leak opts->frame_nxdn48 = 1; state->samplesPerSymbol = 20; state->symbolCenter = 10; state->rf_mod = 0; sprintf (opts->output_name, "NXDN48"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 1; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; //opts->unmute_encrypted_p25 = 0; // opts->mod_qpsk = 0; // opts->mod_gfsk = 0; // state->rf_mod = 0; } if (choice == 10) { //NXDN96 // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (opts->output_name, "NXDN96"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 1; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; //opts->unmute_encrypted_p25 = 0; } if (choice == 11) { //Decode DMR Stereo (was X2-TDMA) // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; // sprintf (opts->output_name, "X2-TDMA"); sprintf (opts->output_name, "DMR"); opts->dmr_mono = 0; opts->dmr_stereo = 1; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 2; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 1; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; //opts->unmute_encrypted_p25 = 0; } if (choice == 12) { //Decode YSF Fusion // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (opts->output_name, "YSF"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 1; opts->frame_m17 = 0; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; } if (choice == 5) //was 3 { //Decode M17 // resetState (state); //use sparingly, may cause memory leak state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (opts->output_name, "M17"); opts->dmr_mono = 0; opts->dmr_stereo = 0; //this value is the end user option state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling opts->pulse_digi_rate_out = 8000; opts->pulse_digi_out_channels = 1; opts->frame_dstar = 0; opts->frame_x2tdma = 0; opts->frame_p25p1 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 0; opts->frame_dpmr = 0; opts->frame_provoice = 0; opts->frame_ysf = 0; opts->frame_m17 = 1; opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; } if (choice == 13) { //Set all signal for inversion or uninversion if (opts->inverted_dmr == 0) { opts->inverted_dmr = 1; opts->inverted_dpmr = 1; opts->inverted_x2tdma = 1; opts->inverted_ysf = 1; opts->inverted_m17 = 1; } else { opts->inverted_dmr = 0; opts->inverted_dpmr = 0; opts->inverted_x2tdma = 0; opts->inverted_ysf = 0; opts->inverted_m17 = 0; } } if (choice == 15) //reset call history (usually if janky output when switching modes) { for (short int k = 0; k < 10; 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; sprintf (alias_ch[k], "%s", ""); } 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; state->nxdn_last_ran = -1; state->nxdn_last_rid = 0; state->nxdn_last_tg = 0; sprintf (state->str50a, "%s", ""); memset (state->str50b, 0, 50*sizeof(char)); } if (choice == 16) //toggle payload printing { if (opts->payload == 0) { opts->payload = 1; fprintf(stderr, "Payload on\n"); } else { opts->payload = 0; fprintf(stderr, "Payload Off\n"); } } if (choice == 17) { //hardset P2 WACN, SYSID, and NAC entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Phase 2 WACN (HEX)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->p2_wacn); //%X if (state->p2_wacn > 0xFFFFF) { state->p2_wacn = 0xFFFFF; } noecho(); entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Phase 2 SYSID (HEX)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->p2_sysid); //%X if (state->p2_sysid > 0xFFF) { state->p2_sysid = 0xFFF; } noecho(); entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter Phase 2 NAC/CC (HEX)"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%llX", &state->p2_cc); //%X if (state->p2_cc > 0xFFF) { state->p2_cc = 0xFFF; } noecho(); //need handling to truncate larger than expected values //set our hardset flag to 1 if values inserted, else set to 0 so we can attempt to get them from TSBK/LCCH if (state->p2_wacn != 0 && state->p2_sysid != 0 && state->p2_cc != 0) { state->p2_hardset = 1; } else state->p2_hardset = 0; } if (choice == 19) { short int lrrpchoice = 0; entry_win = newwin(10, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enable or Disable LRRP Data File"); mvwprintw(entry_win, 3, 2, " 1 - ~/lrrp.txt (QGis)"); mvwprintw(entry_win, 4, 2, " 2 - ./DSDPlus.LRRP (LRRP.exe)"); mvwprintw(entry_win, 5, 2, " 3 - ./Custom Filename"); mvwprintw(entry_win, 6, 2, " 4 - Cancel/Stop"); mvwprintw(entry_win, 7, 2, " "); mvwprintw(entry_win, 8, 2, " "); echo(); refresh(); wscanw(entry_win, "%hd", &lrrpchoice); //%d noecho(); if (lrrpchoice == 1) { //find user home directory and append directory and filename. char * filename = "/lrrp.txt"; char * home_dir = getenv("HOME"); char * filepath = malloc(strlen(home_dir) + strlen(filename) + 1); strncpy (filepath, home_dir, strlen(home_dir) + 1); strncat (filepath, filename, strlen(filename) + 1); //assign home directory/filename to lrrp_out_file sprintf (opts->lrrp_out_file, "%s", filepath); //double check make sure this still works opts->lrrp_file_output = 1; } else if (lrrpchoice == 2) { sprintf (opts->lrrp_out_file, "DSDPlus.LRRP"); opts->lrrp_file_output = 1; } else if (lrrpchoice == 3) { //read in filename for symbol capture bin opts->lrrp_out_file[0] = 0; entry_win = newwin(6, WIDTH+16, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Enter LRRP Data Filename"); mvwprintw(entry_win, 3, 3, " "); echo(); refresh(); wscanw(entry_win, "%s", opts->lrrp_out_file); //&opts->lrrp_out_file noecho(); if (opts->lrrp_out_file[0] != 0) //NULL { opts->lrrp_file_output = 1; } else { opts->lrrp_file_output = 0; sprintf (opts->lrrp_out_file, "%s", ""); opts->lrrp_out_file[0] = 0; } } else { opts->lrrp_file_output = 0; sprintf (opts->lrrp_out_file, "%s", ""); opts->lrrp_out_file[0] = 0; } } if (choice == 20) { exitflag = 1; break; } if(choice != 0 && choice != 20) /* User did a choice come out of the infinite loop */ break; } clrtoeol(); //clear to end of line? refresh(); state->menuopen = 0; //flag the menu is closed, resume processing getFrameSync //reopen pulse output with new parameters, if not null output type if (opts->audio_out == 1 && opts->audio_out_type == 0) { openPulseOutput (opts); } if (opts->audio_out_type == 2 || opts->audio_out_type == 5) { openOSSOutput (opts); } if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method { openPulseInput(opts); } //fix location of this statement to inside the if statement and add conditions if (opts->audio_in_type == 3) //open rtl input if it is the specified input method { // ncursesPrinter (opts, state); //not sure why this was placed here originally, but causes a double free core dump when calling free(timestr) #ifdef USE_RTLSDR if (opts->rtl_started == 0) { opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again open_rtlsdr_stream(opts); } rtl_clean_queue(); reset_dibit_buffer(state); //test and observe for any random issues, disable if needed #elif AERO_BUILD opts->audio_out_type = 5; //hopefully the audio stream is still/already open //shouldn't this be 5? Was set to 3 #else opts->audio_out_type = 0; //need to see if we need to open pulseoutput as well here? openPulseOutput (opts); #endif } if (opts->audio_in_type == 8) //re-open TCP input 'file' { opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0); } //update sync time on cc sync so we don't immediately go CC hunting when exiting the menu state->last_cc_sync_time = time(NULL); } //end Ncurses Menu void ncursesPrinter (dsd_opts * opts, dsd_state * state) { uint8_t idas = 0; int level = 0; int c = 0; timestr = getTimeN(); 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 != src) { src = state->nxdn_last_rid; } if (state->nxdn_last_ran != -1 ) { rn = state->nxdn_last_ran; } if (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; //EDACS standard does not provide source LIDs on channel update messages; instead, for the sake of display, let's //assume the prior source for a given LCN is still accurate, unless we have an updated one provided (or the call //type has changed under us). // //If you MUST have perfectly-accurate source LIDs, look at the logged CC messages yourself - incorrect source LIDs //may be displayed if we miss an initial call channel assignment. if (state->ea_mode == 1 || (state->lastsrc != 0 || call_matrix[state->edacs_vc_lcn][4] != state->edacs_vc_call_type)) call_matrix[state->edacs_vc_lcn][3] = state->lastsrc; call_matrix[state->edacs_vc_lcn][4] = state->edacs_vc_call_type; 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]; sprintf (alias_ch[k], "%s", alias_ch[k+1]); } call_matrix[9][0] = lls; call_matrix[9][1] = tgn; //was rn, switch to tgn so it'll show tg in call history call_matrix[9][2] = src; call_matrix[9][3] = 0; call_matrix[9][4] = rn; //was tgn, switched with rn call_matrix[9][5] = time(NULL); sprintf (alias_ch[9], "%s", ""); sprintf (state->str50a, "%s", ""); //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(), timestr, 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); } } //TODO: Find better placement for these if ( strcmp(state->str50a, "") != 0 ) sprintf (alias_ch[9], "%s", state->str50a); //tdma only // if ( strcmp(state->str50b, "") != 0 ) // sprintf (alias_ch[5], "%s", state->str50a); //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(), timestr, 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(), timestr, 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(), timestr, 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(), timestr, 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 (20231015)"); 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 %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 && opts->frame_m17 == 0) printw (" MBElib %s", versionstr); #ifdef USE_CODEC2 if (i == 4 && opts->frame_m17 == 1) printw (" CODEC2"); #endif #ifdef AERO_BUILD if (i == 5) printw (" %s ", "Aero Build"); if (i == 6) printw (" AW (20231015) \n"); #elif ZDEV_BUILD if (i == 5) printw (" %s ", "AW "); if (i == 6) printw (" %s \n", GIT_TAG); #else if (i == 5) printw (" %s ", "AW "); 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 Signal Input: %i kHz; %i Ch; ", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); if (opts->use_rigctl == 1) printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno); printw ("\n"); } if (opts->audio_in_type == 5) { printw ("| OSS Signal Input: %i kHz; 1 Ch;", SAMPLE_RATE_IN/1000); if (opts->use_rigctl == 1) printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno); printw ("\n"); } if (opts->audio_in_type == 4) { printw ("| Symbol Bin Input: %s \n", opts->audio_in_dev); } if (opts->m17decoderip == 1 && opts->udp_sockfd) printw ("| M17 UDP IP Frame Input: %s:%d \n", opts->m17_hostname, opts->m17_portno); if (opts->audio_in_type == 8) { printw ("| TCP Signal Input: %s:%d; %d kHz; 1 Ch; ", opts->tcp_hostname, opts->tcp_portno, opts->wav_sample_rate/1000); if (opts->use_rigctl == 1) printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno); printw ("\n"); } if (opts->audio_in_type == 2) { printw ("| WAV Audio Input: %s; %d kHz; \n", opts->audio_in_dev, opts->wav_sample_rate); } if (opts->audio_in_type == 1) { printw ("| STDIN Standard Input: - Menu Disabled when using STDIN!\n"); // printw ("| NCURSES Menu Disabled when using STDIN! - Use CTRL + C to Close. \n"); } if (opts->audio_in_type == 3) { printw ("| RTL: %d;", opts->rtl_dev_index); if (opts->rtl_gain_value == 0) printw (" G: AGC;"); else printw (" G: %idB;", opts->rtl_gain_value); printw (" V: %iX;", opts->rtl_volume_multiplier); printw (" PPM: %i;", opts->rtlsdr_ppm_error); printw (" SQ: %i;", opts->rtl_squelch_level); printw (" RMS: %04li;", opts->rtl_rms); printw (" BW: %i;", opts->rtl_bandwidth); printw (" FRQ: %i;", opts->rtlsdr_center_freq); if (opts->rtl_udp_port != 0) printw ("\n| External RTL Tuning on UDP Port: %i", opts->rtl_udp_port); printw ("\n"); } if (opts->audio_out_type == 0) { printw ("| Pulse Digital Output: %i kHz; %i Ch; G: %02.0f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2); if (opts->floating_point == 1) printw (" FLOAT: %02.0f%%;", opts->audio_gain*2); if (opts->audio_gain == 0) printw (" (+|-) Auto "); if (opts->audio_gain > 0) printw (" (+|-) Manual"); if (opts->use_hpf_d == 1) printw (" HPF"); if (opts->call_alert == 1) printw (" *CA!"); //Call Alert printw (" \n"); } if ( opts->audio_out_type == 0 && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) ) { printw ("| Pulse Analog Output: %i kHz; %i Ch; G: %02.0f%% (/|*) ", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->audio_gainA); if (opts->audio_gainA == 0.0f) printw ("Auto "); else printw ("Manual "); if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms); if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |"); if (opts->use_hpf == 1) printw ("HP|"); else printw (" |"); if (opts->use_pbf == 1) printw ("PB|"); else printw (" |"); printw (" \n"); } if (opts->audio_out_type == 5 || opts->audio_out_type == 2) { printw ("| OSS Audio Output: %i kHz; %i Ch; G: %02.0f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2); if (opts->audio_gain == 0) printw (" (+/-) Auto "); if (opts->audio_gain > 0) printw (" (+/-) Manual"); if (opts->use_hpf_d == 1) printw (" HPF"); if (opts->call_alert == 1) printw (" *CA!"); //Call Alert if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) ) { printw ("\n| Analog Monitor RMS: %04ld; G: %02.0f%% (/|*) ", opts->rtl_rms, opts->audio_gainA); if (opts->audio_gainA == 0.0f) printw ("Auto "); else printw ("Manual "); if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |"); if (opts->use_hpf == 1) printw ("HP|"); else printw (" |"); if (opts->use_pbf == 1) printw ("PB|"); else printw (" |"); } printw (" \n"); } if (opts->audio_out_type == 8) { printw ("| UDP Digital Output: %s:%d; %d kHz %d Ch; %02.0f%%", opts->udp_hostname, opts->udp_portno, opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2); if (opts->audio_gain == 0) printw (" (+/-) Auto "); if (opts->audio_gain > 0) printw (" (+/-) Manual"); if (opts->use_hpf_d == 1) printw (" HPF"); if (opts->call_alert == 1) printw (" *CA!"); //Call Alert if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) ) printw (" - Monitor RMS: %04ld ", opts->rtl_rms); printw (" \n"); if (opts->udp_sockfdA != 0) //Analog Output on udp port +2 { printw ("| UDP Analog Output: %s:%d; 48 kHz 1 Ch; G: %02.0f%% (/|*) ", opts->udp_hostname, opts->udp_portno+2, opts->audio_gainA); if (opts->audio_gainA == 0.0f) printw ("A "); else printw ("M "); if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms); if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |"); if (opts->use_hpf == 1) printw ("HP|"); else printw (" |"); if (opts->use_pbf == 1) printw ("PB|"); else printw (" |"); printw (" \n"); } } if (opts->m17_use_ip == 1) printw ("| M17 UDP IP Frame Output: %s:%d \n", opts->m17_hostname, opts->m17_portno); if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0) { printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir); } if (opts->wav_out_raw) { printw ("| Raw Audio Output: %s\n", opts->wav_out_file_raw); } if (opts->symbol_out_f) //don't display when not actively capturing { printw ("| Symbol Bin Output: %s\n", opts->symbol_out_file); } if (opts->dmr_stereo_wav == 0 && opts->wav_out_file[0] != 0) { printw ("| Decoded WAV Output: %s\n", opts->wav_out_file); } 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); } #ifdef PRETTY_COLORS if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) ) { printw ("| Trunking -"); if (opts->trunk_tune_group_calls == 0) attron(COLOR_PAIR(2)); printw (" Group(g)"); attron(COLOR_PAIR(4)); if (opts->trunk_tune_private_calls == 0) attron(COLOR_PAIR(2)); printw (" Private(u)"); attron(COLOR_PAIR(4)); if (opts->trunk_tune_data_calls == 0) attron(COLOR_PAIR(2)); printw (" Data(d)"); attron(COLOR_PAIR(4)); if (opts->trunk_tune_enc_calls == 0) attron(COLOR_PAIR(2)); printw (" Encrypted(e)"); attron(COLOR_PAIR(4)); printw (" Calls"); if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n"); else printw (" - Black List Mode\n"); } #else //set on to UPPER CASE, off to lower case if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) ) { printw ("| Trunking -"); if (opts->trunk_tune_group_calls == 0) printw (" group(g)"); else printw (" GROUP(g)"); if (opts->trunk_tune_private_calls == 0) printw (" private(u)"); else printw (" PRIVATE(u)"); if (opts->trunk_tune_data_calls == 0) printw (" data(d)"); else printw (" DATA(d)"); if (opts->trunk_tune_enc_calls == 0) printw (" encrypted(e)"); else printw (" ENCRYPTED(e)"); printw (" Calls"); if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n"); else printw (" - Black List Mode\n"); } #endif //print additional information for EDACS modes and toggles #ifdef PRETTY_COLORS if (opts->p25_trunk == 1 && opts->frame_provoice == 1) { printw ("| \\--EDACS -"); if (state->ea_mode == -1) { attron(COLOR_PAIR(2)); printw (" Standard/Network"); printw (" Extended Address"); attron(COLOR_PAIR(4)); } else if (state->ea_mode == 0) { printw (" Standard/Network"); attron(COLOR_PAIR(2)); printw (" Extended Address"); attron(COLOR_PAIR(4)); } else if (state->ea_mode == 1) { attron(COLOR_PAIR(2)); printw (" Standard/Network"); attron(COLOR_PAIR(4)); printw (" Extended Address"); } printw (" Mode (S);"); printw(" ESK: %02X", state->esk_mask); printw (" (A);"); if (state->ea_mode == 0) printw (" AFS: %d:%d:%d;", state->edacs_a_bits, state->edacs_f_bits, state->edacs_s_bits); attron(COLOR_PAIR(4)); printw ("\n"); } #else //set on to UPPER CASE, off to lower case if (opts->p25_trunk == 1 && opts->frame_provoice == 1) { printw ("| \\--EDACS -"); if (state->ea_mode == -1) { printw (" standard/network"); printw (" extended address"); } else if (state->ea_mode == 0) { printw (" STANDARD/NETWORK"); printw (" extended address"); } else if (state->ea_mode == 1) { printw (" standard/network"); printw (" EXTENDED ADDRESS"); } printw (" Mode (S);"); printw(" ESK: %02X", state->esk_mask); printw (" (A) Toggle; "); if (state->ea_mode == 0) printw (" AFS: %d:%d:%d;", state->edacs_a_bits, state->edacs_f_bits, state->edacs_s_bits); printw ("\n"); } #endif // if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n"); if (state->M == 1) { if (state->R != 0) printw ("| Forcing Key Priority -- NXDN Sc Key: %05lld \n", state->R); if (state->K != 0) printw ("| Forcing Key Priority -- Moto BP Key: %03lld \n", state->K); if (state->K1 != 0) printw ("| Forcing Key Priority -- 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 ("| Scan Mode: "); if (state->lcn_freq_roll != 0) printw (" Frequency: %.06lf Mhz", (double)state->trunk_lcn_freq[state->lcn_freq_roll-1]/1000000); printw (" Speed: %.02lf sec \n", opts->trunk_hangtime); //not sure values less than 1 make a difference, may be system/environment dependent } if (opts->reverse_mute == 1) printw ("| Reverse Mute - Muting Unencrypted Voice\n"); // if (opts->call_alert == 1) printw ("| Call Alert Tone Enabled\n"); printw ("------------------------------------------------------------------------------\n"); attroff(COLOR_PAIR(4)); if (state->carrier == 1) { attron(COLOR_PAIR(3)); level = (int) state->max / 164; //only update on carrier present if (opts->mod_qpsk == 1) level = (int) state->max / 328; //test values here if (opts->audio_in_type == 4) level = 50; //hard set when reading symbol bin files, otherwise, it will just be near zero if (level > 100) level = 100; //cap max at 100 to prevent it going over reset = 1; } else level = 0; printw ("--Audio Decode----------------------------------------------------------------\n"); printw ("| Demod/Rate: "); if (opts->mod_qpsk == 1) printw ("[QPSK]"); if (opts->mod_c4fm == 1) printw ("[C4FM]"); if (opts->mod_gfsk == 1) printw ("[GFSK]"); printw ( "[%d] \n", (48000*opts->wav_interpolator)/state->samplesPerSymbol); if (opts->m17encoder == 1) printw ("| Encoding: [%s] ", opts->output_name); if (opts->m17encoder == 1 && state->m17encoder_tx == 1 && state->m17_vox == 0) printw (" TX (\\) ON ;"); if (opts->m17encoder == 1 && state->m17encoder_tx == 0 && state->m17_vox == 0) printw (" TX (\\) OFF;"); if (opts->m17encoder == 1 && state->m17_vox == 1) printw (" Vox Mode;"); if (opts->m17encoder == 1) printw (" Input Gain (/|*): %02.0f%% ", opts->audio_gainA); if (opts->m17encoder == 1) { if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |"); if (opts->use_hpf == 1) printw ("HP|"); else printw (" |"); if (opts->use_pbf == 1) printw ("PB|"); else printw (" |"); printw ("\n"); } printw ("| Decoding: [%s] ", opts->output_name); if (opts->aggressive_framesync == 0) printw ("CRC/(RAS) "); //debug -- troubleshoot voice tuning after grant on DMR CC, subsequent grant may not tune because tuner isn't available if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1) printw ("Tuner Locked "); if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) printw ("Tuner Available "); //TG Hold on EDACS, if specified by user if ( (opts->frame_provoice == 1) && (state->tg_hold != 0) ) { // Compute AFS for display purposes only int a = (state->tg_hold >> state->edacs_a_shift) & state->edacs_a_mask; int f = (state->tg_hold >> state->edacs_f_shift) & state->edacs_f_mask; int s = state->tg_hold & state->edacs_s_mask; if (state->ea_mode == 1) printw ("TG HOLD: %d; ", state->tg_hold); else printw ("TG HOLD: %d [%02d-%02d%01d]; ", state->tg_hold, a, f, s); } printw ("\n"); printw ("| In Level: [%02d%%] \n", level); if (opts->dmr_stereo == 0) { printw ("| Voice Error: [%X][%X]", state->errs&0xF, state->errs2&0xF); if (opts->slot1_on == 0) printw (" OFF"); if (opts->slot1_on == 1) printw (" ON"); printw ("\n"); } if (opts->dmr_stereo == 1) { printw ("| Voice Error: [%X][%X] Slot 1 (1)", state->errs&0xF, state->errs2&0xF); if (opts->slot1_on == 0) printw (" OFF"); if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred"); printw ("\n"); printw ("| Voice Error: [%X][%X] Slot 2 (2)", state->errsR&0xF, state->errs2R&0xF); if (opts->slot2_on == 0) printw (" OFF"); if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred"); printw ("\n"); } printw ("------------------------------------------------------------------------------\n"); printw ("--Call Info-------------------------------------------------------------------\n"); //DSTAR if (lls == 6 || lls == 7 || lls == 18 || lls == 19) { printw ("| %s ", SyncTypes[lls]); printw ("\n"); printw ("| RPT2: %s", state->dstar_rpt2); printw (" RPT1: %s", state->dstar_rpt1); printw ("\n"); printw ("| DEST: %s", state->dstar_dst); printw (" SRC: %s", state->dstar_src); printw ("\n"); printw ("| TEXT: %s", state->dstar_txt); printw ("\n"); printw ("| DATA: %s", state->dstar_gps); printw ("\n"); } //M17 if (lls == 8 || lls == 9 || lls == 16 || lls == 17) { printw ("| "); printw ("M17: "); //insert data type and frame information if (state->m17_str_dt == 0) printw("Reserved"); if (state->m17_str_dt == 1) printw("Data "); if (state->m17_str_dt == 2) printw("Voice (3200) "); if (state->m17_str_dt == 3) printw("Voice (1600) + Data"); printw ("\n"); printw ("| "); printw ("DST: "); if (state->m17_dst == 0xFFFFFFFFFFFF) printw("BROADCAST "); else if (state->m17_dst != 0 && state->m17_dst >= 0xEE6B28000000) printw("RESERVED (%012llx) ", state->m17_dst); else printw("%s", state->m17_dst_str); printw ("\n"); printw ("| "); printw ("SRC: "); if (state->m17_src != 0 && state->m17_src >= 0xEE6B28000000) printw("RESERVED (%012llx)", state->m17_src); else printw("%s", state->m17_src_str); printw ("\n"); printw ("| "); printw ("CAN: %02d ", state->m17_can); printw ("\n"); printw ("| "); //fill in any extra info, like Meta (IV, etc) if (state->m17_enc == 1) { printw (" Scrambler - Type: %d", state->m17_enc_st); } if (state->m17_enc == 2) { 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) //consider disabling this printw ("Alias: [%s]", alias_ch[9]); //Group Name Labels from CSV import for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == tgn) { printw ("TG: "); attron(COLOR_PAIR(4)); printw (" [%s]", state->group_array[k].groupName); printw ("[%s] ", state->group_array[k].groupMode); } else if (state->group_array[k].groupNumber == src) { attron(COLOR_PAIR(4)); printw (" [%s]", state->group_array[k].groupName); } if (state->carrier == 1) { attron(COLOR_PAIR(3)); } } if (state->carrier == 1) { printw(" %s ", state->nxdn_call_type); } printw ("\n|"); if (state->nxdn_cipher_type > 0) { printw (" ALG: [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)); } //TG Hold, if specified by user if (state->tg_hold != 0) printw ("TG HOLD: %d", state->tg_hold); printw("\n"); } //P25 and DMR BS/MS if ( lls == 0 || lls == 1 || lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32 || lls == 33 || lls == 34 || lls == 35 || lls == 36) { printw ("| "); if (lls > 1 && lls < 30) { printw ("DMR BS - DCC: %02i; ", 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 || state->dmrburstL == 21 || state->dmrburstL == 26 || state->dmrburstL == 27 || state->dmrburstL == 32) //only during call { attron(COLOR_PAIR(4)); //Embedded GPS (not LRRP) printw ("%s ", state->dmr_embedded_gps[0]); //Embedded Talker Alias 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] -- Also Including DMR MS now to keep the display more 'uniform' in nature // if (lls < 30 || lls == 35 || lls == 36) { printw ("| SLOT 2 - "); if (state->dmrburstR < 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) { attron(COLOR_PAIR(2)); } printw ("TGT: [%8i] SRC: [%8i] ", state->lasttgR, state->lastsrcR); if (state->dmrburstR != 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) { attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } printw ("%s | ", state->call_string[1]); printw ("%s ", DMRBusrtTypes[state->dmrburstR]); if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*"); printw ("\n"); printw ("| V XTRA | "); //10 spaces if(state->dmrburstR == 16 && state->payload_algidR == 0 && (state->dmr_soR & 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 || state->dmrburstR == 21) //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); } //TG Hold, if specified by user if (state->tg_hold != 0) printw ("TG HOLD: %d", state->tg_hold); if (state->carrier == 1) attron(COLOR_PAIR(3)); else attroff(COLOR_PAIR(4)); printw ("\n"); } } // end if not MS } //end DMR BS Types //dPMR if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27) { printw ("| DCC: [%i] ", state->dpmr_color_code); printw ("TGT: [%s] SRC: [%s] ", state->dpmr_target_id, state->dpmr_caller_id); printw ("\n| "); if (state->dPMRVoiceFS2Frame.Version[0] == 3) { attron(COLOR_PAIR(2)); printw ("Scrambler "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); if (state->R != 0) { attron(COLOR_PAIR(1)); printw ("KEY VALUE: [%05lld] ", state->R ); //printw ("SEED: [%04llX]", state->payload_miN); attron(COLOR_PAIR(3)); } } printw ("\n"); } //EDACS and ProVoice if (lls == 14 || lls == 15 || lls == 37 || lls == 38) { attroff (COLOR_PAIR(3)); //colors off for EDACS if (state->edacs_site_id != 0) { if (opts->p25_is_tuned == 0) { printw ("| Monitoring 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++) { // Compute AFS for display purposes only int a = (call_matrix[i][2] >> state->edacs_a_shift) & state->edacs_a_mask; int f = (call_matrix[i][2] >> state->edacs_f_shift) & state->edacs_f_mask; int s = call_matrix[i][2] & state->edacs_s_mask; printw ("| - LCN [%02d][%010.06lf] MHz", i, (double)state->trunk_lcn_freq[i-1]/1000000); //print Control Channel on LCN line with the current Control Channel if ( (i) == state->edacs_cc_lcn) { attron (COLOR_PAIR(1)); //yellow printw (" Control Channel"); attroff (COLOR_PAIR(1)); } int print_call = 0; //print active calls on corresponding LCN line if ((i != state->edacs_cc_lcn) && time(NULL) - call_matrix[i][5] < 2) { print_call = 3; attron (COLOR_PAIR(3)); } //print dying or dead calls in red for x seconds longer else if ( (i != state->edacs_cc_lcn) && (time(NULL) - call_matrix[i][5] >= 2) && (time(NULL) - call_matrix[i][5] < 5) ) { print_call = 2; attron (COLOR_PAIR(2)); } if (print_call != 0) { if (state->ea_mode == 1) { // Voice call if ((call_matrix[i][4] & EDACS_IS_VOICE) != 0) { // System all-call if ((call_matrix[i][4] & EDACS_IS_GROUP) != 0) printw (" TGT [%8lld] SRC [%8lld]", call_matrix[i][2], call_matrix[i][3] ); // I-Call else if ((call_matrix[i][4] & EDACS_IS_INDIVIDUAL) != 0) printw (" TGT [%8lld] SRC [%8lld] I-Call", call_matrix[i][2], call_matrix[i][3] ); // System all-call else if ((call_matrix[i][4] & EDACS_IS_ALL_CALL) != 0) printw (" TGT [ SYSTEM ] SRC [%8lld] All-Call", call_matrix[i][3] ); // Interconnect call else if ((call_matrix[i][4] & EDACS_IS_INTERCONNECT) != 0) printw (" TGT [ SYSTEM ] SRC [%8lld] Interconnect", call_matrix[i][3] ); // Unknown call else printw (" Unknown call type" ); // Call flags if ((call_matrix[i][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]"); else printw (" [Dig]"); if ((call_matrix[i][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]"); } else // Data call printw (" TGT [ DATA ] SRC [%8lld] Data", call_matrix[i][3] ); } else { // Voice call if ((call_matrix[i][4] & EDACS_IS_VOICE) != 0) { // Group call if ((call_matrix[i][4] & EDACS_IS_GROUP) != 0) printw (" TGT [%6lld][%02d-%02d%01d] SRC [%5lld]", call_matrix[i][2], a, f, s, call_matrix[i][3] ); // I-Call else if ((call_matrix[i][4] & EDACS_IS_INDIVIDUAL) != 0) printw (" TGT [%6lld][ UNIT ] SRC [%5lld] I-Call", call_matrix[i][2], call_matrix[i][3] ); // System all-call else if ((call_matrix[i][4] & EDACS_IS_ALL_CALL) != 0) printw (" TGT [ SYSTEM ] SRC [%5lld] All-Call", call_matrix[i][3] ); // Interconnect call else if ((call_matrix[i][4] & EDACS_IS_INTERCONNECT) != 0) printw (" TGT [ SYSTEM ] SRC [%5lld] Interconnect", call_matrix[i][3] ); // Unknown call else printw (" Unknown call type" ); // Call flags if ((call_matrix[i][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]"); else printw (" [Dig]"); if ((call_matrix[i][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]"); } else // Data call printw (" TGT [ DATA ] SRC [%8lld] Data", call_matrix[i][3] ); } for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == call_matrix[i][2] && call_matrix[i][2] != 0) { printw (" [%s]", state->group_array[k].groupName); printw ("[%s]", state->group_array[k].groupMode); break; } else if (state->group_array[k].groupNumber == call_matrix[i][3] && call_matrix[i][3] != 0) { printw (" [%s]", state->group_array[k].groupName); printw ("[%s]", state->group_array[k].groupMode); break; } } if (print_call == 3) attroff (COLOR_PAIR(3)); else if (print_call == 2) attroff (COLOR_PAIR(2)); } if (i == state->edacs_tuned_lcn && opts->p25_is_tuned == 1) printw (" **T**"); //asterisk which lcn is tuned printw ("\n"); } if (state->carrier == 1) { attron (COLOR_PAIR(3)); } } //fence bottom printw ("------------------------------------------------------------------------------\n"); //colors off if (state->carrier == 1){ //same as above attroff(COLOR_PAIR(3)); } //only print 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][4]); if (idas == 1) printw ("Area [%02lld] ", call_matrix[9-j][4]); printw ("TG [%5lld] ", call_matrix[9-j][1]); 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); } } //alias values here printw ("%s", alias_ch[9-j]); // #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][2] != 0) { printw ("| "); printw ("%s ", getDateC(call_matrix[j][5]) ); printw ("%s ", getTimeC(call_matrix[j][5]) ); printw ("LCN [%2lld] ", call_matrix[j][1]); if (state->ea_mode == 1) { // Voice call if ((call_matrix[j][4] & EDACS_IS_VOICE) != 0) { // Group call if ((call_matrix[j][4] & EDACS_IS_GROUP) != 0) printw ("Target [%8lld] Source [%8lld]", call_matrix[j][2], call_matrix[j][3]); // I-Call else if ((call_matrix[j][4] & EDACS_IS_INDIVIDUAL) != 0) printw ("Target [%8lld] Source [%8lld] I-Call", call_matrix[j][2], call_matrix[j][3]); // System all-call else if ((call_matrix[j][4] & EDACS_IS_ALL_CALL) != 0) printw ("Target [ SYSTEM ] Source [%8lld] All-Call", call_matrix[j][3]); // Interconnect else if ((call_matrix[j][4] & EDACS_IS_INTERCONNECT) != 0) printw ("Target [ SYSTEM ] Source [%8lld] Interconnect", call_matrix[j][3]); // Unknown call else printw ("Unknown call type"); // Call flags if ((call_matrix[j][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]"); else printw (" [Dig]"); if ((call_matrix[j][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]"); } else // Data call printw ("Target [ DATA ] Source [%8lld] Data", call_matrix[j][3]); } else { // Voice call if ((call_matrix[j][4] & EDACS_IS_VOICE) != 0) { // Compute AFS for display purposes only int a = (call_matrix[j][2] >> state->edacs_a_shift) & state->edacs_a_mask; int f = (call_matrix[j][2] >> state->edacs_f_shift) & state->edacs_f_mask; int s = call_matrix[j][2] & state->edacs_s_mask; // Group call if ((call_matrix[j][4] & EDACS_IS_GROUP) != 0) printw ("Target [%6lld][%02d-%02d%01d] Source [%5lld]", call_matrix[j][2], a, f, s, call_matrix[j][3]); // I-Call else if ((call_matrix[j][4] & EDACS_IS_INDIVIDUAL) != 0) printw ("Target [%6lld][ UNIT ] Source [%5lld] I-Call", call_matrix[j][2], call_matrix[j][3]); // System all-call else if ((call_matrix[j][4] & EDACS_IS_ALL_CALL) != 0) printw ("Target [ SYSTEM ] Source [%5lld] All-Call", call_matrix[j][3]); // Interconnect else if ((call_matrix[j][4] & EDACS_IS_INTERCONNECT) != 0) printw ("Target [ SYSTEM ] Source [%5lld] Interconnect", call_matrix[j][3]); // Unknown call else printw ("Unknown call type"); // Call flags if ((call_matrix[j][4] & EDACS_IS_DIGITAL) == 0) printw (" [Ana]"); else printw (" [Dig]"); if ((call_matrix[j][4] & EDACS_IS_EMERGENCY) != 0) printw ("[EM]"); } else // Data call printw ("Target [ DATA ] Source [%5lld] Data", call_matrix[j][3]); } //test for (int k = 0; k < state->group_tally; k++) { if (state->group_array[k].groupNumber == call_matrix[j][2] && call_matrix[j][2] != 0) { attron(COLOR_PAIR(4)); printw ("[%s] ", state->group_array[k].groupName); break; } else if (state->group_array[k].groupNumber == call_matrix[j][3] && call_matrix[j][3] != 0) { attron(COLOR_PAIR(4)); printw ("[%s] ", state->group_array[k].groupName); break; } } //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 { if (opts->m17encoder == 0) //don't allow menu if using M17 encoder ncursesMenu (opts, state); } //use k and l keys to test tg hold toggles on slots 1 and slots 2 if (c == 107) //'k' key, hold tg on slot 1 for trunking purposes, or toggle clear { if (state->tg_hold == 0) state->tg_hold = state->lasttg; else state->tg_hold = 0; if ( (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1) && (state->tg_hold == 0) ) state->tg_hold = state->nxdn_last_tg; else if (opts->frame_provoice == 1 && state->ea_mode == 0) state->tg_hold = state->lastsrc; } if (c == 108) //'l' key, hold tg on slot 2 for trunking purposes, or toggle clear { if (state->tg_hold == 0) state->tg_hold = state->lasttgR; else state->tg_hold = 0; } //toggling when 48k/1 OSS still has some lag -- needed to clear out the buffer when switching if (c == 49) // '1' key, toggle slot1 on { //switching, but want to control each seperately plz if (opts->slot1_on == 1) { opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2; // opts->slot_preference = 1; //slot 2 //clear any previously buffered audio state->audio_out_float_buf_p = state->audio_out_float_buf + 100; state->audio_out_buf_p = state->audio_out_buf + 100; memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); memset (state->audio_out_buf, 0, 100 * sizeof (short)); state->audio_out_idx2 = 0; state->audio_out_idx = 0; } else if (opts->slot1_on == 0) { opts->slot1_on = 1; if (opts->audio_out_type == 5) //OSS 48k/1 { opts->slot_preference = 0; //slot 1 // opts->slot2_on = 0; //turn off slot 2 } } } if (c == 50) // '2' key, toggle slot2 on { //switching, but want to control each seperately plz if (opts->slot2_on == 1) { opts->slot2_on = 0; opts->slot_preference = 0; //slot 1 //clear any previously buffered audio state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100; state->audio_out_buf_pR = state->audio_out_bufR + 100; memset (state->audio_out_float_bufR, 0, 100 * sizeof (float)); memset (state->audio_out_bufR, 0, 100 * sizeof (short)); state->audio_out_idx2R = 0; state->audio_out_idxR = 0; } else if (opts->slot2_on == 0) { opts->slot2_on = 1; if (opts->audio_out_type == 5) //OSS 48k/1 { opts->slot_preference = 1; //slot 2 // opts->slot1_on = 0; //turn off slot 1 } } } // if (c == 51) //'3' key, toggle slot preference on 48k/1 // { // if (opts->slot_preference == 1) opts->slot_preference = 0; // else opts->slot_preference = 1; // } if (c == 51) //'3' key, cycle slot preference { if (opts->slot_preference == 0 || opts->slot_preference == 1) opts->slot_preference++; else opts->slot_preference = 0; } if (c == 43) //+ key, increment audio_gain { if (opts->audio_gain < 50) opts->audio_gain++; state->aout_gain = opts->audio_gain; state->aout_gainR = opts->audio_gain; opts->audio_gainR = opts->audio_gain; } if (c == 45) //- key, decrement audio_gain { if (opts->audio_gain > 0) opts->audio_gain--; state->aout_gain = opts->audio_gain; state->aout_gainR = opts->audio_gain; //reset to default on 0 for auto if (opts->audio_gain == 0) { state->aout_gain = 25; state->aout_gainR = 25; } opts->audio_gainR = opts->audio_gain; } if (c == 42) // * key, increment audio_gainA { if (opts->audio_gainA < 100) opts->audio_gainA++; } if (c == 47) // / key, decrement audio_gainA { if (opts->audio_gainA > 0) opts->audio_gainA--; } if (c == 122) //'z' key, toggle payload to console { if (opts->payload == 1) opts->payload = 0; else opts->payload = 1; } if (c == 99) //'c' key, toggle compact mode { if (opts->ncurses_compact == 1) opts->ncurses_compact = 0; else opts->ncurses_compact = 1; } if (c == 116) //'t' key, toggle trunking { if (opts->p25_trunk == 1) opts->p25_trunk = 0; else opts->p25_trunk = 1; } if (c == 121) //'y' key, toggle scanner mode { if (opts->scanner_mode == 1) opts->scanner_mode = 0; else opts->scanner_mode = 1; opts->p25_trunk = 0; //turn off trunking mode } if (c == 97) //'a' key, toggle call alert beep { if (opts->call_alert == 1) opts->call_alert = 0; else opts->call_alert = 1; } if (c == 104) //'h' key, toggle history { if (opts->ncurses_history == 1) opts->ncurses_history = 0; else opts->ncurses_history = 1; } if (c == 113) //'q' key, quit { exitflag = 1; } if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr) { if (state->M == 1 || state->M == 0x21) state->M = 0; else state->M = 1; } if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry { if (state->M == 1 || state->M == 0x21) state->M = 0; else state->M = 0x21; } if (c == 105) //'i' key, toggle signal inversion on inverted types { //Set all signal for inversion or uninversion if (opts->inverted_dmr == 0) { opts->inverted_dmr = 1; opts->inverted_dpmr = 1; opts->inverted_x2tdma = 1; opts->inverted_ysf = 1; opts->inverted_m17 = 1; } else { opts->inverted_dmr = 0; opts->inverted_dpmr = 0; opts->inverted_x2tdma = 0; opts->inverted_ysf = 0; opts->inverted_m17 = 0; } } if (c == 109) //'m' key, toggle qpsk/c4fm - everything but phase 2 { if (state->rf_mod == 0) { opts->mod_c4fm = 0; opts->mod_qpsk = 1; opts->mod_gfsk = 0; state->rf_mod = 1; state->samplesPerSymbol = 10; state->symbolCenter = 4; } else { opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; state->samplesPerSymbol = 10; state->symbolCenter = 4; } } if (c == 77) //'M' key, toggle qpsk - phase 2 6000 sps { if (state->rf_mod == 0) { opts->mod_c4fm = 0; opts->mod_qpsk = 1; opts->mod_gfsk = 0; state->rf_mod = 1; state->samplesPerSymbol = 8; state->symbolCenter = 3; } else { opts->mod_c4fm = 1; opts->mod_qpsk = 0; opts->mod_gfsk = 0; state->rf_mod = 0; state->samplesPerSymbol = 8; state->symbolCenter = 3; } } if (c == 82) //'R', save symbol capture bin with date/time string as name { sprintf (opts->symbol_out_file, "%s %s.bin", getDateN(), timestr); openSymbolOutFile (opts, state); } if (c == 114) //'r' key, stop capturing symbol capture bin file { if (opts->symbol_out_f) { closeSymbolOutFile (opts, state); sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file); } } #ifdef 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 -- NOTE: Doesn't work correctly on EDACS Analog Voice //RIGCTL if (opts->p25_trunk == 1 && opts->use_rigctl == 1) { if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); SetFreq(opts->rigctl_sockfd, state->p25_cc_freq); } //rtl #ifdef USE_RTLSDR if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq); #endif state->last_cc_sync_time = time(NULL); //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } } if (state->lasttgR != 0 && opts->frame_provoice != 1 && c == 64) //SHIFT+'2' key (@ at sign), lockout slot 2 tdma tgR from tuning/playback during session { state->group_array[state->group_tally].groupNumber = state->lasttgR; sprintf (state->group_array[state->group_tally].groupMode, "%s", "B"); sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT"); state->group_tally++; //if we have an opened group file, let's write a group lock out into it to make it permanent if (opts->group_in_file[0] != 0) //file is available { FILE * pFile; //file pointer //open file by name that is supplied in the ncurses terminal, or cli pFile = fopen (opts->group_in_file, "a"); fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttgR, state->payload_algidR); fclose (pFile); } //extra safeguards due to sync issues with NXDN memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); memset (state->active_channel, 0, sizeof(state->active_channel)); //reset dmr blocks dmr_reset_blocks (opts, state); //zero out additional items state->lasttg = 0; state->lasttgR = 0; state->lastsrc = 0; state->lastsrcR = 0; state->payload_algid = 0; state->payload_algidR = 0; state->payload_keyid = 0; state->payload_keyidR = 0; state->payload_mi = 0; state->payload_miR = 0; state->payload_miP = 0; state->payload_miN = 0; opts->p25_is_tuned = 0; state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0; //tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice //RIGCTL if (opts->p25_trunk == 1 && opts->use_rigctl == 1) { if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); SetFreq(opts->rigctl_sockfd, state->p25_cc_freq); } //rtl #ifdef USE_RTLSDR if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq); #endif state->last_cc_sync_time = time(NULL); //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } } if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode { if (opts->trunk_use_allow_list == 1) opts->trunk_use_allow_list = 0; else opts->trunk_use_allow_list = 1; } if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls { if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0; else opts->trunk_tune_private_calls = 1; } if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls { if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0; else opts->trunk_tune_data_calls = 1; } if (opts->p25_trunk == 1 && c == 101) //'e' key, toggle tune enc calls (P25 only on certain grants) { if (opts->trunk_tune_enc_calls == 1) opts->trunk_tune_enc_calls = 0; else opts->trunk_tune_enc_calls = 1; } if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls { if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0; else opts->trunk_tune_group_calls = 1; } if (c == 70) //'F' key - toggle agressive sync/crc failure/ras { if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1; else opts->aggressive_framesync = 0; } if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc. { //dmr trunking/ncurses stuff state->dmr_rest_channel = -1; //init on -1 state->dmr_mfid = -1; // //dmr mfid branding and site parms sprintf(state->dmr_branding_sub, "%s", ""); sprintf(state->dmr_branding, "%s", ""); sprintf (state->dmr_site_parms, "%s", ""); //DMR Location Area - DMRLA B***S*** opts->dmr_dmrla_is_set = 0; opts->dmr_dmrla_n = 0; //reset NXDN info state->nxdn_location_site_code = 0; state->nxdn_location_sys_code = 0; sprintf (state->nxdn_location_category, "%s", " "); state->nxdn_last_ran = -1; //0 state->nxdn_ran = 0; //0 state->nxdn_rcn = 0; state->nxdn_base_freq = 0; state->nxdn_step = 0; state->nxdn_bw = 0; } //Debug/Troubleshooting Option if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z) { // opts->p25_is_tuned = 0; state->last_cc_sync_time = 0; state->last_vc_sync_time = 0; noCarrier(opts, state); } //attempt retry to TCP Audio server if (c == 56) // '8' key, try audio in type 8 (TCP Audio Server connection) using defaults OR whatever the user last specified { opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno); if (opts->tcp_sockfd != 0) { //reset audio input stream opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); opts->audio_in_file_info->samplerate=opts->wav_sample_rate; opts->audio_in_file_info->channels=1; opts->audio_in_file_info->seekable=0; opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE; opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0); if(opts->tcp_file_in == NULL) { fprintf(stderr, "Error, couldn't Connect to TCP with libsndfile: %s\n", sf_strerror(NULL)); } else { //close pulse input if it is currently open if (opts->audio_in_type == 0) closePulseInput(opts); fprintf (stderr, "TCP Socket Connected Successfully.\n"); opts->audio_in_type = 8; } } else fprintf (stderr, "TCP Socket Connection Error.\n"); } if (c == 57) //'9' key, try rigctl connection with default values { //use same or last specified host for TCP audio sink for connection memcpy (opts->rigctlhostname, opts->tcp_hostname, sizeof (opts->rigctlhostname) ); opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno); if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1; else opts->use_rigctl = 0; } //if trunking and user wants to just go back to the control channel and skip this call if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && c == 67) //Capital C key - Return to CC { //extra safeguards due to sync issues with NXDN memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); memset (state->active_channel, 0, sizeof(state->active_channel)); //reset dmr blocks dmr_reset_blocks (opts, state); //zero out additional items state->lasttg = 0; state->lasttgR = 0; state->lastsrc = 0; state->lastsrcR = 0; state->payload_algid = 0; state->payload_algidR = 0; state->payload_keyid = 0; state->payload_keyidR = 0; state->payload_mi = 0; state->payload_miR = 0; state->payload_miP = 0; state->payload_miN = 0; opts->p25_is_tuned = 0; state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0; //tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice //RIGCTL if (opts->p25_trunk == 1 && opts->use_rigctl == 1) { if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); SetFreq(opts->rigctl_sockfd, state->p25_cc_freq); } //rtl #ifdef USE_RTLSDR if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq); #endif state->last_cc_sync_time = time(NULL); //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } //if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate if (state->p25_cc_is_tdma == 1) { state->samplesPerSymbol = 8; state->symbolCenter = 3; } fprintf (stderr, "\n User Activated Return to CC; \n "); } //if trunking or scanning, manually cycle forward through channels loaded (can be run without trunking or scanning enabled) if ( (opts->use_rigctl == 1 || opts->audio_in_type == 3) && c == 76) //Capital L key - Cycle Channels Forward { //extra safeguards due to sync issues with NXDN memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); memset (state->active_channel, 0, sizeof(state->active_channel)); //reset dmr blocks dmr_reset_blocks (opts, state); //zero out additional items state->lasttg = 0; state->lasttgR = 0; state->lastsrc = 0; state->lastsrcR = 0; state->payload_algid = 0; state->payload_algidR = 0; state->payload_keyid = 0; state->payload_keyidR = 0; state->payload_mi = 0; state->payload_miR = 0; state->payload_miP = 0; state->payload_miN = 0; opts->p25_is_tuned = 0; state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0; //just copy and pasted the cycle logic for CC/signal hunting on no sync if (state->lcn_freq_roll >= state->lcn_freq_count) //fixed this to skip the extra wait out at the end of the list { state->lcn_freq_roll = 0; //reset to zero } //roll an extra value up if the current is the same as what's already loaded -- faster hunting on Cap+, etc if (state->lcn_freq_roll != 0) { if (state->trunk_lcn_freq[state->lcn_freq_roll-1] == state->trunk_lcn_freq[state->lcn_freq_roll]) { state->lcn_freq_roll++; //check roll again if greater than expected, then go back to zero if (state->lcn_freq_roll >= state->lcn_freq_count) { state->lcn_freq_roll = 0; //reset to zero } } } //check that we have a non zero value first, then tune next frequency if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0) { //rigctl if (opts->use_rigctl == 1) { if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]); } //rtl if (opts->audio_in_type == 3) { #ifdef USE_RTLSDR rtl_dev_tune (opts, state->trunk_lcn_freq[state->lcn_freq_roll]); #endif } fprintf (stderr, "\n User Activated Channel Cycle;"); fprintf (stderr, " Tuning to Frequency: %.06lf MHz\n", (double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000); } state->lcn_freq_roll++; state->last_cc_sync_time = time(NULL); //may need to test to see if we want to do the conditional below or not for symbol rate flipping //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } //if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate if (state->p25_cc_is_tdma == 1) { state->samplesPerSymbol = 8; state->symbolCenter = 3; } } if (c == 118 && opts->audio_in_type == 3) //'v' key, cycle rtl volume multiplier, when active { if (opts->rtl_volume_multiplier == 1 || opts->rtl_volume_multiplier == 2) opts->rtl_volume_multiplier++; else opts->rtl_volume_multiplier = 1; } if (c == 86) // 'V' Key, toggle LPF { if (opts->use_lpf == 0) opts->use_lpf = 1; else opts->use_lpf = 0; } if (c == 66) // 'B' Key, toggle HPF { if (opts->use_hpf == 0) opts->use_hpf = 1; else opts->use_hpf = 0; } if (c == 78) // 'N' Key, toggle PBF { if (opts->use_pbf == 0) opts->use_pbf = 1; else opts->use_pbf = 0; } if (c == 72) // 'H' Key, toggle HPF on digital { if (opts->use_hpf_d == 0) opts->use_hpf_d = 1; else opts->use_hpf_d = 0; } if (opts->m17encoder == 1 && c == 92) //'\' key - toggle M17 encoder Encode + TX { if (state->m17encoder_tx == 0) state->m17encoder_tx = 1; else state->m17encoder_tx = 0; //flag on the EOT marker to send last frame after toggling encoder to zero if (state->m17encoder_tx == 0) state->m17encoder_eot = 1; } if(opts->frame_provoice == 1 && c == 65) //'A' Key, toggle ESK mask 0xA0 { if (state->esk_mask == 0) state->esk_mask = 0xA0; else state->esk_mask = 0; } if(opts->frame_provoice == 1 && c == 83) //'S' Key, toggle STD or EA mode and reset { if (state->ea_mode == -1) state->ea_mode = 0; else if (state->ea_mode == 0) state->ea_mode = 1; else state->ea_mode = 0; //reset -- test to make sure these don't do weird things when reset state->edacs_site_id = 0; state->edacs_lcn_count = 0; state->edacs_cc_lcn = 0; state->edacs_vc_lcn = 0; state->edacs_tuned_lcn = -1; state->edacs_vc_call_type = 0; state->p25_cc_freq = 0; opts->p25_is_tuned = 0; state->lasttg = 0; state->lastsrc = 0; } //anything with an entry box will need the inputs and outputs stopped first //so probably just write a function to handle c input, and when c = certain values //needing an entry box, then stop all of those //allocated memory pointer needs to be free'd each time //if issues arise, just delete this line. //TODO: Redo this in edacs and file, making a seperate char * timestr instead of calling GetTime //directly from the sprintf command free (timestr); } //end ncursesPrinter void ncursesClose () { endwin(); }