From 7d6c3dc67cb88349cb7685b6b86771814b650530 Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Thu, 12 May 2022 11:25:41 -0400 Subject: [PATCH] DMR Stereo Inversion Handling DMR Stereo Inversion Handling --Fix frame sync not forwarding inverted signal to DMR Stereo methods --Other Misc Bug Fixes --- src/dmr_bs.c | 24 ++++--- src/dmr_data.c | 51 ++----------- src/dmr_ms.c | 2 +- src/dsd_frame_sync.c | 29 ++++++-- src/dsd_main.c | 168 +++++++++++++++++++++---------------------- 5 files changed, 131 insertions(+), 143 deletions(-) diff --git a/src/dmr_bs.c b/src/dmr_bs.c index fff2fae..1bc78bc 100644 --- a/src/dmr_bs.c +++ b/src/dmr_bs.c @@ -185,6 +185,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } sync[24] = 0; + EmbeddedSignallingOk = -1; if(QR_16_7_6_decode(EmbeddedSignalling)) { @@ -192,9 +193,10 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } internalcolorcode = 69; //set so we know if this value is being set properly - if(EmbeddedSignallingOk == 1) + //state->color_code = 69; + if( EmbeddedSignallingOk == 1 ) //don't set on 1? { - state->color_code = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); + //state->color_code = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); internalcolorcode = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); state->color_code_ok = EmbeddedSignallingOk; @@ -255,7 +257,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } //reset vc counters to 1 if new voice sync frame on each slot - if ( (strcmp (sync, DMR_BS_VOICE_SYNC) == 0) ) + //fixed to compensate for inverted signal + if ( ((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) && opts->inverted_dmr == 0) || ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) && opts->inverted_dmr == 1) ) { if (internalslot == 0) { @@ -268,7 +271,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } //check for sync pattern here after collected the rest of the payload, decide what to do with it - if ( (strcmp (sync, DMR_BS_DATA_SYNC) == 0) ) + //fixed to compensate for inverted signal + if ( ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) && opts->inverted_dmr == 0) || ((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) && opts->inverted_dmr == 1) ) { fprintf (stderr,"%s ", getTime()); if (internalslot == 0) @@ -293,8 +297,10 @@ void dmrBS (dsd_opts * opts, dsd_state * state) skipcount++; //after 6 data frames, drop back to getFrameSync and process subsequent data with processDMRdata goto SKIP; } - - if( (strcmp (sync, DMR_BS_DATA_SYNC) != 0) ) //only play voice no data sync // || (strcmp (sync, DMR_MS_DATA_SYNC) != 0) + //only play voice on no data sync + //fixed to compensate for inverted signal + //(strcmp (sync, DMR_BS_DATA_SYNC) != 0) + if( ((strcmp (sync, DMR_BS_DATA_SYNC) != 0) && opts->inverted_dmr == 0) || ((strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && opts->inverted_dmr == 1)) { if (EmbeddedSignallingOk == 0) { @@ -305,13 +311,15 @@ void dmrBS (dsd_opts * opts, dsd_state * state) if (internalslot == 0) { state->dmrburstL = 16; //use 16 for Voice? - fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | VC%d \n", state->color_code, vc1); + //fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | VC%d \n", state->dmr_color_code, vc1); + fprintf (stderr,"Sync: +DMR [slot1] slot2 | | DMRSTEREO | VC%d \n",vc1); } if (internalslot == 1) { state->dmrburstR = 16; //use 16 for Voice? - fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | VC%d \n", state->color_code, vc2); + //fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | VC%d \n", state->dmr_color_code, vc2); + fprintf (stderr,"Sync: +DMR [slot1] slot2 | | DMRSTEREO | VC%d \n",vc2); } if (internalslot == 0 && vc1 == 6) //presumably when full (and no sync issues) { diff --git a/src/dmr_data.c b/src/dmr_data.c index ccb31f2..24604a3 100644 --- a/src/dmr_data.c +++ b/src/dmr_data.c @@ -51,11 +51,13 @@ processDMRdata (dsd_opts * opts, dsd_state * state) dibit_p = state->dibit_buf_p - 90; //using the estimate_symbol method for the dmr_payload_p buffer causes sync //issues with P25, so only do it when frame_p25p1 == 0, or -fr option - if (opts->frame_p25p1 == 0) //opts->frame_p25p1 == 0 + //temp fix to only use dmr_payload_p buffer when no inversion expected, otherwise use dibit_buf + if (opts->frame_p25p1 == 0 && opts->inverted_dmr == 0) //opts->frame_p25p1 == 0 { dibit_p = state->dmr_payload_p - 90; } + // CACH for (i = 0; i < 12; i++) { @@ -312,7 +314,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) //fprintf(stderr, "| Color Code=%02d ", (int)state->color_code); /* Reconstitute the burst type */ - //consider assigning thsi only when slottypeok or similar check passes, eliminate bad burst types from decoding randomly + //consider assigning this only when slottypeok or similar check passes, eliminate bad burst types from decoding randomly burst = (unsigned int)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]); if (state->currentslot == 0) { @@ -323,7 +325,6 @@ processDMRdata (dsd_opts * opts, dsd_state * state) state->dmrburstR = burst; } - /* Reconstitute the burst type */ bursttype[0] = SlotType[4] + '0'; bursttype[1] = SlotType[5] + '0'; @@ -331,48 +332,6 @@ processDMRdata (dsd_opts * opts, dsd_state * state) bursttype[3] = SlotType[7] + '0'; bursttype[4] = '\0'; - /* //delete this chunk later - if (state->dmr_stereo == 3) //may not need this any longer - { - burst = (state->dmr_stereo_payload[63] << 2) | (state->dmr_stereo_payload[64]); - //this whole split for getting burst and burst type is makes no sense - //why not just use burst - bursttype[0] = (((state->dmr_stereo_payload[63] >> 1) & 1) + '0'); - bursttype[1] = (((state->dmr_stereo_payload[63] >> 0) & 1) + '0'); - bursttype[2] = (((state->dmr_stereo_payload[64] >> 1) & 1) + '0'); - bursttype[3] = (((state->dmr_stereo_payload[64] >> 0) & 1) + '0'); - bursttype[4] = '\0'; - //fprintf(stderr, "BURST1 = %04b ", burst); - } - //figure out why the sync is wrong when dumping the payload to processDMRdata for MS Data - //I think its a conversion issue with the payload(chat) from the dibit buffer (int *) - //actually, its the dibit buffer storing as 1 and 3 only (GFSK) when sync drops - //made a seperate dmr buffer, but still, when sync loss and regain, takes a few syncs to calibrate center/umid/lmid properly - //getting accurate MS data AND leading BS data may be impossible without saving the symbols, calibrating, then going back - //and running the buffer payload, but I honestly don't know right now, probably easier to start from stratch than fix this - if (state->dmr_ms_mode == 7) - { - burst = (unsigned int)((SlotType[4] << 3) | (SlotType[5] << 2) | (SlotType[6] << 1) | SlotType[7]); - bursttype[0] = SlotType[4] + '0'; - bursttype[1] = SlotType[5] + '0'; - bursttype[2] = SlotType[6] + '0'; - bursttype[3] = SlotType[7] + '0'; - bursttype[4] = '\0'; - //fprintf(stderr, "BURST1 = %04b ", burst); - } - - if (state->dmr_stereo == 3) - { - fprintf(stderr, "BURST2 = %b%b%b%b Slot Dump ", SlotType[4], SlotType[5], SlotType[6], SlotType[7] ); - fprintf(stderr, " Slot Dump = "); - for (i = 0; i < 20; i++) - { - fprintf(stderr, "%b", SlotType[i]); - } - fprintf(stderr, "\n "); - } - */ - if (strcmp (bursttype, "0000") == 0) { sprintf(state->fsubtype, " PI Header "); @@ -554,7 +513,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) /* Burst = Slot idle */ case 0b1001: { - if(state->color_code_ok) state->dmr_color_code = state->color_code; //try setting this on idle if crc ok + if(state->color_code_ok && state->dmr_stereo == 0) state->dmr_color_code = state->color_code; //try setting this on idle if crc ok break; } diff --git a/src/dmr_ms.c b/src/dmr_ms.c index 5e5aafc..0ea4ab9 100644 --- a/src/dmr_ms.c +++ b/src/dmr_ms.c @@ -586,7 +586,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) fprintf (stderr, "MS MODE "); fprintf (stderr,"%s ", getTime()); - fprintf (stderr,"Sync: +DMR | Color Code=XX | DMRSTEREO | VC1 FS \n"); + fprintf (stderr,"Sync: +DMR | Frame Sync | DMRSTEREO | VC1 FS \n"); processMbeFrame (opts, state, NULL, ambe_fr, NULL); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index 546580b..63060b2 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -687,7 +687,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->min = ((state->min) + lmin) / 2; //state->directmode = 0; //fprintf (stderr, "DMR MS Data"); - if (0 == 0) //opts->inverted_dmr + if (opts->inverted_dmr == 0) //opts->inverted_dmr { // data frame sprintf(state->ftype, "DMR MS"); @@ -706,6 +706,16 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } return (33); //33 } + else //inverted MS voice frame + { + sprintf(state->ftype, "DMR MS"); + state->lastsynctype = 32; + if ( opts->monitor_input_audio == 1) + { + pa_simple_flush(opts->pulse_raw_dev_out, NULL); + } + return (32); + } } //not sure if this should be here, RC data should only be present in vc6? if(strcmp (synctest, DMR_RC_DATA_SYNC) == 0) @@ -746,7 +756,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->min = ((state->min) + lmin) / 2; //state->directmode = 0; //fprintf (stderr, "DMR MS VOICE\n"); - if (0 == 0) //opts->inverted_dmr + if (opts->inverted_dmr == 0) //opts->inverted_dmr { // voice frame sprintf(state->ftype, "DMR MS"); @@ -765,6 +775,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } return (32); } + else //inverted MS data frame + { + sprintf(state->ftype, "DMR MS"); + state->lastsynctype = 33; + if ( opts->monitor_input_audio == 1) + { + pa_simple_flush(opts->pulse_raw_dev_out, NULL); + } + return (33); + } + } //if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0)) @@ -794,7 +815,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { // inverted voice frame sprintf(state->ftype, "DMR "); - if (opts->errorbars == 1) + if (opts->errorbars == 1 && opts->dmr_stereo == 0) { printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); } @@ -928,7 +949,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { // inverted data frame sprintf(state->ftype, "DMR "); - if (opts->errorbars == 1 && opts->dmr_stereo == 0) + if (opts->errorbars == 1) //&& opts->dmr_stereo == 0 { printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); } diff --git a/src/dsd_main.c b/src/dsd_main.c index e183c86..90796fa 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -410,90 +410,90 @@ initState (dsd_state * state) void usage () { - fprintf (stderr, "Github Build Version: %s \n", GIT_TAG); - fprintf (stderr,"\n"); - fprintf (stderr,"Usage: dsd [options] Live scanner mode\n"); - fprintf (stderr," or: dsd [options] -r Read/Play saved mbe data from file(s)\n"); - fprintf (stderr," or: dsd -h Show help\n"); - fprintf (stderr,"\n"); - fprintf (stderr,"Display Options:\n"); - fprintf (stderr," -e Show Frame Info and errorbars (default)\n"); - fprintf (stderr," -pe Show P25 encryption sync bits\n"); - fprintf (stderr," -pl Show P25 link control bits\n"); - fprintf (stderr," -ps Show P25 status bits and low speed data\n"); - fprintf (stderr," -pt Show P25 talkgroup info\n"); - fprintf (stderr," -q Don't show Frame Info/errorbars\n"); - fprintf (stderr," -s Datascope (disables other display options)\n"); - fprintf (stderr," -t Show symbol timing during sync\n"); - fprintf (stderr," -v Frame information Verbosity\n"); - fprintf (stderr," -z Frame rate for datascope\n"); - fprintf (stderr,"\n"); - fprintf (stderr,"Input/Output options:\n"); - fprintf (stderr," -i Audio input device (default is pulse audio, \n - for piped stdin, rtl for rtl device)\n"); - fprintf (stderr," -o Audio output device (default is pulse audio)\n"); - fprintf (stderr," -d Create mbe data files, use this directory\n"); - fprintf (stderr," -r Read/Play saved mbe data from file(s)\n"); - fprintf (stderr," -g Audio output gain (default = 0 = auto, disable = -1)\n"); - fprintf (stderr," -w Output synthesized speech to a .wav file\n"); - //fprintf (stderr," -a Display port audio devices\n"); - fprintf (stderr," -W Monitor Source Audio When No Sync Detected (WIP!)\n"); - fprintf (stderr,"\n"); - fprintf (stderr,"RTL-SDR options:\n"); - fprintf (stderr," -c RTL-SDR Frequency\n"); - fprintf (stderr," -P RTL-SDR PPM Error (default = 0)\n"); - fprintf (stderr," -D RTL-SDR Device Index Number\n"); - fprintf (stderr," -G RTL-SDR Device Gain (0-49) (default = 0 Auto Gain)\n"); - fprintf (stderr," -L RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)\n (Just have to guess really...)\n"); - fprintf (stderr," -V RTL-SDR Sample Gain Multiplier (default = 1)\n"); - fprintf (stderr," -Y RTL-SDR VFO Bandwidth kHz (default = 48)(6, 8, 12, 16, 24, 48) \n"); - fprintf (stderr," -U RTL-SDR UDP Remote Port (default = 6020)\n"); - fprintf (stderr,"\n"); - fprintf (stderr,"Scanner control options:\n"); - fprintf (stderr," -B Serial port baud rate (default=115200)\n"); - fprintf (stderr," -C Serial port for scanner control (default=/dev/ttyUSB0)\n"); - fprintf (stderr," -R Resume scan after TDULC frames or any PDU or TSDU\n"); - fprintf (stderr,"\n"); - fprintf (stderr,"Decoder options:\n"); - fprintf (stderr," -fa Auto-detect frame type (default)\n"); - fprintf (stderr," -f1 Decode only P25 Phase 1\n"); - fprintf (stderr," -fd Decode only D-STAR\n"); - fprintf (stderr," -fr Decode only DMR/MOTOTRBO\n"); - fprintf (stderr," -fx Decode only X2-TDMA\n"); - fprintf (stderr," -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n"); - fprintf (stderr," -fn Decode only NXDN96* (12.5 kHz)\n"); - fprintf (stderr," -fp Decode only ProVoice*\n"); - fprintf (stderr," -fm Decode only dPMR*\n"); - fprintf (stderr," -l Disable DMR/MOTOTRBO and NXDN input filtering\n"); - fprintf (stderr," -ma Auto-select modulation optimizations (default)\n"); - fprintf (stderr," -mc Use only C4FM modulation optimizations\n"); - fprintf (stderr," -mg Use only GFSK modulation optimizations\n"); - fprintf (stderr," -mq Use only QPSK modulation optimizations\n"); - fprintf (stderr," -pu Unmute Encrypted P25\n"); - fprintf (stderr," -u Unvoiced speech quality (default=3)\n"); - fprintf (stderr," -xx Expect non-inverted X2-TDMA signal\n"); - fprintf (stderr," -xr Expect inverted DMR/MOTOTRBO signal\n"); - fprintf (stderr," -xd Expect inverted ICOM dPMR signal\n"); //still need to do this - fprintf (stderr,"\n"); - fprintf (stderr," * denotes frame types that cannot be auto-detected.\n"); - fprintf (stderr,"\n"); - fprintf (stderr,"Advanced decoder options:\n"); - fprintf (stderr," -A QPSK modulation auto detection threshold (default=26)\n"); - fprintf (stderr," -S Symbol buffer size for QPSK decision point tracking\n"); - fprintf (stderr," (default=36)\n"); - fprintf (stderr," -M Min/Max buffer size for QPSK decision point tracking\n"); - fprintf (stderr," (default=15)\n"); - fprintf (stderr," -n Reset P25 Heuristics and initState variables on mixed signal decoding\n"); - fprintf (stderr," Helps when decoding mixed signal types (P25P1) at same time\n"); - fprintf (stderr," (WiP! May Cause Slow Memory Leak or System Hang - Experimental)\n"); - fprintf (stderr," -T Enable DMR TDMA Stereo Voice (Two Slot Dual Voices)\n"); - fprintf (stderr," This feature will open two streams for slot 1 voice and slot 2 voice\n"); - fprintf (stderr," May Cause Skipping or sync issues if bad signal/errors\n"); - fprintf (stderr," -F Enable DMR TDMA Stereo Passive Frame Sync\n"); - fprintf (stderr," This feature will attempt to resync less often due to excessive voice errors\n"); - fprintf (stderr," Use if skipping occurs, but may cause wonky audio due to loss of good sync\n"); - fprintf (stderr," -Z Log MBE Payload to console\n"); - fprintf (stderr,"\n"); - fprintf (stderr,"Report bugs to: https://github.com/lwvmobile/dsd-fme/issues \n"); + printf ( "Github Build Version: %s \n", GIT_TAG); + printf ("\n"); + printf ("Usage: dsd [options] Live scanner mode\n"); + printf (" or: dsd [options] -r Read/Play saved mbe data from file(s)\n"); + printf (" or: dsd -h Show help\n"); + printf ("\n"); + printf ("Display Options:\n"); + printf (" -e Show Frame Info and errorbars (default)\n"); + printf (" -pe Show P25 encryption sync bits\n"); + printf (" -pl Show P25 link control bits\n"); + printf (" -ps Show P25 status bits and low speed data\n"); + printf (" -pt Show P25 talkgroup info\n"); + printf (" -q Don't show Frame Info/errorbars\n"); + printf (" -s Datascope (disables other display options)\n"); + printf (" -t Show symbol timing during sync\n"); + printf (" -v Frame information Verbosity\n"); + printf (" -z Frame rate for datascope\n"); + printf ("\n"); + printf ("Input/Output options:\n"); + printf (" -i Audio input device (default is pulse audio, \n - for piped stdin, rtl for rtl device)\n"); + printf (" -o Audio output device (default is pulse audio)\n"); + printf (" -d Create mbe data files, use this directory\n"); + printf (" -r Read/Play saved mbe data from file(s)\n"); + printf (" -g Audio output gain (default = 0 = auto, disable = -1)\n"); + printf (" -w Output synthesized speech to a .wav file\n"); + //printf (" -a Display port audio devices\n"); + printf (" -W Monitor Source Audio When No Sync Detected (WIP!)\n"); + printf ("\n"); + printf ("RTL-SDR options:\n"); + printf (" -c RTL-SDR Frequency\n"); + printf (" -P RTL-SDR PPM Error (default = 0)\n"); + printf (" -D RTL-SDR Device Index Number\n"); + printf (" -G RTL-SDR Device Gain (0-49) (default = 0 Auto Gain)\n"); + printf (" -L RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)\n (Just have to guess really...)\n"); + printf (" -V RTL-SDR Sample Gain Multiplier (default = 1)\n"); + printf (" -Y RTL-SDR VFO Bandwidth kHz (default = 48)(6, 8, 12, 16, 24, 48) \n"); + printf (" -U RTL-SDR UDP Remote Port (default = 6020)\n"); + printf ("\n"); + printf ("Scanner control options:\n"); + printf (" -B Serial port baud rate (default=115200)\n"); + printf (" -C Serial port for scanner control (default=/dev/ttyUSB0)\n"); + printf (" -R Resume scan after TDULC frames or any PDU or TSDU\n"); + printf ("\n"); + printf ("Decoder options:\n"); + printf (" -fa Auto-detect frame type (default)\n"); + printf (" -f1 Decode only P25 Phase 1\n"); + printf (" -fd Decode only D-STAR\n"); + printf (" -fr Decode only DMR/MOTOTRBO\n"); + printf (" -fx Decode only X2-TDMA\n"); + printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n"); + printf (" -fn Decode only NXDN96* (12.5 kHz)\n"); + printf (" -fp Decode only ProVoice*\n"); + printf (" -fm Decode only dPMR*\n"); + printf (" -l Disable DMR/MOTOTRBO and NXDN input filtering\n"); + printf (" -ma Auto-select modulation optimizations (default)\n"); + printf (" -mc Use only C4FM modulation optimizations\n"); + printf (" -mg Use only GFSK modulation optimizations\n"); + printf (" -mq Use only QPSK modulation optimizations\n"); + printf (" -pu Unmute Encrypted P25\n"); + printf (" -u Unvoiced speech quality (default=3)\n"); + printf (" -xx Expect non-inverted X2-TDMA signal\n"); + printf (" -xr Expect inverted DMR/MOTOTRBO signal\n"); + printf (" -xd Expect inverted ICOM dPMR signal\n"); //still need to do this + printf ("\n"); + printf (" * denotes frame types that cannot be auto-detected.\n"); + printf ("\n"); + printf ("Advanced decoder options:\n"); + printf (" -A QPSK modulation auto detection threshold (default=26)\n"); + printf (" -S Symbol buffer size for QPSK decision point tracking\n"); + printf (" (default=36)\n"); + printf (" -M Min/Max buffer size for QPSK decision point tracking\n"); + printf (" (default=15)\n"); + printf (" -n Reset P25 Heuristics and initState variables on mixed signal decoding\n"); + printf (" Helps when decoding mixed signal types (P25P1) at same time\n"); + printf (" (WiP! May Cause Slow Memory Leak or System Hang - Experimental)\n"); + printf (" -T Enable DMR TDMA Stereo Voice (Two Slot Dual Voices)\n"); + printf (" This feature will open two streams for slot 1 voice and slot 2 voice\n"); + printf (" May Cause Skipping or sync issues if bad signal/errors\n"); + printf (" -F Enable DMR TDMA Stereo Passive Frame Sync\n"); + printf (" This feature will attempt to resync less often due to excessive voice errors\n"); + printf (" Use if skipping occurs, but may cause wonky audio due to loss of good sync\n"); + printf (" -Z Log MBE Payload to console\n"); + printf ("\n"); + printf ("Report bugs to: https://github.com/lwvmobile/dsd-fme/issues \n"); exit (0); }