From c39ddbc7a76f4d38277fe2904e6d37f73326cc6b Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Sat, 27 Jan 2024 16:54:01 -0500 Subject: [PATCH] P25p1 MFID90 Channel User; TG Hold CLI; DMR BS Stablilization and LE Fix; Updated Patches; OSS Jank Fix; Ncurses Keyboard Shortcuts for Return to CC and Manual Channel Cycling; Misc; --- examples/Example_Usage.md | 7 +- include/dsd.h | 2 +- patch/DMR_MONO_MODE_20240201.patch | 51 +++ ...file_fixes_w_custom_wav_dir_20240201.patch | 425 ++++++++++++++++++ src/dmr_bs.c | 64 ++- src/dmr_csbk.c | 7 +- src/dmr_data.c | 4 +- src/dsd_main.c | 12 +- src/dsd_mbe.c | 6 + src/dsd_ncurses.c | 154 +++++++ src/dsd_symbol.c | 13 +- src/dstar.c | 2 +- src/p25_lcw.c | 18 + src/p25p2_frame.c | 4 + 14 files changed, 746 insertions(+), 23 deletions(-) create mode 100644 patch/DMR_MONO_MODE_20240201.patch create mode 100644 patch/g_dmr_per_call_wav_file_fixes_w_custom_wav_dir_20240201.patch diff --git a/examples/Example_Usage.md b/examples/Example_Usage.md index fdfeb89..959c52e 100644 --- a/examples/Example_Usage.md +++ b/examples/Example_Usage.md @@ -196,8 +196,11 @@ Z - Simulate NoCarrier/No VC/CC sync (capital Z) ! - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified @ - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified -k - Hold TG in Slot 1 or Conventional, or clear current hold (Testing/WIP: DMR T3 Only) -l - Hold TG in Slot 2 on TDMA Systems, or clear current hold (Testing/WIP: DMR T3 Only) +k - Hold TG in Slot 1 or Conventional, or clear current hold +l - Hold TG in Slot 2 on TDMA Systems, or clear current hold + +C - Drop Call and Return to CC during trunking operation +L - Manual Cycle Forward Channel Tuned when RIGCTL or using RTL input and channel csv loaded ``` diff --git a/include/dsd.h b/include/dsd.h index 0b47dee..535f5ee 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -731,7 +731,7 @@ typedef struct int keyloader; //let us know the keyloader is active //dmr late entry mi - uint64_t late_entry_mi_fragment[2][7][3]; + uint64_t late_entry_mi_fragment[2][8][3]; //dmr manufacturer branding and sub_branding (i.e., Motorola and Con+) char dmr_branding[20]; diff --git a/patch/DMR_MONO_MODE_20240201.patch b/patch/DMR_MONO_MODE_20240201.patch new file mode 100644 index 0000000..5403520 --- /dev/null +++ b/patch/DMR_MONO_MODE_20240201.patch @@ -0,0 +1,51 @@ +diff --git a/src/dmr_pi.c b/src/dmr_pi.c +index 55dfb83..33fb3ba 100644 +--- a/src/dmr_pi.c ++++ b/src/dmr_pi.c +@@ -14,6 +14,9 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC + { + UNUSED2(opts, CRCCorrect); + ++ //force slot to 0 if using dmr mono handling ++ if (opts->dmr_mono == 1) state->currentslot = 0; ++ + if((IrrecoverableErrors == 0)) + { + +diff --git a/src/dsd_frame.c b/src/dsd_frame.c +index 3b2a3e1..ba32618 100644 +--- a/src/dsd_frame.c ++++ b/src/dsd_frame.c +@@ -160,7 +160,8 @@ processFrame (dsd_opts * opts, dsd_state * state) + sprintf (state->slot2light, " slot2 "); + //we can safely open MBE on any MS or mono handling + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state); +- if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state); ++ // if (opts->p25_trunk == 0) //line disabled to allow mono mode while trunking ++ dmrMSBootstrap (opts, state); + } + if (opts->dmr_mono == 1 && state->synctype == 32) + { +diff --git a/src/dsd_main.c b/src/dsd_main.c +index 7be5912..8db6dc3 100644 +--- a/src/dsd_main.c ++++ b/src/dsd_main.c +@@ -2302,13 +2302,13 @@ main (int argc, char **argv) + state.rf_mod = 0; // + opts.pulse_digi_rate_out = 8000; + opts.pulse_digi_out_channels = 2; +- opts.dmr_mono = 0; +- opts.dmr_stereo = 1; ++ opts.dmr_mono = 1; ++ opts.dmr_stereo = 0; //not sure if this will break anything + state.dmr_stereo = 0; //0 + // opts.setmod_bw = 7000; +- sprintf (opts.output_name, "DMR Stereo"); +- fprintf (stderr,"-fr / DMR Mono switch has been deprecated.\n"); +- fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n"); ++ sprintf (opts.output_name, "DMR Mono"); ++ // fprintf (stderr,"-fr / DMR Mono switch enabled. \n NOTE: Some ENC options in Slot 2 may not work properly.\n"); ++ fprintf (stderr,"\n Decoding DMR Stereo BS/MS Simplex in Mono Single Slot Only Configuration.\n"); + + } + else if (optarg[0] == 'm') diff --git a/patch/g_dmr_per_call_wav_file_fixes_w_custom_wav_dir_20240201.patch b/patch/g_dmr_per_call_wav_file_fixes_w_custom_wav_dir_20240201.patch new file mode 100644 index 0000000..61b4508 --- /dev/null +++ b/patch/g_dmr_per_call_wav_file_fixes_w_custom_wav_dir_20240201.patch @@ -0,0 +1,425 @@ +diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c +index f1db2e8..0658637 100644 +--- a/src/dmr_csbk.c ++++ b/src/dmr_csbk.c +@@ -424,6 +424,25 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 + //rigctl + if (opts->use_rigctl == 1) + { ++ if (state->currentslot == 0) ++ { ++ //close any perCall wav files that are open ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL) ++ { ++ closeWavOutFileL (opts, state); ++ opts->wav_out_f = NULL; ++ } ++ } ++ else if (state->currentslot == 1) ++ { ++ //close any perCall wav files that are open ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL) ++ { ++ closeWavOutFileR (opts, state); ++ opts->wav_out_fR = NULL; ++ } ++ } ++ + //Guess I forgot to add this condition here + if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq) + dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away from current frequency +@@ -443,6 +462,26 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 + else if (opts->audio_in_type == 3) + { + #ifdef USE_RTLSDR ++ ++ if (state->currentslot == 0) ++ { ++ //close any perCall wav files that are open ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL) ++ { ++ closeWavOutFileL (opts, state); ++ opts->wav_out_f = NULL; ++ } ++ } ++ else if (state->currentslot == 1) ++ { ++ //close any perCall wav files that are open ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL) ++ { ++ closeWavOutFileR (opts, state); ++ opts->wav_out_fR = NULL; ++ } ++ } ++ + //Guess I forgot to add this condition here + uint32_t tempf = (uint32_t)state->p25_cc_freq; + if (opts->rtlsdr_center_freq != tempf) +diff --git a/src/dmr_flco.c b/src/dmr_flco.c +index ecfa70e..653b75d 100644 +--- a/src/dmr_flco.c ++++ b/src/dmr_flco.c +@@ -10,6 +10,38 @@ + *-----------------------------------------------------------------------------*/ + + #include "dsd.h" ++//I really just need to make ONE consolidated date and time function that works correctly ++char * getDateFLC(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; ++} ++ ++//fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b ++char * getTimeFLC(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; ++} + + //combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings + void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type) +@@ -304,6 +336,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C + state->dmr_so = so; + state->lasttg = target; + state->lastsrc = source; ++ char * timestr; ++ timestr = getTimeFLC(); ++ //open wav file here if not already opened ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f == NULL) ++ { ++ sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateFLC(), timestr, state->dmr_color_code, target, source); ++ openWavOutFileL (opts, state); ++ } + } + if (state->currentslot == 1) + { +@@ -311,6 +351,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C + state->dmr_soR = so; + state->lasttgR = target; + state->lastsrcR = source; ++ char * timestr; ++ timestr = getTimeFLC(); ++ //open wav file here if not already opened ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR == NULL) ++ { ++ sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateFLC(), timestr, state->dmr_color_code, target, source); ++ openWavOutFileR (opts, state); ++ } + } + + //update cc amd vc sync time for trunking purposes (particularly Con+) +@@ -337,6 +385,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C + //reset gain + if (opts->floating_point == 1) + state->aout_gain = opts->audio_gain; ++ //close any perCall wav files that are open ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL) ++ { ++ closeWavOutFileL (opts, state); ++ opts->wav_out_f = NULL; ++ } + } + if (state->currentslot == 1) + { +@@ -350,6 +404,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C + //reset gain + if (opts->floating_point == 1) + state->aout_gainR = opts->audio_gain; ++ //close any perCall wav files that are open ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL) ++ { ++ closeWavOutFileR (opts, state); ++ opts->wav_out_fR = NULL; ++ } + } + + } +diff --git a/src/dsd_file.c b/src/dsd_file.c +index 67607e5..dae7862 100644 +--- a/src/dsd_file.c ++++ b/src/dsd_file.c +@@ -563,6 +563,19 @@ void closeWavOutFile (dsd_opts * opts, dsd_state * state) + UNUSED(state); + + sf_close(opts->wav_out_f); ++ char shell[2065], newfilename[1032]; ++ int result; ++ sprintf (newfilename, "%s.wav", opts->wav_out_file); ++#ifdef AERO_BUILD ++ result = rename (opts->wav_out_file, newfilename); ++ UNUSED(shell); ++#else ++ sprintf (shell, "mv '%s' '%s'", opts->wav_out_file, newfilename); ++ result = system (shell); ++#endif ++ // fprintf (stderr, "\n Close WAV FileF %s; Result: %d \n", newfilename, result); ++ UNUSED(result); ++ + } + + void closeWavOutFileL (dsd_opts * opts, dsd_state * state) +@@ -570,6 +583,19 @@ void closeWavOutFileL (dsd_opts * opts, dsd_state * state) + UNUSED(state); + + sf_close(opts->wav_out_f); ++ char shell[2065], newfilename[1032]; ++ int result; ++ sprintf (newfilename, "%s.wav", opts->wav_out_file); ++#ifdef AERO_BUILD ++ result = rename (opts->wav_out_file, newfilename); ++ UNUSED(shell); ++#else ++ sprintf (shell, "mv '%s' '%s'", opts->wav_out_file, newfilename); ++ result = system (shell); ++#endif ++ // fprintf (stderr, "\n Close WAV FileL %s; Result: %d \n", newfilename, result); ++ UNUSED(result); ++ + } + + void closeWavOutFileR (dsd_opts * opts, dsd_state * state) +@@ -577,6 +603,18 @@ void closeWavOutFileR (dsd_opts * opts, dsd_state * state) + UNUSED(state); + + sf_close(opts->wav_out_fR); ++ char shell[2065], newfilename[1032]; ++ int result; ++ sprintf (newfilename, "%s.wav", opts->wav_out_fileR); ++#ifdef AERO_BUILD ++ result = rename (opts->wav_out_fileR, newfilename); ++ UNUSED(shell); ++#else ++ sprintf (shell, "mv '%s' '%s'", opts->wav_out_fileR, newfilename); ++ result = system (shell); ++#endif ++ // fprintf (stderr, "\n Close WAV FileR %s; Result: %d \n", newfilename, result); ++ UNUSED(result); + } + + void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state) +diff --git a/src/dsd_main.c b/src/dsd_main.c +index e1a3a3d..26b256d 100644 +--- a/src/dsd_main.c ++++ b/src/dsd_main.c +@@ -107,6 +107,19 @@ void + noCarrier (dsd_opts * opts, dsd_state * state) + { + ++ //close any perCall wav files that are open ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL) ++ { ++ closeWavOutFileL (opts, state); ++ opts->wav_out_f = NULL; ++ } ++ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL) ++ { ++ closeWavOutFileR (opts, state); ++ opts->wav_out_fR = NULL; ++ } ++ //end perCall wav file close ++ + #ifdef AERO_BUILD + //TODO: Investigate why getSymbol needs to be run first in this context...truly confused here + if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5 +@@ -1568,9 +1581,9 @@ main (int argc, char **argv) + } + + #ifdef AERO_BUILD +- fprintf (stderr, "Build Version: AW (20231015) \n"); ++ fprintf (stderr, "Build Version: AW (20231214) G Build\n"); + #else +- fprintf (stderr, "Build Version: AW %s \n", GIT_TAG); ++ fprintf (stderr, "Build Version: AW %s G Build\n", GIT_TAG); + #endif + fprintf (stderr,"MBElib Version: %s\n", versionstr); + +diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c +index 9f609ca..f23209c 100644 +--- a/src/dsd_mbe.c ++++ b/src/dsd_mbe.c +@@ -1191,7 +1191,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a + if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) + { + //write wav to per call on left channel Slot 1 +- writeSynthesizedVoice (opts, state); ++ if (opts->wav_out_f != NULL) ++ writeSynthesizedVoice (opts, state); + } + } + +@@ -1201,7 +1202,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a + if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) + { + //write wav to per call on right channel Slot 2 +- writeSynthesizedVoiceR (opts, state); ++ if (opts->wav_out_fR != NULL) ++ writeSynthesizedVoiceR (opts, state); + } + } + +diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c +index eb070af..f45b5bf 100644 +--- a/src/dsd_ncurses.c ++++ b/src/dsd_ncurses.c +@@ -999,7 +999,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) + if (choicec == 12) + { + //flesh out all closewavs and sprint "" wav filenames +- closeWavOutFile (opts, state); ++ // closeWavOutFile (opts, state); + closeWavOutFileL (opts, state); + closeWavOutFileR (opts, state); + //closeWavOutFileRaw (opts, state); +@@ -2063,6 +2063,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + 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 ++ if (opts->wav_out_f != NULL) + 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 +@@ -2105,13 +2106,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + 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->dmr_stereo_wav == 1 && rd != 0 && tg != 0) ++ // { ++ // //close old first, assign name based on time and radio, open wav file ++ // if (opts->wav_out_f != NULL) ++ // 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) + { +@@ -2126,7 +2128,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + } + + //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) ) ++ 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++) +@@ -2147,14 +2149,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + 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->dmr_stereo_wav == 1 && rd != 0 && tg != 0) ++ // { ++ // //close old first, assign name based on time and radio, open wav file ++ // if (opts->wav_out_f != NULL) ++ // closeWavOutFileL (opts, state); ++ // sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d", 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) + { +@@ -2190,20 +2192,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + 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->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0) ++ // { ++ // //close old first, assign name based on time and radio, open wav file ++ // if (opts->wav_out_fR != NULL) ++ // closeWavOutFileR (opts, state); ++ // sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d", 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 +- } ++ // 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", ""); +@@ -2275,7 +2278,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + if (opts->ncurses_compact == 1) + { + printw ("------------------------------------------------------------------------------\n"); +- printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231015)"); ++ printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231214)"); + printw ("------------------------------------------------------------------------------\n"); + } + #elif LIMAZULUTWEAKS +@@ -2313,13 +2316,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + 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"); ++ if (i == 5) printw (" %s ", "G Build"); ++ if (i == 6) printw (" AW (20231214) \n"); + #elif ZDEV_BUILD +- if (i == 5) printw (" %s ", "AW "); ++ if (i == 5) printw (" %s ", "AW G Build"); + if (i == 6) printw (" %s \n", GIT_TAG); + #else +- if (i == 5) printw (" %s ", "AW "); ++ if (i == 5) printw (" %s ", "AW G Build"); + if (i == 6) printw (" %s \n", GIT_TAG); + #endif + else printw ("\n"); +@@ -3914,7 +3917,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + 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); ++ // closeWavOutFile (opts, state); + closeWavOutFileL (opts, state); + closeWavOutFileR (opts, state); + sprintf (opts->wav_out_file, "%s", ""); diff --git a/src/dmr_bs.c b/src/dmr_bs.c index 0ca219b..df78474 100644 --- a/src/dmr_bs.c +++ b/src/dmr_bs.c @@ -75,8 +75,18 @@ void dmrBS (dsd_opts * opts, dsd_state * state) //Init the color code status state->color_code_ok = 0; - vc1 = 2; - vc2 = 2; + //if coming from the bootsrap, then the slot will still be assigned the last value + //we want to set only that vc value to 2, the other to 7 + if (state->currentslot == 0) + { + vc1 = 2; + vc2 = 7; + } + if (state->currentslot == 1) + { + vc1 = 7; + vc2 = 2; + } short int loop = 1; short int skipcount = 0; @@ -273,7 +283,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } else fprintf (stderr,"Sync: -DMR "); - vc1 = 1; + vc1 = 7; //set to 7 so we can see that we should not be on a VC unless a framesync comes in for it first //close MBEout file - slot 1 if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state); @@ -286,7 +296,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } else fprintf (stderr,"Sync: -DMR "); - vc2 = 1; + vc2 = 7; //set to 7 so we can see that we should not be on a VC unless a framesync comes in for it first //close MBEout file - slot 2 if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state); @@ -297,7 +307,49 @@ void dmrBS (dsd_opts * opts, dsd_state * state) goto SKIP; } - //only play voice on no data sync + //check to see if we are expecting a VC at this point vc > 7 + if (strcmp (sync, DMR_BS_DATA_SYNC) != 0 && internalslot == 0 && vc1 > 6) + { + fprintf (stderr,"%s ", getTime()); + + //simplifying things + char polarity[3]; + char light[18]; + + sprintf (light, "%s", " [SLOT1] slot2 "); + fprintf (stderr,"Sync: %sDMR %s", polarity, light); + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "| Frame Sync Err: %d", vc1); + fprintf (stderr, "%s", KNRM); + fprintf (stderr, "\n"); + vc1++; + //this should give it enough time to find the next frame sync pattern, if it exists, if not, then trigger a resync + if ( vc1 > 13 ) goto END; + else goto SKIP; + } + + //check to see if we are expecting a VC at this point vc > 7 + if (strcmp (sync, DMR_BS_DATA_SYNC) != 0 && internalslot == 1 && vc2 > 6) + { + fprintf (stderr,"%s ", getTime()); + + //simplifying things + char polarity[3]; + char light[18]; + + sprintf (light, "%s", " slot1 [SLOT2] "); + fprintf (stderr,"Sync: %sDMR %s", polarity, light); + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "| Frame Sync Err: %d", vc2); + fprintf (stderr, "%s", KNRM); + fprintf (stderr, "\n"); + vc2++; + //this should give it enough time to find the next frame sync pattern, if it exists, if not, then trigger a resync + if ( vc2 > 13 ) goto END; + else goto SKIP; + } + + //only play voice on no data sync, and VC values are within expected values 1-6 if (strcmp (sync, DMR_BS_DATA_SYNC) != 0) //we already have a tact ecc check, so we won't get here without that, see if there is any other eccs we can run just to make sure { @@ -430,7 +482,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state); if (internalslot == 1 && vc2 == 6) dmr_alg_refresh (opts, state); - dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3); + dmr_late_entry_mi_fragment (opts, state, vc%7, m1, m2, m3); //increment the vc counters if (internalslot == 0) vc1++; diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c index 2641080..78045d8 100644 --- a/src/dmr_csbk.c +++ b/src/dmr_csbk.c @@ -13,7 +13,7 @@ *-----------------------------------------------------------------------------*/ #include "dsd.h" - +#define PCLEAR_TUNE_AWAY //disable if slower return is preferred //function for handling Control Signalling PDUs (CSBK, MBC) messages void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors) { @@ -297,6 +297,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 SetFreq(opts->rigctl_sockfd, freq); state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq; opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop + state->last_vc_sync_time = time(NULL); //set here so a random p_clear on the opposite slot doesn't send us back to the CC } @@ -324,6 +325,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 rtl_dev_tune (opts, freq); state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq; opts->p25_is_tuned = 1; + state->last_vc_sync_time = time(NULL); //set here so a random p_clear on the opposite slot doesn't send us back to the CC #endif } @@ -395,7 +397,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 //initial line break fprintf (stderr, "\n"); fprintf (stderr, " Clear (P_CLEAR) %d", clear); - + #ifdef PCLEAR_TUNE_AWAY //check to see if this is a dummy csbk sent from link control to signal return to tscc if (clear && csbk_fid == 255) fprintf (stderr, " No Encrypted Call Trunking; Return to CC; "); if (!clear && csbk_fid == 255) fprintf (stderr, " No Encrypted Call Trunking; Other Slot Busy; "); @@ -461,6 +463,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 } } + #endif } //(P_PROTECT) diff --git a/src/dmr_data.c b/src/dmr_data.c index d4479f0..006fb50 100644 --- a/src/dmr_data.c +++ b/src/dmr_data.c @@ -336,7 +336,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state) if (opts->setmod_bw != 0) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); SetFreq(opts->rigctl_sockfd, state->p25_cc_freq); //debug - fprintf (stderr, " Con+ Timeout; Return to CC;"); + fprintf (stderr, " Con+ Timeout; Return to CC; \n"); } else if (opts->audio_in_type == 3) //rtl_fm tuning @@ -344,7 +344,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state) #ifdef USE_RTLSDR rtl_dev_tune(opts, state->p25_cc_freq); //debug - fprintf (stderr, " Con+ Timeout; Return to CC;"); + fprintf (stderr, " Con+ Timeout; Return to CC; \n"); #endif } opts->p25_is_tuned = 0; diff --git a/src/dsd_main.c b/src/dsd_main.c index 1d2616b..ebbf643 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -1349,7 +1349,7 @@ usage () printf (" -G Import Group List Allow/Block and Label from csv file.\n"); printf (" (See group.csv for example)\n"); printf (" -T Enable Trunking Features (NXDN/P25/EDACS/DMR) with RIGCTL/TCP or RTL Input\n"); - printf (" -Y Enable Scanning Mode with RIGCTL/TCP or RTL Input (Lower z) \n"); + printf (" -Y Enable Scanning Mode with RIGCTL/TCP or RTL Input \n"); printf (" Experimental -- Can only scan for sync with enabled decoders, don't mix NXDN and DMR/P25!\n"); printf (" This is not a Trunking Feature, just scans through conventional frequencies fast!\n"); printf (" -W Use Imported Group List as a Trunking Allow/White List -- Only Tune with Mode A\n"); @@ -1357,7 +1357,7 @@ usage () printf (" -E Disable Tune to Group Calls (DMR TIII, Con+, Cap+, P25, NXDN Type-C, and Type-D)\n"); printf (" -e Enable Tune to Data Calls (DMR TIII, Cap+, NXDN Type-C)\n"); printf (" (NOTE: No Clear Distinction between Cap+ Private Voice Calls and Data Calls -- Both enabled with Data Calls \n"); - printf (" (NOTE: P25 Data Channels Not Enabled (no handling) \n"); + printf (" -I Specify TG to Hold During Trunking (DMR, P25, NXDN Type-C Trunking)\n"); printf (" -U Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)\n"); printf (" -B Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)\n"); printf (" P25 - 12000; NXDN48 - 7000; NXDN96: 12000; DMR - 7000-12000; EDACS/PV - 12000-24000;\n"); //redo this, or check work, or whatever @@ -1586,7 +1586,7 @@ main (int argc, char **argv) exitflag = 0; - while ((c = getopt (argc, argv, "yhaepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89Ek:")) != -1) + while ((c = getopt (argc, argv, "yhaepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89Ek:I:")) != -1) { opterr = 0; switch (c) @@ -1609,6 +1609,12 @@ main (int argc, char **argv) //NOTE: The 'K' option for single BP key has been swapped to 'b' //'K' is now used for hexidecimal key.csv imports + //specify TG Hold value + case 'I': + sscanf (optarg, "%d", &state.tg_hold); + fprintf (stderr, "TG Hold set to %d \n", state.tg_hold); + break; + case '9': //This is a temporary fix for RR issue until a permanent fix can be found state.ea_mode = 0; fprintf (stderr,"Force Enabling EDACS Standard/Networked Mode Mode\n"); diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index 9f609ca..cc3a928 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -1077,6 +1077,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a { if ( opts->floating_point == 0 ) //opts->audio_out == 1 && //needed to remove for AERO OSS so we could still save wav files during dual voices { + #ifdef AERO_BUILD + if(opts->audio_out == 1 && opts->slot1_on == 1) //add conditional check here, otherwise some lag occurs on dual voices with OSS48k/1 input due to buffered audio + #endif processAudio(opts, state); } if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot1_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible @@ -1151,6 +1154,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a { if ( opts->floating_point == 0) //opts->audio_out == 1 && //needed to remove for AERO OSS so we could still save wav files during dual voices { + #ifdef AERO_BUILD + if(opts->audio_out == 1 && opts->slot2_on == 1) //add conditional check here, otherwise some lag occurs on dual voices with OSS48k/1 input due to buffered audio + #endif processAudioR(opts, state); } if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot2_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index 4646e77..e094f07 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -2533,8 +2533,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) 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: "); @@ -4195,6 +4198,157 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) 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 + //RIGCTL + if (opts->p25_trunk == 1 && opts->use_rigctl == 1) SetFreq(opts->rigctl_sockfd, state->p25_cc_freq); + + //rtl + #ifdef USE_RTLSDR + if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq); + #endif + + state->last_cc_sync_time = time(NULL); + + //if P25p2 VCH and going back to P25p1 CC, flip symbolrate + if (state->p25_cc_is_tdma == 0) + { + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + } + + //if 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; + } + + } + //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 diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c index c032b46..a4da20c 100644 --- a/src/dsd_symbol.c +++ b/src/dsd_symbol.c @@ -264,16 +264,17 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) } + //BUG REPORT: 1. DMR Simplex doesn't work with raw wav files. 2. Using the monitor w/ wav file saving may produce undecodable wav files. //reworked a bit to allow raw audio wav file saving without the monitoring poriton active if (have_sync == 0) { //do an extra checkfor carrier signal so that random raw audio spurts don't play during decoding - if ( (state->carrier == 1) && ((time(NULL) - state->last_vc_sync_time) < 2)) - { - memset (state->analog_out, 0, sizeof(state->analog_out)); - state->analog_sample_counter = 0; - } + // if ( (state->carrier == 1) && ((time(NULL) - state->last_vc_sync_time) < 2)) /This probably doesn't work correctly since we update time check when playing raw audio + // { + // memset (state->analog_out, 0, sizeof(state->analog_out)); + // state->analog_sample_counter = 0; + // } //This is the root cause of issue listed above, will evaluate further at a later time for a more elegant solution, or determine if anything is negatively impacted by removing this //sanity check to prevent an overflow if (state->analog_sample_counter > 959) @@ -295,7 +296,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) // state->analog_out[x] /= 4; //seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise - if ( (opts->rtl_rms > opts->rtl_squelch_level) && (opts->monitor_input_audio == 1) ) + if ( (opts->rtl_rms > opts->rtl_squelch_level) && opts->monitor_input_audio == 1 && state->carrier == 0 ) //added carrier check here in lieu of disabling it above { if (opts->audio_out_type == 0) pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL); diff --git a/src/dstar.c b/src/dstar.c index af5baf1..c41c1fd 100644 --- a/src/dstar.c +++ b/src/dstar.c @@ -328,7 +328,7 @@ void processDSTAR_SD(dsd_opts * opts, dsd_state * state, uint8_t * sd) fprintf (stderr, "; "); //Got the feeling nobody will actually ever see this message, but who knows - fprintf(stderr, "\n DEV NOTE: If you see this message, but incorrect lat/lon,\n please submit samples to https://github.com/lwvmobile/dsd-fme/issues/164 "); + // fprintf(stderr, "\n DEV NOTE: If you see this message, but incorrect lat/lon,\n please submit samples to https://github.com/lwvmobile/dsd-fme/issues/164 "); SKIP: ; //do nothing diff --git a/src/p25_lcw.c b/src/p25_lcw.c index cd93f5f..625ae2f 100644 --- a/src/p25_lcw.c +++ b/src/p25_lcw.c @@ -406,10 +406,28 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir } else if (lc_mfid == 0x90 && lc_opcode == 0x0) + { + //needed to fill this in, since tuning this on P1 will just leave the TG/SRC as zeroes fprintf (stderr, " MFID90 (Moto) Group Regroup Channel User (LCGRGR)"); + uint32_t sg = (uint32_t)ConvertBitIntoBytes(&LCW_bits[32], 16); + uint32_t src = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24); + fprintf (stderr, " SG: %d; SRC: %d;", sg, src); + if (LCW_bits[16] == 1) fprintf (stderr, " Res;"); //res bit (octet 2) + if (LCW_bits[17] == 1) fprintf (stderr, " ENC;"); //P-bit (octet 2) + if (LCW_bits[31] == 1) fprintf (stderr, " EXT;"); //Full SUID next LC (external) (octet 3) + state->lasttg = sg; + state->lastsrc = src; + } else if (lc_mfid == 0x90 && lc_opcode == 0x1) + { fprintf (stderr, " MFID90 (Moto) Group Regroup Channel Update (LCGRGU)"); + uint32_t sg = (uint32_t)ConvertBitIntoBytes(&LCW_bits[24], 16); + uint32_t ch = (uint32_t)ConvertBitIntoBytes(&LCW_bits[56], 16); + fprintf (stderr, " SG: %d; CH: %04X;", sg, ch); + if (LCW_bits[16] == 1) fprintf (stderr, " Res;"); //res bit (octet 2) + if (LCW_bits[17] == 1) fprintf (stderr, " ENC;"); //P-bit (octet 2) + } else if (lc_mfid == 0x90 && lc_opcode == 0x3) fprintf (stderr, " MFID90 (Moto) Group Regroup Add"); diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c index c391eba..b27b79e 100644 --- a/src/p25p2_frame.c +++ b/src/p25p2_frame.c @@ -845,6 +845,10 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0; memset (state->active_channel, 0, sizeof (state->active_channel)); //zero out here? I think this will be fine } + else if (duid_decoded == 13 && ((time(NULL) - state->last_active_time) > 2) && opts->p25_is_tuned == 0) //should we use && opts->p25_is_tuned == 1? + { + memset (state->active_channel, 0, sizeof (state->active_channel)); //zero out here? I think this will be fine + } if (duid_decoded == 0) {