/*------------------------------------------------------------------------------- * dsd_ncurses_handler.c * DSD-FME ncurses terminal user input handler * * LWVMOBILE * 2025-05 DSD-FME Florida Man Edition *-----------------------------------------------------------------------------*/ #include "dsd.h" uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c) { struct stat st_wav = {0}; // //debug char value // if (c != -1) // fprintf (stderr, "\n User Input: %i / %c ;;", c, c); //TEST: Handle Escape Characters //if issues arise, just go back to the way it was before //this is primarly a fix for scroll wheel activatign the menu //and Windows Powershell right-click doing a copy and paste //and sendign tons of garbage getch chars here and changing things if (c == '\033') { //TODO: Find way to getch all the chars immediately after, or just //run getch in a loop in case of somebody copying and pasting a ton of things accidentally for (int i = 0; i < 100000; i++) //wonder how slow this will be getch(); c = -1; return 1; } //keyboard shortcuts - codes same as ascii codes if (c == 10) //Return / Enter key, open menu 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, cycle history off, short, long { opts->ncurses_history++; opts->ncurses_history %= 3; } if (c == 113) //'q' key, quit { exitflag = 1; } if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr) { if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0; else state->forced_alg_id = 1; } if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry { if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0; else state->forced_alg_id = 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; } else { opts->inverted_dmr = 0; opts->inverted_dpmr = 0; opts->inverted_x2tdma = 0; opts->inverted_ysf = 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 { //for filenames (no colons, etc) char * timestr = getTime(); char * datestr = getDate(); sprintf (opts->symbol_out_file, "%s_%s_dibit_capture.bin", datestr, timestr); openSymbolOutFile (opts, state); //add a system event to echo in the event history state->event_history_s[0].Event_History_Items[0].color_pair = 4; char event_str[2000]; memset (event_str, 0, sizeof(event_str)); sprintf (event_str, "DSD-FME Dibit Capture File Started: %s;", opts->symbol_out_file); watchdog_event_datacall (opts, state, 0xFFFFFF, 0xFFFFFF, event_str, 0); state->lastsrc = 0; //this could wipe a call src if they hit 'R' while call in slot 1 in progress watchdog_event_history(opts, state, 0); watchdog_event_current(opts, state, 0); //allocated memory pointer needs to be free'd if (timestr != NULL) { free (timestr); timestr = NULL; } if (datestr != NULL) { free (datestr); datestr = NULL; } opts->symbol_out_file_creation_time = time(NULL); opts->symbol_out_file_is_auto = 1; } 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); //add a system event to echo in the event history state->event_history_s[0].Event_History_Items[0].color_pair = 4; char event_str[2000]; memset (event_str, 0, sizeof(event_str)); sprintf (event_str, "DSD-FME Dibit Capture File Closed: %s;", opts->symbol_out_file); watchdog_event_datacall (opts, state, 0xFFFFFF, 0xFFFFFF, event_str, 0); state->lastsrc = 0; //this could wipe a call src if they hit 'R' while call in slot 1 in progress watchdog_event_history(opts, state, 0); watchdog_event_current(opts, state, 0); } opts->symbol_out_file_is_auto = 0; } #ifdef __CYGWIN__ //do nothing #else if (c == 32) //'space bar' replay last bin file (rework to do wav files too?) { struct stat stat_buf; if (stat(opts->audio_in_dev, &stat_buf) != 0) { fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); goto SKIPR; } if (S_ISREG(stat_buf.st_mode)) { opts->symbolfile = fopen(opts->audio_in_dev, "r"); opts->audio_in_type = 4; //symbol capture bin files } SKIPR: ; //do nothing } #endif if (c == 80) //'P' key - start per call wav files //TODO: Fix { char wav_file_directory[1024]; sprintf (wav_file_directory, "%s", opts->wav_out_dir); wav_file_directory[1023] = '\0'; if (stat(wav_file_directory, &st_wav) == -1) { fprintf (stderr, "%s wav file directory does not exist\n", wav_file_directory); fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory); mkdir(wav_file_directory, 0700); } fprintf (stderr,"\n Per Call Wav File Enabled to Directory: %s;.\n", opts->wav_out_dir); srand(time(NULL)); //seed random for filenames (so two filenames aren't the exact same datetime string on initailization) opts->wav_out_f = open_wav_file(opts->wav_out_dir, opts->wav_out_file, 8000, 0); opts->wav_out_fR = open_wav_file(opts->wav_out_dir, opts->wav_out_fileR, 8000, 0); opts->dmr_stereo_wav = 1; } if (c == 112) //'p' key - stop all per call wav files //TODO: Fix { //TODO: Add Closing of RAW files as well? opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, &state->event_history_s[0]); opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, &state->event_history_s[1]); opts->wav_out_file[0] = 0; //Bugfix for decoded wav file display after disabling opts->wav_out_fileR[0] = 0; opts->dmr_stereo_wav = 0; } // #ifdef __CYGWIN__ //this might be okay on Aero as well, will need to look into and/or test // #else if (c == 115) //'s' key, stop playing wav or symbol in files { if (opts->symbolfile != NULL) { if (opts->audio_in_type == 4) { fclose(opts->symbolfile); } } if (opts->audio_in_type == 2) //wav input file { sf_close(opts->audio_in_file); } if (opts->audio_out_type == 0) { opts->audio_in_type = 0; openPulseInput(opts); } else opts->audio_in_type = 5; //exitflag = 1; } #endif //makes buzzing sound when locked out in new audio config and short, probably something to do with processaudio running or not running if (state->lasttg != 0 && opts->frame_provoice != 1 && c == 33) //SHIFT+'1' key (exclamation point), lockout slot 1 or conventional tg from tuning/playback during session { state->group_array[state->group_tally].groupNumber = state->lasttg; sprintf (state->group_array[state->group_tally].groupMode, "%s", "B"); sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT"); state->group_tally++; sprintf (state->event_history_s[0].Event_History_Items[0].internal_str, "Target: %d; has been locked out; User Lock Out.", state->lasttg); watchdog_event_current(opts, state, 0); sprintf (state->call_string[0], "%s", " "); //21 spaces //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) { //drop all items (failsafe) noCarrier(opts, state); 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) { //drop all items (failsafe) noCarrier(opts, state); 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++; sprintf (state->event_history_s[1].Event_History_Items[0].internal_str, "Target: %d; has been locked out; User Lock Out.", state->lasttgR); watchdog_event_current(opts, state, 1); sprintf (state->call_string[1], "%s", " "); //21 spaces //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) { //drop all items (failsafe) noCarrier(opts, state); 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) { //drop all items (failsafe) noCarrier(opts, state); rtl_dev_tune (opts, state->p25_cc_freq); } #endif state->last_cc_sync_time = time(NULL); //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } } if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode { if (opts->trunk_use_allow_list == 1) opts->trunk_use_allow_list = 0; else opts->trunk_use_allow_list = 1; } if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls { if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0; else opts->trunk_tune_private_calls = 1; } if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls { if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0; else opts->trunk_tune_data_calls = 1; } if (opts->p25_trunk == 1 && c == 101) //'e' key, toggle tune enc calls (P25 only on certain grants) { if (opts->trunk_tune_enc_calls == 1) opts->trunk_tune_enc_calls = 0; else opts->trunk_tune_enc_calls = 1; } if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls { if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0; else opts->trunk_tune_group_calls = 1; } if (c == 70) //'F' key - toggle agressive sync/crc failure/ras { if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1; else opts->aggressive_framesync = 0; } if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc. { //dmr trunking/ncurses stuff state->dmr_rest_channel = -1; //init on -1 state->dmr_mfid = -1; // //dmr mfid branding and site parms sprintf(state->dmr_branding_sub, "%s", ""); sprintf(state->dmr_branding, "%s", ""); sprintf (state->dmr_site_parms, "%s", ""); //DMR Location Area - DMRLA B***S*** opts->dmr_dmrla_is_set = 0; opts->dmr_dmrla_n = 0; //reset NXDN info state->nxdn_location_site_code = 0; state->nxdn_location_sys_code = 0; sprintf (state->nxdn_location_category, "%s", " "); state->nxdn_last_ran = -1; //0 state->nxdn_ran = 0; //0 state->nxdn_rcn = 0; state->nxdn_base_freq = 0; state->nxdn_step = 0; state->nxdn_bw = 0; } //Debug/Troubleshooting Option if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z) { // opts->p25_is_tuned = 0; state->last_cc_sync_time = 0; state->last_vc_sync_time = 0; noCarrier(opts, state); } if (c == 93) //']' key - increment event history indexer { state->eh_index++; } if (c == 91) //'[' key - decrement event history indexer { state->eh_index--; } if (c == 92) //'\' key - toggle events for slot displayed, and reset eh_index { state->eh_slot ^= 1; state->eh_index = 0; } //attempt retry to TCP Audio server if (c == 56) // '8' key, try audio in type 8 (TCP Audio Server connection) using defaults OR whatever the user last specified { opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno); if (opts->tcp_sockfd != 0) { //reset audio input stream opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); opts->audio_in_file_info->samplerate=opts->wav_sample_rate; opts->audio_in_file_info->channels=1; opts->audio_in_file_info->seekable=0; opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE; opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0); if(opts->tcp_file_in == NULL) { fprintf(stderr, "Error, couldn't Connect to TCP with libsndfile: %s\n", sf_strerror(NULL)); } else { //close pulse input if it is currently open if (opts->audio_in_type == 0) closePulseInput(opts); fprintf (stderr, "TCP Socket Connected Successfully.\n"); opts->audio_in_type = 8; } } else fprintf (stderr, "TCP Socket Connection Error.\n"); } if (c == 57) //'9' key, try rigctl connection with default values { //use same or last specified host for TCP audio sink for connection memcpy (opts->rigctlhostname, opts->tcp_hostname, sizeof (opts->rigctlhostname) ); opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno); if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1; else opts->use_rigctl = 0; } //if trunking and user wants to just go back to the control channel and skip this call if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && c == 67) //Capital C key - Return to CC { //extra safeguards due to sync issues with NXDN memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); memset (state->active_channel, 0, sizeof(state->active_channel)); //reset dmr blocks dmr_reset_blocks (opts, state); //zero out additional items state->lasttg = 0; state->lasttgR = 0; state->lastsrc = 0; state->lastsrcR = 0; state->payload_algid = 0; state->payload_algidR = 0; state->payload_keyid = 0; state->payload_keyidR = 0; state->payload_mi = 0; state->payload_miR = 0; state->payload_miP = 0; state->payload_miN = 0; opts->p25_is_tuned = 0; state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0; //tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice //RIGCTL if (opts->p25_trunk == 1 && opts->use_rigctl == 1) { if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); SetFreq(opts->rigctl_sockfd, state->p25_cc_freq); } //rtl #ifdef USE_RTLSDR if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq); #endif state->last_cc_sync_time = time(NULL); //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } //if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate if (state->p25_cc_is_tdma == 1) { state->samplesPerSymbol = 8; state->symbolCenter = 3; } fprintf (stderr, "\n User Activated Return to CC; \n "); } //if trunking or scanning, manually cycle forward through channels loaded (can be run without trunking or scanning enabled) if ( (opts->use_rigctl == 1 || opts->audio_in_type == 3) && c == 76) //Capital L key - Cycle Channels Forward { //extra safeguards due to sync issues with NXDN memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); memset (state->active_channel, 0, sizeof(state->active_channel)); //reset dmr blocks dmr_reset_blocks (opts, state); //zero out additional items state->lasttg = 0; state->lasttgR = 0; state->lastsrc = 0; state->lastsrcR = 0; state->payload_algid = 0; state->payload_algidR = 0; state->payload_keyid = 0; state->payload_keyidR = 0; state->payload_mi = 0; state->payload_miR = 0; state->payload_miP = 0; state->payload_miN = 0; opts->p25_is_tuned = 0; state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0; //just copy and pasted the cycle logic for CC/signal hunting on no sync if (state->lcn_freq_roll >= state->lcn_freq_count) //fixed this to skip the extra wait out at the end of the list { state->lcn_freq_roll = 0; //reset to zero } //roll an extra value up if the current is the same as what's already loaded -- faster hunting on Cap+, etc if (state->lcn_freq_roll != 0) { if (state->trunk_lcn_freq[state->lcn_freq_roll-1] == state->trunk_lcn_freq[state->lcn_freq_roll]) { state->lcn_freq_roll++; //check roll again if greater than expected, then go back to zero if (state->lcn_freq_roll >= state->lcn_freq_count) { state->lcn_freq_roll = 0; //reset to zero } } } //check that we have a non zero value first, then tune next frequency if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0) { //rigctl if (opts->use_rigctl == 1) { if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]); } //rtl if (opts->audio_in_type == 3) { #ifdef USE_RTLSDR rtl_dev_tune (opts, state->trunk_lcn_freq[state->lcn_freq_roll]); #endif } fprintf (stderr, "\n User Activated Channel Cycle;"); fprintf (stderr, " Tuning to Frequency: %.06lf MHz\n", (double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000); } state->lcn_freq_roll++; state->last_cc_sync_time = time(NULL); //may need to test to see if we want to do the conditional below or not for symbol rate flipping //if P25p2 VCH and going back to P25p1 CC, flip symbolrate if (state->p25_cc_is_tdma == 0) { state->samplesPerSymbol = 10; state->symbolCenter = 4; } //if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate if (state->p25_cc_is_tdma == 1) { state->samplesPerSymbol = 8; state->symbolCenter = 3; } } if (c == 118 && opts->audio_in_type == 3) //'v' key, cycle rtl volume multiplier, when active { if (opts->rtl_volume_multiplier == 1 || opts->rtl_volume_multiplier == 2) opts->rtl_volume_multiplier++; else opts->rtl_volume_multiplier = 1; } if (c == 86) // 'V' Key, toggle LPF { if (opts->use_lpf == 0) opts->use_lpf = 1; else opts->use_lpf = 0; } if (c == 66) // 'B' Key, toggle HPF { if (opts->use_hpf == 0) opts->use_hpf = 1; else opts->use_hpf = 0; } if (c == 78) // 'N' Key, toggle PBF { if (opts->use_pbf == 0) opts->use_pbf = 1; else opts->use_pbf = 0; } if (c == 72) // 'H' Key, toggle HPF on digital { if (opts->use_hpf_d == 0) opts->use_hpf_d = 1; else opts->use_hpf_d = 0; } if(opts->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; } //RTL PPM Manual Adjustment if (c == 125) opts->rtlsdr_ppm_error++; if (c == 123) opts->rtlsdr_ppm_error--; //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 return 0; } //end ncursesPrinter