From 502607a60867b0cd3e5216f0b2bb7bf9fa27afd9 Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Sat, 16 Jan 2021 18:29:20 -0500 Subject: [PATCH 01/14] Start on rtlsdr --- CMakeLists.txt | 7 + cmake/FindLibSndFile.cmake | 4 +- cmake/FindRTLSDR.cmake | 29 ++ include/dsd.h | 13 +- src/dsd_audio.c | 7 + src/dsd_main.c | 14 + src/dsd_symbol.c | 28 +- src/rtl_sdr_fm.cpp | 986 +++++++++++++++++++++++++++++++++++++ 8 files changed, 1075 insertions(+), 13 deletions(-) create mode 100644 cmake/FindRTLSDR.cmake create mode 100644 src/rtl_sdr_fm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c1663c..23eb391 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ find_package(LibSndFile REQUIRED) find_package(MBE REQUIRED) find_package(ITPP REQUIRED) find_package(LibPortAudio) +find_package(RTLSDR) include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR}) set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY}) @@ -20,6 +21,12 @@ if(PORTAUDIO_FOUND) add_definitions(-DUSE_PORTAUDIO) endif(PORTAUDIO_FOUND) +if(RTLSDR_FOUND) + include_directories(SYSTEM ${RTLSDR_INCLUDE_DIRS}) + list(APPEND LIBS ${RTLSDR_LIBRARIES}) + add_definitions(-DUSE_RTLSDR) +endif(RTLSDR_FOUND) + FILE(GLOB SRCS src/*.c src/*.cpp) FILE(GLOB HEADERS include/*.h include/*.hpp) diff --git a/cmake/FindLibSndFile.cmake b/cmake/FindLibSndFile.cmake index b12b358..d976921 100644 --- a/cmake/FindLibSndFile.cmake +++ b/cmake/FindLibSndFile.cmake @@ -12,5 +12,5 @@ SET(LIBSNDFILE_NAMES ${LIBSNDFILE_NAMES} sndfile libsndfile) FIND_LIBRARY(LIBSNDFILE_LIBRARY NAMES ${LIBSNDFILE_NAMES}) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LIBSNDFILE DEFAULT_MSG LIBSNDFILE_LIBRARY - LIBSNDFILE_INCLUDE_DIR) \ No newline at end of file +find_package_handle_standard_args(LibSndFile DEFAULT_MSG LIBSNDFILE_LIBRARY + LIBSNDFILE_INCLUDE_DIR) diff --git a/cmake/FindRTLSDR.cmake b/cmake/FindRTLSDR.cmake new file mode 100644 index 0000000..8c18b49 --- /dev/null +++ b/cmake/FindRTLSDR.cmake @@ -0,0 +1,29 @@ +# - Try to find rtlsdr - the hardware driver for the realtek chip in the dvb receivers +# Once done this will define +# RTLSDR_FOUND - System has rtlsdr +# RTLSDR_LIBRARIES - The rtlsdr libraries +# RTLSDR_INCLUDE_DIRS - The rtlsdr include directories +# RTLSDR_LIB_DIRS - The rtlsdr library directories + +if (NOT RTLSDR_FOUND) + + find_package(PkgConfig) + pkg_check_modules(RTLSDR_PKG librtlsdr) + set(RTLSDR_DEFINITIONS ${PC_RTLSDR_CFLAGS_OTHER}) + + find_path(RTLSDR_INCLUDE_DIR + NAMES rtl-sdr.h + HINTS ${RTLSDR_PKG_INCLUDE_DIRS}) + + find_library(RTLSDR_LIBRARY + NAMES rtlsdr + HINTS ${RTLSDR_PKG_LIBRARY_DIRS}) + + set(RTLSDR_LIBRARIES ${RTLSDR_LIBRARY}) + set(RTLSDR_INCLUDE_DIRS ${RTLSDR_INCLUDE_DIR}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(RTLSDR DEFAULT_MSG RTLSDR_LIBRARY RTLSDR_INCLUDE_DIR) + mark_as_advanced(RTLSDR_INCLUDE_DIR RTLSDR_LIBRARY) + +endif (NOT RTLSDR_FOUND) diff --git a/include/dsd.h b/include/dsd.h index 22ef3e9..59dbe40 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -58,6 +58,10 @@ #define PA_LATENCY_OUT 0.100 #endif +#ifdef USE_RTLSDR +#include +#endif + /* * global variables */ @@ -85,7 +89,10 @@ typedef struct #ifdef USE_PORTAUDIO PaStream* audio_in_pa_stream; #endif - int audio_in_type; // 0 for device, 1 for file, 2 for portaudio +#ifdef USE_RTLSDR + rtlsdr_dev_t *rtlSdrDev; +#endif + int audio_in_type; // 0 for device, 1 for file, 2 for portaudio, 3 for rtlsdr char audio_out_dev[1024]; int audio_out_fd; SNDFILE *audio_out_file; @@ -317,4 +324,8 @@ void processDSTAR_HD (dsd_opts * opts, dsd_state * state); short dmr_filter(short sample); short nxdn_filter(short sample); +void open_rtlsdr_stream(); +void cleanup_rtlsdr_stream(); +void get_rtlsdr_sample(); + #endif // DSD_H diff --git a/src/dsd_audio.c b/src/dsd_audio.c index 993add2..6e75b85 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -500,6 +500,13 @@ openAudioInDevice (dsd_opts * opts) exit(1); #endif } + else if(strncmp(opts->audio_in_dev, "rtl:", 3) == 0) + { + printf("USING RTL SDR\n"); + opts->audio_in_type = 3; + + // Starting the stream will open the device. + } else { struct stat stat_buf; diff --git a/src/dsd_main.c b/src/dsd_main.c index 4069ce0..450180d 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -327,6 +327,13 @@ liveScanner (dsd_opts * opts, dsd_state * state) return; } } +#endif +#ifdef USE_RTLSDR + if(opts->audio_in_type == 3) + { + printf("starting rtl stream\n"); + open_rtlsdr_stream(); + } #endif while (1) { @@ -411,6 +418,13 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) } #endif +#ifdef USE_RTLSDR + if(opts->audio_in_type == 3) + { + // TODO: cleanup demod threads + } +#endif + printf("\n"); printf("Total audio errors: %i\n", state->debug_audio_errors); printf("Total header errors: %i\n", state->debug_header_errors); diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c index f286ae2..088486a 100644 --- a/src/dsd_symbol.c +++ b/src/dsd_symbol.c @@ -88,18 +88,26 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) cleanupAndExit (opts, state); } } - else - { + else if (opts->audio_in_type == 2) + { #ifdef USE_PORTAUDIO - PaError err = Pa_ReadStream( opts->audio_in_pa_stream, &sample, 1 ); - if( err != paNoError ) - { - fprintf( stderr, "An error occured while using the portaudio input stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - } + PaError err = Pa_ReadStream( opts->audio_in_pa_stream, &sample, 1 ); + if( err != paNoError ) + { + fprintf( stderr, "An error occured while using the portaudio input stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + } #endif - } + } + else if (opts->audio_in_type == 3) + { +#ifdef USE_RTLSDR + // TODO: need to read demodulated stream here + get_rtlsdr_sample(&sample); + printf("sample: %d\n", sample); +#endif + } #ifdef TRACE_DSD state->debug_sample_index++; diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp new file mode 100644 index 0000000..c99b88f --- /dev/null +++ b/src/rtl_sdr_fm.cpp @@ -0,0 +1,986 @@ +/* + * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver + * Copyright (C) 2012 by Steve Markgraf + * Copyright (C) 2012 by Hoernchen + * Copyright (C) 2012 by Kyle Keen + * Copyright (C) 2013 by Elias Oenal + * Copyright (C) 2014 by Kyle Keen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_SAMPLE_RATE 48000 +#define DEFAULT_BUF_LENGTH (1 * 16384) +#define MAXIMUM_OVERSAMPLE 16 +#define MAXIMUM_BUF_LENGTH (MAXIMUM_OVERSAMPLE * DEFAULT_BUF_LENGTH) +#define AUTO_GAIN -100 +#define BUFFER_DUMP 4096 + +#define FREQUENCIES_LIMIT 1000 + +static volatile int do_exit = 0; +static int lcm_post[17] = {1,1,1,3,1,5,3,7,1,9,5,11,3,13,7,15,1}; +static int ACTUAL_BUF_LENGTH; + +static int *atan_lut = NULL; +static int atan_lut_size = 131072; /* 512 KB */ +static int atan_lut_coef = 8; + +struct dongle_state +{ + int exit_flag; + pthread_t thread; + rtlsdr_dev_t *dev; + int dev_index; + uint32_t freq; + uint32_t rate; + int gain; + uint16_t buf16[MAXIMUM_BUF_LENGTH]; + uint32_t buf_len; + int ppm_error; + int offset_tuning; + int direct_sampling; + int mute; + struct demod_state *demod_target; +}; + +struct demod_state +{ + int exit_flag; + pthread_t thread; + int16_t lowpassed[MAXIMUM_BUF_LENGTH]; + int lp_len; + int16_t lp_i_hist[10][6]; + int16_t lp_q_hist[10][6]; + int16_t result[MAXIMUM_BUF_LENGTH]; + int16_t droop_i_hist[9]; + int16_t droop_q_hist[9]; + int result_len; + int rate_in; + int rate_out; + int rate_out2; + int now_r, now_j; + int pre_r, pre_j; + int prev_index; + int downsample; /* min 1, max 256 */ + int post_downsample; + int output_scale; + int squelch_level, conseq_squelch, squelch_hits, terminate_on_squelch; + int downsample_passes; + int comp_fir_size; + int custom_atan; + int deemph, deemph_a; + int now_lpr; + int prev_lpr_index; + int dc_block, dc_avg; + void (*mode_demod)(struct demod_state*); + pthread_rwlock_t rw; + pthread_cond_t ready; + pthread_mutex_t ready_m; + struct output_state *output_target; +}; + +struct output_state +{ + int exit_flag; + pthread_t thread; + FILE *file; + char *filename; + int16_t result[MAXIMUM_BUF_LENGTH]; + int result_len; + int rate; + std::queue queue; + pthread_rwlock_t rw; + pthread_cond_t ready; + pthread_mutex_t ready_m; +}; + +struct controller_state +{ + int exit_flag; + pthread_t thread; + uint32_t freqs[FREQUENCIES_LIMIT]; + int freq_len; + int freq_now; + int edge; + int wb_mode; + pthread_cond_t hop; + pthread_mutex_t hop_m; +}; + +struct dongle_state dongle; +struct demod_state demod; +struct output_state output; +struct controller_state controller; + +static void sighandler(int signum) +{ + fprintf(stderr, "Signal caught, exiting!\n"); + do_exit = 1; + rtlsdr_cancel_async(dongle.dev); +} + +#define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m) +#define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m) + +/* {length, coef, coef, coef} and scaled by 2^15 + for now, only length 9, optimal way to get +85% bandwidth */ +#define CIC_TABLE_MAX 10 +int cic_9_tables[][10] = { + {0,}, + {9, -156, -97, 2798, -15489, 61019, -15489, 2798, -97, -156}, + {9, -128, -568, 5593, -24125, 74126, -24125, 5593, -568, -128}, + {9, -129, -639, 6187, -26281, 77511, -26281, 6187, -639, -129}, + {9, -122, -612, 6082, -26353, 77818, -26353, 6082, -612, -122}, + {9, -120, -602, 6015, -26269, 77757, -26269, 6015, -602, -120}, + {9, -120, -582, 5951, -26128, 77542, -26128, 5951, -582, -120}, + {9, -119, -580, 5931, -26094, 77505, -26094, 5931, -580, -119}, + {9, -119, -578, 5921, -26077, 77484, -26077, 5921, -578, -119}, + {9, -119, -577, 5917, -26067, 77473, -26067, 5917, -577, -119}, + {9, -199, -362, 5303, -25505, 77489, -25505, 5303, -362, -199}, +}; + +void rotate_90(unsigned char *buf, uint32_t len) +/* 90 rotation is 1+0j, 0+1j, -1+0j, 0-1j + or [0, 1, -3, 2, -4, -5, 7, -6] */ +{ + uint32_t i; + unsigned char tmp; + for (i=0; ilp_len) { + d->now_r += d->lowpassed[i]; + d->now_j += d->lowpassed[i+1]; + i += 2; + d->prev_index++; + if (d->prev_index < d->downsample) { + continue; + } + d->lowpassed[i2] = d->now_r; // * d->output_scale; + d->lowpassed[i2+1] = d->now_j; // * d->output_scale; + d->prev_index = 0; + d->now_r = 0; + d->now_j = 0; + i2 += 2; + } + d->lp_len = i2; +} + +int low_pass_simple(int16_t *signal2, int len, int step) +// no wrap around, length must be multiple of step +{ + int i, i2, sum; + for(i=0; i < len; i+=step) { + sum = 0; + for(i2=0; i2rate_out; + int slow = s->rate_out2; + while (i < s->result_len) { + s->now_lpr += s->result[i]; + i++; + s->prev_lpr_index += slow; + if (s->prev_lpr_index < fast) { + continue; + } + s->result[i2] = (int16_t)(s->now_lpr / (fast/slow)); + s->prev_lpr_index -= fast; + s->now_lpr = 0; + i2 += 1; + } + s->result_len = i2; +} + +void fifth_order(int16_t *data, int length, int16_t *hist) +/* for half of interleaved data */ +{ + int i; + int16_t a, b, c, d, e, f; + a = hist[1]; + b = hist[2]; + c = hist[3]; + d = hist[4]; + e = hist[5]; + f = data[0]; + /* a downsample should improve resolution, so don't fully shift */ + data[0] = (a + (b+e)*5 + (c+d)*10 + f) >> 4; + for (i=4; i> 4; + } + /* archive */ + hist[0] = a; + hist[1] = b; + hist[2] = c; + hist[3] = d; + hist[4] = e; + hist[5] = f; +} + +void generic_fir(int16_t *data, int length, int *fir, int16_t *hist) +/* Okay, not at all generic. Assumes length 9, fix that eventually. */ +{ + int d, temp, sum; + for (d=0; d> 15 ; + hist[0] = hist[1]; + hist[1] = hist[2]; + hist[2] = hist[3]; + hist[3] = hist[4]; + hist[4] = hist[5]; + hist[5] = hist[6]; + hist[6] = hist[7]; + hist[7] = hist[8]; + hist[8] = temp; + } +} + +// define our own complex math ops because ARMv5 has no hardware float +void multiply(int ar, int aj, int br, int bj, int *cr, int *cj) +{ + *cr = ar*br - aj*bj; + *cj = aj*br + ar*bj; +} + +int polar_discriminant(int ar, int aj, int br, int bj) +{ + int cr, cj; + double angle; + multiply(ar, aj, br, -bj, &cr, &cj); + angle = atan2((double)cj, (double)cr); + return (int)(angle / 3.14159 * (1<<14)); +} + +int fast_atan2(int y, int x) +/* pre scaled for int16 */ +{ + int yabs, angle; + int pi4=(1<<12), pi34=3*(1<<12); // note pi = 1<<14 + if (x==0 && y==0) { + return 0; + } + yabs = y; + if (yabs < 0) { + yabs = -yabs; + } + if (x >= 0) { + angle = pi4 - pi4 * (x-yabs) / (x+yabs); + } else { + angle = pi34 - pi4 * (x+yabs) / (yabs-x); + } + if (y < 0) { + return -angle; + } + return angle; +} + +int polar_disc_fast(int ar, int aj, int br, int bj) +{ + int cr, cj; + multiply(ar, aj, br, -bj, &cr, &cj); + return fast_atan2(cj, cr); +} + +int atan_lut_init(void) +{ + int i = 0; + + atan_lut = static_cast(malloc(atan_lut_size * sizeof(int))); + + for (i = 0; i < atan_lut_size; i++) { + atan_lut[i] = (int) (atan((double) i / (1< 0) + {return 1 << 13;} + if (cr == 0 && cj < 0) + {return -(1 << 13);} + if (cj == 0 && cr > 0) + {return 0;} + if (cj == 0 && cr < 0) + {return 1 << 14;} + } + + /* real range -32768 - 32768 use 64x range -> absolute maximum: 2097152 */ + x = (cj << atan_lut_coef) / cr; + x_abs = abs(x); + + if (x_abs >= atan_lut_size) { + /* we can use linear range, but it is not necessary */ + return (cj > 0) ? 1<<13 : -(1<<13); + } + + if (x > 0) { + return (cj > 0) ? atan_lut[x] : atan_lut[x] - (1<<14); + } else { + return (cj > 0) ? (1<<14) - atan_lut[-x] : -atan_lut[-x]; + } + + return 0; +} + +void fm_demod(struct demod_state *fm) +{ + int i, pcm; + int16_t *lp = fm->lowpassed; + pcm = polar_discriminant(lp[0], lp[1], + fm->pre_r, fm->pre_j); + fm->result[0] = (int16_t)pcm; + for (i = 2; i < (fm->lp_len-1); i += 2) { + switch (fm->custom_atan) { + case 0: + pcm = polar_discriminant(lp[i], lp[i+1], + lp[i-2], lp[i-1]); + break; + case 1: + pcm = polar_disc_fast(lp[i], lp[i+1], + lp[i-2], lp[i-1]); + break; + case 2: + pcm = polar_disc_lut(lp[i], lp[i+1], + lp[i-2], lp[i-1]); + break; + } + fm->result[i/2] = (int16_t)pcm; + } + fm->pre_r = lp[fm->lp_len - 2]; + fm->pre_j = lp[fm->lp_len - 1]; + fm->result_len = fm->lp_len/2; +} + +void raw_demod(struct demod_state *fm) +{ + int i; + for (i = 0; i < fm->lp_len; i++) { + fm->result[i] = (int16_t)fm->lowpassed[i]; + } + fm->result_len = fm->lp_len; +} + +void deemph_filter(struct demod_state *fm) +{ + static int avg; // cheating... + int i, d; + // de-emph IIR + // avg = avg * (1 - alpha) + sample * alpha; + for (i = 0; i < fm->result_len; i++) { + d = fm->result[i] - avg; + if (d > 0) { + avg += (d + fm->deemph_a/2) / fm->deemph_a; + } else { + avg += (d - fm->deemph_a/2) / fm->deemph_a; + } + fm->result[i] = (int16_t)avg; + } +} + +void dc_block_filter(struct demod_state *fm) +{ + int i, avg; + int64_t sum = 0; + for (i=0; i < fm->result_len; i++) { + sum += fm->result[i]; + } + avg = sum / fm->result_len; + avg = (avg + fm->dc_avg * 9) / 10; + for (i=0; i < fm->result_len; i++) { + fm->result[i] -= avg; + } + fm->dc_avg = avg; +} + +int rms(int16_t *samples, int len, int step) +/* largely lifted from rtl_power */ +{ + int i; + long p, t, s; + double dc, err; + + p = t = 0L; + for (i=0; idownsample_passes; + if (ds_p) { + for (i=0; i < ds_p; i++) { + fifth_order(d->lowpassed, (d->lp_len >> i), d->lp_i_hist[i]); + fifth_order(d->lowpassed+1, (d->lp_len >> i) - 1, d->lp_q_hist[i]); + } + d->lp_len = d->lp_len >> ds_p; + /* droop compensation */ + if (d->comp_fir_size == 9 && ds_p <= CIC_TABLE_MAX) { + generic_fir(d->lowpassed, d->lp_len, + cic_9_tables[ds_p], d->droop_i_hist); + generic_fir(d->lowpassed+1, d->lp_len-1, + cic_9_tables[ds_p], d->droop_q_hist); + } + } else { + low_pass(d); + } + /* power squelch */ + if (d->squelch_level) { + sr = rms(d->lowpassed, d->lp_len, 1); + if (sr < d->squelch_level) { + d->squelch_hits++; + for (i=0; ilp_len; i++) { + d->lowpassed[i] = 0; + } + } else { + d->squelch_hits = 0;} + } + d->mode_demod(d); /* lowpassed -> result */ + if (d->mode_demod == &raw_demod) { + return; + } + /* todo, fm noise squelch */ + // use nicer filter here too? + if (d->post_downsample > 1) { + d->result_len = low_pass_simple(d->result, d->result_len, d->post_downsample);} + if (d->deemph) { + deemph_filter(d);} + if (d->dc_block) { + dc_block_filter(d);} + if (d->rate_out2 > 0) { + low_pass_real(d); + //arbitrary_resample(d->result, d->result, d->result_len, d->result_len * d->rate_out2 / d->rate_out); + } +} + +static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) +{ + int i; + struct dongle_state *s = static_cast(ctx); + struct demod_state *d = s->demod_target; + + if (do_exit) { + return;} + if (!ctx) { + return;} + if (s->mute) { + for (i=0; imute; i++) { + buf[i] = 127;} + s->mute = 0; + } + if (!s->offset_tuning) { + rotate_90(buf, len);} + for (i=0; i<(int)len; i++) { + s->buf16[i] = (int16_t)buf[i] - 127;} + pthread_rwlock_wrlock(&d->rw); + memcpy(d->lowpassed, s->buf16, 2*len); + d->lp_len = len; + pthread_rwlock_unlock(&d->rw); + safe_cond_signal(&d->ready, &d->ready_m); +} + +static void *dongle_thread_fn(void *arg) +{ + printf("starting dongle thread\n"); + struct dongle_state *s = static_cast(arg); + rtlsdr_read_async(s->dev, rtlsdr_callback, s, 0, s->buf_len); + return 0; +} + +static void *demod_thread_fn(void *arg) +{ + printf("starting demod thread\n"); + struct demod_state *d = static_cast(arg); + struct output_state *o = d->output_target; + while (!do_exit) { + safe_cond_wait(&d->ready, &d->ready_m); + pthread_rwlock_wrlock(&d->rw); + full_demod(d); + pthread_rwlock_unlock(&d->rw); + if (d->exit_flag) { + do_exit = 1; + } + if (d->squelch_level && d->squelch_hits > d->conseq_squelch) { + d->squelch_hits = d->conseq_squelch + 1; /* hair trigger */ + safe_cond_signal(&controller.hop, &controller.hop_m); + continue; + } + pthread_rwlock_wrlock(&o->rw); + memcpy(o->result, d->result, 2*d->result_len); + o->result_len = d->result_len; + pthread_rwlock_unlock(&o->rw); + safe_cond_signal(&o->ready, &o->ready_m); + } + return 0; +} + +static void *output_thread_fn(void *arg) +{ + printf("starting output thread\n"); + struct output_state *s = static_cast(arg); + while (!do_exit) { + // use timedwait and pad out under runs + safe_cond_wait(&s->ready, &s->ready_m); + pthread_rwlock_rdlock(&s->rw); + printf("result_len: %i\n", s->result_len); + for (int i = 0; i < s->result_len; i++) + { + s->queue.push(reinterpret_cast(s->result[i * 2])); + } + printf("queue size: %lu\n", s->queue.size()); + // fwrite(s->result, 2, s->result_len, s->file); + pthread_rwlock_unlock(&s->rw); + } + return 0; +} + +int nearest_gain(rtlsdr_dev_t *dev, int target_gain) +{ + int i, r, err1, err2, count, nearest; + int* gains; + r = rtlsdr_set_tuner_gain_mode(dev, 1); + if (r < 0) { + fprintf(stderr, "WARNING: Failed to enable manual gain.\n"); + return r; + } + count = rtlsdr_get_tuner_gains(dev, NULL); + if (count <= 0) { + return 0; + } + gains = static_cast(malloc(sizeof(int) * count)); + count = rtlsdr_get_tuner_gains(dev, gains); + nearest = gains[0]; + for (i=0; idownsample = (1000000 / dm->rate_in) + 1; + if (dm->downsample_passes) { + dm->downsample_passes = (int)log2(dm->downsample) + 1; + dm->downsample = 1 << dm->downsample_passes; + } + capture_freq = freq; + capture_rate = dm->downsample * dm->rate_in; + if (!d->offset_tuning) { + capture_freq = freq + capture_rate/4;} + capture_freq += cs->edge * dm->rate_in / 2; + dm->output_scale = (1<<15) / (128 * dm->downsample); + if (dm->output_scale < 1) { + dm->output_scale = 1;} + if (dm->mode_demod == &fm_demod) { + dm->output_scale = 1;} + d->freq = (uint32_t)capture_freq; + d->rate = (uint32_t)capture_rate; +} + +static void *controller_thread_fn(void *arg) +{ + printf("starting controller thread\n"); + // thoughts for multiple dongles + // might be no good using a controller thread if retune/rate blocks + int i; + struct controller_state *s = static_cast(arg); + + if (s->wb_mode) { + for (i=0; i < s->freq_len; i++) { + s->freqs[i] += 16000;} + } + + /* set up primary channel */ + optimal_settings(s->freqs[0], demod.rate_in); + if (dongle.direct_sampling) { + verbose_direct_sampling(dongle.dev, 1);} + if (dongle.offset_tuning) { + verbose_offset_tuning(dongle.dev);} + + /* Set the frequency */ + verbose_set_frequency(dongle.dev, dongle.freq); + fprintf(stderr, "Oversampling input by: %ix.\n", demod.downsample); + fprintf(stderr, "Oversampling output by: %ix.\n", demod.post_downsample); + fprintf(stderr, "Buffer size: %0.2fms\n", + 1000 * 0.5 * (float)ACTUAL_BUF_LENGTH / (float)dongle.rate); + + /* Set the sample rate */ + verbose_set_sample_rate(dongle.dev, dongle.rate); + fprintf(stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample); + + while (!do_exit) { + safe_cond_wait(&s->hop, &s->hop_m); + if (s->freq_len <= 1) { + continue;} + /* hacky hopping */ + s->freq_now = (s->freq_now + 1) % s->freq_len; + optimal_settings(s->freqs[s->freq_now], demod.rate_in); + rtlsdr_set_center_freq(dongle.dev, dongle.freq); + dongle.mute = BUFFER_DUMP; + } + return 0; +} + +void dongle_init(struct dongle_state *s) +{ + s->rate = DEFAULT_SAMPLE_RATE; + s->gain = AUTO_GAIN; // tenths of a dB + s->mute = 0; + s->direct_sampling = 0; + s->offset_tuning = 0; + s->demod_target = &demod; +} + +void demod_init(struct demod_state *s) +{ + s->rate_in = DEFAULT_SAMPLE_RATE; + s->rate_out = DEFAULT_SAMPLE_RATE; + s->squelch_level = 0; + s->conseq_squelch = 10; + s->terminate_on_squelch = 0; + s->squelch_hits = 11; + s->downsample_passes = 0; + s->comp_fir_size = 0; + s->prev_index = 0; + s->post_downsample = 1; // once this works, default = 4 + s->custom_atan = 0; + s->deemph = 0; + s->rate_out2 = -1; // flag for disabled + s->mode_demod = &fm_demod; + s->pre_j = s->pre_r = s->now_r = s->now_j = 0; + s->prev_lpr_index = 0; + s->deemph_a = 0; + s->now_lpr = 0; + s->dc_block = 0; + s->dc_avg = 0; + pthread_rwlock_init(&s->rw, NULL); + pthread_cond_init(&s->ready, NULL); + pthread_mutex_init(&s->ready_m, NULL); + s->output_target = &output; +} + +void demod_cleanup(struct demod_state *s) +{ + pthread_rwlock_destroy(&s->rw); + pthread_cond_destroy(&s->ready); + pthread_mutex_destroy(&s->ready_m); +} + +void output_init(struct output_state *s) +{ + s->rate = DEFAULT_SAMPLE_RATE; + pthread_rwlock_init(&s->rw, NULL); + pthread_cond_init(&s->ready, NULL); + pthread_mutex_init(&s->ready_m, NULL); +} + +void output_cleanup(struct output_state *s) +{ + pthread_rwlock_destroy(&s->rw); + pthread_cond_destroy(&s->ready); + pthread_mutex_destroy(&s->ready_m); +} + +void controller_init(struct controller_state *s) +{ + s->freqs[0] = 451800000; + s->freq_len = 0; + s->edge = 0; + s->wb_mode = 0; + pthread_cond_init(&s->hop, NULL); + pthread_mutex_init(&s->hop_m, NULL); +} + +void controller_cleanup(struct controller_state *s) +{ + pthread_cond_destroy(&s->hop); + pthread_mutex_destroy(&s->hop_m); +} + +extern "C" void open_rtlsdr_stream(); +void open_rtlsdr_stream() +{ + printf("+++++ OPEN STREAM +++++\n"); + + struct sigaction sigact; + int r; + + dongle_init(&dongle); + demod_init(&demod); + output_init(&output); + controller_init(&controller); + + /* quadruple sample_rate to limit to Δθ to ±π/2 */ + demod.rate_in *= demod.post_downsample; + + if (!output.rate) output.rate = demod.rate_out; + + // sanity_checks(); + + ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH; + + r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index); + if (r < 0) + { + fprintf(stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index); + exit(1); + } + + sigact.sa_handler = sighandler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGPIPE, &sigact, NULL); + + if (demod.deemph) { + demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6))))); + } + + /* Set the tuner gain */ + if (dongle.gain == AUTO_GAIN) { + verbose_auto_gain(dongle.dev); + } else { + dongle.gain = nearest_gain(dongle.dev, dongle.gain); + verbose_gain_set(dongle.dev, dongle.gain); + } + + verbose_ppm_set(dongle.dev, dongle.ppm_error); + + /* Reset endpoint before we start reading from it (mandatory) */ + verbose_reset_buffer(dongle.dev); + + pthread_create(&controller.thread, NULL, controller_thread_fn, (void*)(&controller)); + usleep(100000); + pthread_create(&output.thread, NULL, output_thread_fn, (void*)(&output)); + pthread_create(&demod.thread, NULL, demod_thread_fn, (void*)(&demod)); + pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void*)(&dongle)); + printf("done opening stream\n"); +} + +void cleanup_rtlsdr_stream() +{ + rtlsdr_cancel_async(dongle.dev); + pthread_join(dongle.thread, NULL); + safe_cond_signal(&demod.ready, &demod.ready_m); + pthread_join(demod.thread, NULL); + safe_cond_signal(&output.ready, &output.ready_m); + pthread_join(output.thread, NULL); + safe_cond_signal(&controller.hop, &controller.hop_m); + pthread_join(controller.thread, NULL); + + //dongle_cleanup(&dongle); + demod_cleanup(&demod); + output_cleanup(&output); + controller_cleanup(&controller); + + rtlsdr_close(dongle.dev); +} + +extern "C" void get_rtlsdr_sample(int16_t *sample); +void get_rtlsdr_sample(int16_t *sample) +{ + printf("getting sample\n"); + safe_cond_wait(&output.ready, &output.ready_m); + *sample = output.queue.front(); + output.queue.pop(); +} From 0b0754c1d5b3cbf13b8e951787085340a8c97229 Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Sat, 16 Jan 2021 21:43:23 -0500 Subject: [PATCH 02/14] It works --- include/dsd.h | 4 +- src/dsd_audio.c | 3 -- src/dsd_main.c | 5 ++- src/dsd_symbol.c | 1 - src/rtl_sdr_fm.cpp | 95 ++++++++++++++++++---------------------------- 5 files changed, 43 insertions(+), 65 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index 59dbe40..5d073aa 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -65,7 +65,7 @@ /* * global variables */ -int exitflag; +static volatile int exitflag; typedef struct @@ -327,5 +327,7 @@ short nxdn_filter(short sample); void open_rtlsdr_stream(); void cleanup_rtlsdr_stream(); void get_rtlsdr_sample(); +void rtlsdr_sighandler(); + #endif // DSD_H diff --git a/src/dsd_audio.c b/src/dsd_audio.c index 6e75b85..e706deb 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -502,10 +502,7 @@ openAudioInDevice (dsd_opts * opts) } else if(strncmp(opts->audio_in_dev, "rtl:", 3) == 0) { - printf("USING RTL SDR\n"); opts->audio_in_type = 3; - - // Starting the stream will open the device. } else { diff --git a/src/dsd_main.c b/src/dsd_main.c index 450180d..7982c8b 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -331,7 +331,6 @@ liveScanner (dsd_opts * opts, dsd_state * state) #ifdef USE_RTLSDR if(opts->audio_in_type == 3) { - printf("starting rtl stream\n"); open_rtlsdr_stream(); } #endif @@ -422,6 +421,7 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) if(opts->audio_in_type == 3) { // TODO: cleanup demod threads + cleanup_rtlsdr_stream(); } #endif @@ -461,6 +461,9 @@ sigfun (int sig) { exitflag = 1; signal (SIGINT, SIG_DFL); +#ifdef USE_RTLSDR + rtlsdr_sighandler(); +#endif } int diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c index 088486a..d34c7e6 100644 --- a/src/dsd_symbol.c +++ b/src/dsd_symbol.c @@ -105,7 +105,6 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) #ifdef USE_RTLSDR // TODO: need to read demodulated stream here get_rtlsdr_sample(&sample); - printf("sample: %d\n", sample); #endif } diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index c99b88f..9f34e5a 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -39,7 +39,10 @@ #define FREQUENCIES_LIMIT 1000 -static volatile int do_exit = 0; +extern "C" { + volatile int exitflag; +} + static int lcm_post[17] = {1,1,1,3,1,5,3,7,1,9,5,11,3,13,7,15,1}; static int ACTUAL_BUF_LENGTH; @@ -103,12 +106,6 @@ struct demod_state struct output_state { - int exit_flag; - pthread_t thread; - FILE *file; - char *filename; - int16_t result[MAXIMUM_BUF_LENGTH]; - int result_len; int rate; std::queue queue; pthread_rwlock_t rw; @@ -134,13 +131,6 @@ struct demod_state demod; struct output_state output; struct controller_state controller; -static void sighandler(int signum) -{ - fprintf(stderr, "Signal caught, exiting!\n"); - do_exit = 1; - rtlsdr_cancel_async(dongle.dev); -} - #define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m) #define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m) @@ -541,7 +531,7 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) struct dongle_state *s = static_cast(ctx); struct demod_state *d = s->demod_target; - if (do_exit) { + if (exitflag) { return;} if (!ctx) { return;} @@ -563,7 +553,6 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) static void *dongle_thread_fn(void *arg) { - printf("starting dongle thread\n"); struct dongle_state *s = static_cast(arg); rtlsdr_read_async(s->dev, rtlsdr_callback, s, 0, s->buf_len); return 0; @@ -571,16 +560,15 @@ static void *dongle_thread_fn(void *arg) static void *demod_thread_fn(void *arg) { - printf("starting demod thread\n"); struct demod_state *d = static_cast(arg); struct output_state *o = d->output_target; - while (!do_exit) { + while (!exitflag) { safe_cond_wait(&d->ready, &d->ready_m); pthread_rwlock_wrlock(&d->rw); full_demod(d); pthread_rwlock_unlock(&d->rw); if (d->exit_flag) { - do_exit = 1; + exitflag = 1; } if (d->squelch_level && d->squelch_hits > d->conseq_squelch) { d->squelch_hits = d->conseq_squelch + 1; /* hair trigger */ @@ -588,34 +576,16 @@ static void *demod_thread_fn(void *arg) continue; } pthread_rwlock_wrlock(&o->rw); - memcpy(o->result, d->result, 2*d->result_len); - o->result_len = d->result_len; + for (int i = 0; i < d->result_len; i++) + { + o->queue.push(d->result[i]); + } pthread_rwlock_unlock(&o->rw); safe_cond_signal(&o->ready, &o->ready_m); } return 0; } -static void *output_thread_fn(void *arg) -{ - printf("starting output thread\n"); - struct output_state *s = static_cast(arg); - while (!do_exit) { - // use timedwait and pad out under runs - safe_cond_wait(&s->ready, &s->ready_m); - pthread_rwlock_rdlock(&s->rw); - printf("result_len: %i\n", s->result_len); - for (int i = 0; i < s->result_len; i++) - { - s->queue.push(reinterpret_cast(s->result[i * 2])); - } - printf("queue size: %lu\n", s->queue.size()); - // fwrite(s->result, 2, s->result_len, s->file); - pthread_rwlock_unlock(&s->rw); - } - return 0; -} - int nearest_gain(rtlsdr_dev_t *dev, int target_gain) { int i, r, err1, err2, count, nearest; @@ -777,7 +747,6 @@ static void optimal_settings(int freq, int rate) static void *controller_thread_fn(void *arg) { - printf("starting controller thread\n"); // thoughts for multiple dongles // might be no good using a controller thread if retune/rate blocks int i; @@ -806,7 +775,7 @@ static void *controller_thread_fn(void *arg) verbose_set_sample_rate(dongle.dev, dongle.rate); fprintf(stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample); - while (!do_exit) { + while (!exitflag) { safe_cond_wait(&s->hop, &s->hop_m); if (s->freq_len <= 1) { continue;} @@ -895,11 +864,15 @@ void controller_cleanup(struct controller_state *s) pthread_mutex_destroy(&s->hop_m); } -extern "C" void open_rtlsdr_stream(); +extern "C" { +void rtlsdr_sighandler() +{ + fprintf(stderr, "Signal caught, exiting!\n"); + rtlsdr_cancel_async(dongle.dev); +} + void open_rtlsdr_stream() { - printf("+++++ OPEN STREAM +++++\n"); - struct sigaction sigact; int r; @@ -915,6 +888,8 @@ void open_rtlsdr_stream() // sanity_checks(); + if (controller.freq_len > 1) demod.terminate_on_squelch = 0; + ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH; r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index); @@ -924,13 +899,13 @@ void open_rtlsdr_stream() exit(1); } - sigact.sa_handler = sighandler; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(SIGINT, &sigact, NULL); - sigaction(SIGTERM, &sigact, NULL); - sigaction(SIGQUIT, &sigact, NULL); - sigaction(SIGPIPE, &sigact, NULL); + // sigact.sa_handler = sighandler; + // sigemptyset(&sigact.sa_mask); + // sigact.sa_flags = 0; + // sigaction(SIGINT, &sigact, NULL); + // sigaction(SIGTERM, &sigact, NULL); + // sigaction(SIGQUIT, &sigact, NULL); + // sigaction(SIGPIPE, &sigact, NULL); if (demod.deemph) { demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6))))); @@ -951,20 +926,18 @@ void open_rtlsdr_stream() pthread_create(&controller.thread, NULL, controller_thread_fn, (void*)(&controller)); usleep(100000); - pthread_create(&output.thread, NULL, output_thread_fn, (void*)(&output)); pthread_create(&demod.thread, NULL, demod_thread_fn, (void*)(&demod)); pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void*)(&dongle)); - printf("done opening stream\n"); } void cleanup_rtlsdr_stream() { + printf("cleaning up...\n"); rtlsdr_cancel_async(dongle.dev); pthread_join(dongle.thread, NULL); safe_cond_signal(&demod.ready, &demod.ready_m); pthread_join(demod.thread, NULL); safe_cond_signal(&output.ready, &output.ready_m); - pthread_join(output.thread, NULL); safe_cond_signal(&controller.hop, &controller.hop_m); pthread_join(controller.thread, NULL); @@ -976,11 +949,15 @@ void cleanup_rtlsdr_stream() rtlsdr_close(dongle.dev); } -extern "C" void get_rtlsdr_sample(int16_t *sample); void get_rtlsdr_sample(int16_t *sample) { - printf("getting sample\n"); - safe_cond_wait(&output.ready, &output.ready_m); + if (output.queue.empty()) + { + safe_cond_wait(&output.ready, &output.ready_m); + } + pthread_rwlock_wrlock(&output.rw); *sample = output.queue.front(); output.queue.pop(); + pthread_rwlock_unlock(&output.rw); +} } From 2bdcc9cc65e4b011b72284a2837940ff50bab302 Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Sat, 16 Jan 2021 22:33:27 -0500 Subject: [PATCH 03/14] Update deps --- .travis.yml | 3 ++- debian/control | 6 +++--- debian/copyright | 10 +++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index d81eecc..3bc5da6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: cpp -dist: trusty +dist: bionic sudo: false compiler: @@ -14,6 +14,7 @@ addons: - libmbe-dev - libsndfile1-dev - libitpp-dev + - librtlsdr-dev - portaudio19-dev before_script: diff --git a/debian/control b/debian/control index 58239bc..0479cf4 100644 --- a/debian/control +++ b/debian/control @@ -2,8 +2,8 @@ Source: dsd Section: hamradio Priority: optional Maintainer: Jared Szechy -Build-Depends: debhelper (>= 9), libmbe-dev, libitpp-dev, libsndfile1-dev, - portaudio19-dev, cmake, git, help2man +Build-Depends: debhelper (>= 9), libmbe-dev, libitpp-dev, librtlsdr-dev + libsndfile1-dev, portaudio19-dev, cmake, git, help2man Standards-Version: 4.1.4 Homepage: https://github.com/szechyjs/dsd Vcs-Git: https://github.com/szechyjs/dsd.git @@ -17,4 +17,4 @@ Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends} Description: Digital Speech Decoder DSD is able to decode several digital voice formats from discriminator tap - audio and synthesize the decoded speech. \ No newline at end of file + audio and synthesize the decoded speech. diff --git a/debian/copyright b/debian/copyright index 898cf45..46dadab 100644 --- a/debian/copyright +++ b/debian/copyright @@ -20,6 +20,14 @@ Files: src/dstar_header.c include/dstar_header.h include/fcs.h Copyright: Copyright (C) 2010 by Kristoff Bonne, ON1ARF License: GPL-2 +Files: src/rtl_sdr_fm.cpp +Copyright: Copyright (C) 2012 by Steve Markgraf + Copyright (C) 2012 by Hoernchen + Copyright (C) 2012 by Kyle Keen + Copyright (C) 2013 by Elias Oenal + Copyright (C) 2014 by Kyle Keen +License: GPL-2 + Files: include/descramble.h Copyright: Copyright (C) 2011 by Jonathan Naylor, G4KLX License: GPL-2 @@ -103,4 +111,4 @@ License: BSL-1.0 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. \ No newline at end of file + DEALINGS IN THE SOFTWARE. From f0f067510f8cf6a22fc69f4428889866b5ec1e36 Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Sat, 16 Jan 2021 22:49:34 -0500 Subject: [PATCH 04/14] Require threads --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23eb391..fd2c0d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,14 +22,19 @@ if(PORTAUDIO_FOUND) endif(PORTAUDIO_FOUND) if(RTLSDR_FOUND) + find_package(Threads) include_directories(SYSTEM ${RTLSDR_INCLUDE_DIRS}) - list(APPEND LIBS ${RTLSDR_LIBRARIES}) + list(APPEND LIBS ${RTLSDR_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) add_definitions(-DUSE_RTLSDR) endif(RTLSDR_FOUND) FILE(GLOB SRCS src/*.c src/*.cpp) FILE(GLOB HEADERS include/*.h include/*.hpp) +if(NOT RTLSDR_FOUND) + list(REMOVE_ITEM SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_sdr_fm.cpp) +endif(NOT RTLSDR_FOUND) + configure_file("src/git_ver.c.in" "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c" @ONLY) list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c") From 5324d53c47baa08e2131bb467814969708f129d0 Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Sun, 17 Jan 2021 19:37:00 -0500 Subject: [PATCH 05/14] Add center freq cli opt --- include/dsd.h | 16 +++++++++------- src/dsd_main.c | 35 +++++++++++++++++++++++++++++++++-- src/rtl_sdr_fm.cpp | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index 5d073aa..3dc6949 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -67,7 +67,6 @@ */ static volatile int exitflag; - typedef struct { int onesymbol; @@ -89,9 +88,7 @@ typedef struct #ifdef USE_PORTAUDIO PaStream* audio_in_pa_stream; #endif -#ifdef USE_RTLSDR - rtlsdr_dev_t *rtlSdrDev; -#endif + uint32_t rtlsdr_center_freq; int audio_in_type; // 0 for device, 1 for file, 2 for portaudio, 3 for rtlsdr char audio_out_dev[1024]; int audio_out_fd; @@ -324,10 +321,15 @@ void processDSTAR_HD (dsd_opts * opts, dsd_state * state); short dmr_filter(short sample); short nxdn_filter(short sample); -void open_rtlsdr_stream(); +#ifdef __cplusplus +extern "C" { +#endif +void open_rtlsdr_stream(dsd_opts *opts); void cleanup_rtlsdr_stream(); -void get_rtlsdr_sample(); +void get_rtlsdr_sample(int16_t *sample); void rtlsdr_sighandler(); - +#ifdef __cplusplus +} +#endif #endif // DSD_H diff --git a/src/dsd_main.c b/src/dsd_main.c index 7982c8b..5231cd3 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -274,6 +274,7 @@ usage () printf (" -n Do not send synthesized speech to audio output device\n"); printf (" -w Output synthesized speech to a .wav file\n"); printf (" -a Display port audio devices\n"); + printf (" -c RTL-SDR center frequency\n"); printf ("\n"); printf ("Scanner control options:\n"); printf (" -B Serial port baud rate (default=115200)\n"); @@ -331,7 +332,7 @@ liveScanner (dsd_opts * opts, dsd_state * state) #ifdef USE_RTLSDR if(opts->audio_in_type == 3) { - open_rtlsdr_stream(); + open_rtlsdr_stream(opts); } #endif while (1) @@ -466,6 +467,32 @@ sigfun (int sig) #endif } +double atofs(char *s) +{ + char last; + int len; + double suff = 1.0; + len = strlen(s); + last = s[len-1]; + s[len-1] = '\0'; + switch (last) { + case 'g': + case 'G': + suff *= 1e3; + case 'm': + case 'M': + suff *= 1e3; + case 'k': + case 'K': + suff *= 1e3; + suff *= atof(s); + s[len-1] = last; + return suff; + } + s[len-1] = last; + return atof(s); +} + int main (int argc, char **argv) { @@ -486,7 +513,7 @@ main (int argc, char **argv) exitflag = 0; signal (SIGINT, sigfun); - while ((c = getopt (argc, argv, "haep:qstv:z:i:o:d:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1) + while ((c = getopt (argc, argv, "haep:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1) { opterr = 0; switch (c) @@ -568,6 +595,10 @@ main (int argc, char **argv) opts.mbe_out_dir[1023] = '\0'; printf ("Writing mbe data files to directory %s\n", opts.mbe_out_dir); break; + case 'c': + opts.rtlsdr_center_freq = (uint32_t)atofs(optarg); + printf("Using center freq: %i\n", opts.rtlsdr_center_freq); + break; case 'g': sscanf (optarg, "%f", &opts.audio_gain); if (opts.audio_gain < (float) 0 ) diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index 9f34e5a..ea4e190 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -29,6 +29,7 @@ #include #include #include +#include "dsd.h" #define DEFAULT_SAMPLE_RATE 48000 #define DEFAULT_BUF_LENGTH (1 * 16384) @@ -39,10 +40,6 @@ #define FREQUENCIES_LIMIT 1000 -extern "C" { - volatile int exitflag; -} - static int lcm_post[17] = {1,1,1,3,1,5,3,7,1,9,5,11,3,13,7,15,1}; static int ACTUAL_BUF_LENGTH; @@ -850,7 +847,7 @@ void output_cleanup(struct output_state *s) void controller_init(struct controller_state *s) { - s->freqs[0] = 451800000; + s->freqs[0] = 446000000; s->freq_len = 0; s->edge = 0; s->wb_mode = 0; @@ -864,14 +861,32 @@ void controller_cleanup(struct controller_state *s) pthread_mutex_destroy(&s->hop_m); } -extern "C" { +void sanity_checks(void) +{ + if (controller.freq_len == 0) { + fprintf(stderr, "Please specify a frequency.\n"); + exit(1); + } + + if (controller.freq_len >= FREQUENCIES_LIMIT) { + fprintf(stderr, "Too many channels, maximum %i.\n", FREQUENCIES_LIMIT); + exit(1); + } + + if (controller.freq_len > 1 && demod.squelch_level == 0) { + fprintf(stderr, "Please specify a squelch level. Required for scanning multiple frequencies.\n"); + exit(1); + } + +} + void rtlsdr_sighandler() { fprintf(stderr, "Signal caught, exiting!\n"); rtlsdr_cancel_async(dongle.dev); } -void open_rtlsdr_stream() +void open_rtlsdr_stream(dsd_opts *opts) { struct sigaction sigact; int r; @@ -881,12 +896,17 @@ void open_rtlsdr_stream() output_init(&output); controller_init(&controller); + if (opts->rtlsdr_center_freq > 0) { + controller.freqs[controller.freq_len] = opts->rtlsdr_center_freq; + controller.freq_len++; + } + /* quadruple sample_rate to limit to Δθ to ±π/2 */ demod.rate_in *= demod.post_downsample; if (!output.rate) output.rate = demod.rate_out; - // sanity_checks(); + sanity_checks(); if (controller.freq_len > 1) demod.terminate_on_squelch = 0; @@ -960,4 +980,3 @@ void get_rtlsdr_sample(int16_t *sample) output.queue.pop(); pthread_rwlock_unlock(&output.rw); } -} From f383d165fd5cd7f2eff937a190a70646d818cb13 Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Thu, 21 Jan 2021 23:14:04 -0500 Subject: [PATCH 06/14] Add ppm_error option --- include/dsd.h | 1 + src/dsd_main.c | 6 +++++- src/rtl_sdr_fm.cpp | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/dsd.h b/include/dsd.h index 3dc6949..1171d75 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -89,6 +89,7 @@ typedef struct PaStream* audio_in_pa_stream; #endif uint32_t rtlsdr_center_freq; + int rtlsdr_ppm_error; int audio_in_type; // 0 for device, 1 for file, 2 for portaudio, 3 for rtlsdr char audio_out_dev[1024]; int audio_out_fd; diff --git a/src/dsd_main.c b/src/dsd_main.c index 5231cd3..075175e 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -275,6 +275,7 @@ usage () printf (" -w Output synthesized speech to a .wav file\n"); printf (" -a Display port audio devices\n"); printf (" -c RTL-SDR center frequency\n"); + printf (" -P RTL-SDR ppm error (default = 0)\n"); printf ("\n"); printf ("Scanner control options:\n"); printf (" -B Serial port baud rate (default=115200)\n"); @@ -513,7 +514,7 @@ main (int argc, char **argv) exitflag = 0; signal (SIGINT, sigfun); - while ((c = getopt (argc, argv, "haep:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1) + while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1) { opterr = 0; switch (c) @@ -550,6 +551,9 @@ main (int argc, char **argv) opts.unmute_encrypted_p25 = 1; } break; + case 'P': + sscanf (optarg, "%i", &opts.rtlsdr_ppm_error); + break; case 'q': opts.errorbars = 0; opts.verbose = 0; diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index ea4e190..b8b6cb5 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -901,6 +901,10 @@ void open_rtlsdr_stream(dsd_opts *opts) controller.freq_len++; } + if (opts->rtlsdr_ppm_error > 0) { + dongle.ppm_error = opts->rtlsdr_ppm_error; + } + /* quadruple sample_rate to limit to Δθ to ±π/2 */ demod.rate_in *= demod.post_downsample; From 2523383b140f6c15aa6da7285c1b6dd1dcf7f31a Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Sat, 29 Jan 2022 21:53:35 -0500 Subject: [PATCH 07/14] Add More RTL Options, UDP Remote Add Gain and Device Index Number for RTL, add UDP remote to control frequency and squelch of RTL. Other Random things. --- CMakeLists.txt | 6 +- cmake/FindCURSES.cmake | 16 ++++ cmake/FindNCURSES.cmake | 15 ++++ include/dsd.h | 3 + src/dsd_audio.c | 101 +++++++++++++++++++--- src/dsd_file.c | 3 +- src/dsd_frame.c | 14 ++-- src/dsd_frame_sync.c | 69 ++++++++++++++- src/dsd_main.c | 138 ++++++++++++++++++++++++------ src/dsd_mbe.c | 1 + src/provoice.c | 151 ++++++++++++++++----------------- src/rtl_sdr_fm.cpp | 180 ++++++++++++++++++++++++++++++++++++++-- src/todolist | 9 ++ 13 files changed, 574 insertions(+), 132 deletions(-) create mode 100644 cmake/FindCURSES.cmake create mode 100644 cmake/FindNCURSES.cmake create mode 100644 src/todolist diff --git a/CMakeLists.txt b/CMakeLists.txt index fd2c0d0..cdf3e4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,11 @@ find_package(MBE REQUIRED) find_package(ITPP REQUIRED) find_package(LibPortAudio) find_package(RTLSDR) +#more fucking around +find_package(Curses REQUIRED) -include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR}) -set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY}) +include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${CURSES_INCLUDE_DIR}) +set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${CURSES_LIBRARY}) if(PORTAUDIO_FOUND) include_directories(SYSTEM ${PORTAUDIO_INCLUDE_DIRS}) diff --git a/cmake/FindCURSES.cmake b/cmake/FindCURSES.cmake new file mode 100644 index 0000000..29818ba --- /dev/null +++ b/cmake/FindCURSES.cmake @@ -0,0 +1,16 @@ +# - Try to find NCURSES +# Once done this will define +# +# ITPP_FOUND - System has ITPP +# ITPP_INCLUDE_DIR - The ITPP include directory +# ITPP_LIBRARY - The library needed to use ITPP +# +set(CURSES_LIBRARY "/opt/lib/libncurses.so") +set(CURSES_INCLUDE_PATH "/opt/include") +find_path(CURSES_INCLUDE_DIR /usr/ncurses.h) + +set(CURSES_NAMES ${CURSES_NAMES} curses.h curses curses5w curses6w curses6 curses5 libncursesw) +FIND_LIBRARY(CURSES_LIBRARY NAMES ${CURSES_NAMES}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CURSES DEFAULT_MSG NCURSES_LIBRARY CURSES_INCLUDE_DIR) diff --git a/cmake/FindNCURSES.cmake b/cmake/FindNCURSES.cmake new file mode 100644 index 0000000..93b8210 --- /dev/null +++ b/cmake/FindNCURSES.cmake @@ -0,0 +1,15 @@ +# - Try to find NCURSES +# Once done this will define +# +# ITPP_FOUND - System has ITPP +# ITPP_INCLUDE_DIR - The ITPP include directory +# ITPP_LIBRARY - The library needed to use ITPP +# + +find_path(ITPP_INCLUDE_DIR itpp/itcomm.h) + +set(NCURSES_NAMES ${NCURSES_NAMES} curses.h ncurses ncurses5w ncurses6w ncurses6 ncurses5 libncursesw) +FIND_LIBRARY(NCURSES_LIBRARY NAMES ${NCURSES_NAMES}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NCURSES DEFAULT_MSG NCURSES_LIBRARY NCURSES_INCLUDE_DIR) diff --git a/include/dsd.h b/include/dsd.h index 1171d75..16583a7 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -66,6 +66,7 @@ * global variables */ static volatile int exitflag; +//volatile int exitflag; //didn't work, couldn't build, multiple definitions of exitflag typedef struct { @@ -134,6 +135,8 @@ typedef struct int delay; int use_cosine_filter; int unmute_encrypted_p25; + int rtl_dev_index; + int rtl_gain_value; } dsd_opts; typedef struct diff --git a/src/dsd_audio.c b/src/dsd_audio.c index e706deb..6c7ab9c 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -17,7 +17,6 @@ #include "dsd.h" - void processAudio (dsd_opts * opts, dsd_state * state) { @@ -164,7 +163,7 @@ writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) // for(n=0; n<160; n++) // printf("%d ", ((short*)(state->audio_out_temp_buf))[n]); // printf("\n"); - + aout_buf_p = aout_buf; state->audio_out_temp_buf_p = state->audio_out_temp_buf; @@ -214,6 +213,84 @@ writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) */ } +//Test playing raw audio HERE +//get_rtlsdr_sample(&sample); +void +playRawAudio (dsd_opts * opts, dsd_state * state) +{ + ssize_t result; + + //if (state->audio_out_idx > opts->delay) + if (opts->audio_in_type == 3) //if set to rtl_fm, maybe it shouldn't matter but for now, using this + { + // output synthesized speech to sound card + if(opts->audio_out_type == 2) + { +#ifdef USE_PORTAUDIO + PaError err = paNoError; + do + { + long available = Pa_GetStreamWriteAvailable( opts->audio_out_pa_stream ); + if(available < 0) + err = available; + //printf("Frames available: %d\n", available); + if( err != paNoError ) + break; + if(available > SAMPLE_RATE_OUT * PA_LATENCY_OUT) + { + //It looks like this might not be needed for very small latencies. However, it's definitely needed for a bit larger ones. + //When PA_LATENCY_OUT == 0.500 I get output buffer underruns if I don't use this. With PA_LATENCY_OUT <= 0.100 I don't see those happen. + //But with PA_LATENCY_OUT < 0.100 I run the risk of choppy audio and stream errors. + printf("\nSyncing voice output stream\n"); + err = Pa_StopStream( opts->audio_out_pa_stream ); + if( err != paNoError ) + break; + } + + err = Pa_IsStreamActive( opts->audio_out_pa_stream ); + if(err == 0) + { + printf("Start voice output stream\n"); + err = Pa_StartStream( opts->audio_out_pa_stream ); + } + else if(err == 1) + { + err = paNoError; + } + if( err != paNoError ) + break; + + //printf("write stream %d\n", state->audio_out_idx); + err = Pa_WriteStream( opts->audio_out_pa_stream, (state->audio_out_buf_p - state->audio_out_idx), state->audio_out_idx ); + if( err != paNoError ) + break; + } while(0); + + if( err != paNoError ) + { + fprintf( stderr, "An error occured while using the portaudio output stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + } + +#endif + } + else + result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2)); + state->audio_out_idx = 0; + } + + if (state->audio_out_idx2 >= 800000) + { + 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; + } +} + +//end test raw audio void playSynthesizedVoice (dsd_opts * opts, dsd_state * state) @@ -309,7 +386,7 @@ int getPADevice(char* dev, int input, PaStream** stream) printf( "ERROR: Requested device %d is larger than number of devices.\n", devnum ); return(1); } - + const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( devnum ); /* print device name */ @@ -500,7 +577,7 @@ openAudioInDevice (dsd_opts * opts) exit(1); #endif } - else if(strncmp(opts->audio_in_dev, "rtl:", 3) == 0) + else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0) { opts->audio_in_type = 3; } @@ -533,9 +610,9 @@ openAudioInDevice (dsd_opts * opts) #ifdef SOLARIS sample_info_t aset, aget; int rgain; - + rgain = 64; - + if (opts->split == 1) { opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY); @@ -549,10 +626,10 @@ openAudioInDevice (dsd_opts * opts) printf ("Error, couldn't open %s\n", opts->audio_in_dev); exit(1); } - + // get current ioctl (opts->audio_in_fd, AUDIO_GETINFO, &aset); - + aset.record.sample_rate = SAMPLE_RATE_IN; aset.play.sample_rate = SAMPLE_RATE_IN; aset.record.channels = 1; @@ -563,7 +640,7 @@ openAudioInDevice (dsd_opts * opts) aset.play.encoding = AUDIO_ENCODING_LINEAR; aset.record.port = AUDIO_LINE_IN; aset.record.gain = rgain; - + if (ioctl (opts->audio_in_fd, AUDIO_SETINFO, &aset) == -1) { printf ("Error setting sample device parameters\n"); @@ -573,7 +650,7 @@ openAudioInDevice (dsd_opts * opts) #if defined(BSD) && !defined(__APPLE__) int fmt; - + if (opts->split == 1) { opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY); @@ -582,13 +659,13 @@ openAudioInDevice (dsd_opts * opts) { opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR); } - + if (opts->audio_in_fd == -1) { printf ("Error, couldn't open %s\n", opts->audio_in_dev); opts->audio_out = 0; } - + fmt = 0; if (ioctl (opts->audio_in_fd, SNDCTL_DSP_RESET) < 0) { diff --git a/src/dsd_file.c b/src/dsd_file.c index c805885..36f7dee 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -211,7 +211,8 @@ closeMbeOutFile (dsd_opts * opts, dsd_state * state) fclose (opts->mbe_out_f); opts->mbe_out_f = NULL; strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep); - sprintf (newfilename, "nac%X-%s-tg%i%s", state->nac, datestr, talkgroup, ext); + //sprintf (newfilename, "nac%X-%s-tg%i%s", state->nac, datestr, talkgroup, ext); + sprintf (newfilename, "%s%s", datestr, ext); //this one sprintf (new_path, "%s%s", opts->mbe_out_dir, newfilename); #ifdef _WIN32 sprintf (shell, "move %s %s", opts->mbe_out_path, new_path); diff --git a/src/dsd_frame.c b/src/dsd_frame.c index 539c391..8234ff1 100644 --- a/src/dsd_frame.c +++ b/src/dsd_frame.c @@ -31,7 +31,7 @@ printFrameInfo (dsd_opts * opts, dsd_state * state) level = (int) state->max / 164; if (opts->verbose > 0) { - printf ("inlvl: %2i%% ", level); + //printf ("inlvl: %2i%% ", level); } if (state->nac != 0) { @@ -89,7 +89,7 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->verbose > 0) { level = (int) state->max / 164; - printf ("inlvl: %2i%% ", level); + //printf ("inlvl: %2i%% ", level); } } state->nac = 0; @@ -112,7 +112,7 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->verbose > 0) { level = (int) state->max / 164; - printf ("inlvl: %2i%% ", level); + //printf ("inlvl: %2i%% ", level); } } state->nac = 0; @@ -134,7 +134,7 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->verbose > 0) { level = (int) state->max / 164; - printf ("inlvl: %2i%% ", level); + //printf ("inlvl: %2i%% ", level); } } state->nac = 0; @@ -156,7 +156,7 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->verbose > 0) { level = (int) state->max / 164; - printf ("inlvl: %2i%% ", level); + //printf ("inlvl: %2i%% ", level); } } state->nac = 0; @@ -179,7 +179,7 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->verbose > 0) { level = (int) state->max / 164; - printf ("inlvl: %2i%% ", level); + //printf ("inlvl: %2i%% ", level); } } if ((state->synctype == 11) || (state->synctype == 12)) @@ -233,7 +233,7 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->verbose > 0) { level = (int) state->max / 164; - printf ("inlvl: %2i%% ", level); + //printf ("inlvl: %2i%% ", level); } } if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index 1993c23..796bf06 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -16,27 +16,81 @@ */ #include "dsd.h" +#include +#include +char * FM_banner2[9] = { + " Digital Speech Decoder: Florida Man Edition - mbelib version 1.3.0 ", + " ███████╗██████╗ █████╗ █████╗ ██████╗ ███████╗███╗ ███╗ ██████╗ ", + " ██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝ ██╔════╝████╗ ████║ ██╔══██╗", + " █████╗ ██║ ██║███████║██║ ╚═╝╚█████╗ ███ █████╗ ██╔████╔██║█████████║", + " ██╔══╝ ██║ ██║██╔══██║██║ ██╗ ╚═══██╗ ██╔══╝ ██║╚██╔╝██║ ██║ ██║", + " ███████╗██████╔╝██║ ██║╚█████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║ ██████╔╝", + " ╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ", +}; +time_t now; +char * getTime(void) //get pretty hh:mm:ss timestamp +{ + time_t t = time(NULL); + + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; +} + +char * getDate(void) { + char datename[32]; + 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; +} + void printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation) { + //char datestr[32]; + //struct tm timep; + erase(); + attron(COLOR_PAIR(4)); + for (short int i = 0; i < 7; i++) { + printw("%s \n", FM_banner2[i]);} + attroff(COLOR_PAIR(4)); if (opts->verbose > 0) { - printf ("Sync: %s ", frametype); + //strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep); + //printf ("Sync: %s ", frametype); + //printf ("%s %s Sync: %s ", getDate(), getTime(), frametype); + printf ("%s Sync: %s ", getTime(), frametype); + printw("%s Sync: %s ", getTime(), frametype); } if (opts->verbose > 2) { printf ("o: %4i ", offset); + printw("o: %4i ", offset); } if (opts->verbose > 1) { printf ("mod: %s ", modulation); + printw("mod: %s ", modulation); } if (opts->verbose > 2) { printf ("g: %f ", state->aout_gain); + printw("g: %f ", state->aout_gain); } + refresh(); } int @@ -100,6 +154,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) if ((opts->symboltiming == 1) && (state->carrier == 1)) { printf ("\nSymbol Timing:\n"); + //printw("\nSymbol Timing:\n"); } while (sync == 0) { @@ -489,8 +544,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->min = ((state->min) + lmin) / 2; sprintf (state->ftype, " ProVoice "); if (opts->errorbars == 1) + //if (opts->errorbars == 1 && (time(NULL) - now) > 2 ) { printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation); + now = time(NULL); } state->lastsynctype = 14; return (14); @@ -503,8 +560,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->min = ((state->min) + lmin) / 2; sprintf (state->ftype, " ProVoice "); if (opts->errorbars == 1) + //if (opts->errorbars == 1 && (time(NULL) - now) > 2 ) { printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation); + now = time(NULL); } state->lastsynctype = 15; return (15); @@ -819,6 +878,14 @@ getFrameSync (dsd_opts * opts, dsd_state * state) if ((opts->errorbars == 1) && (opts->verbose > 1) && (state->carrier == 1)) { printf ("Sync: no sync\n"); + printf("Press CTRL + C to close.\n"); //Kindly remind user to double tap CTRL + C + erase(); + attron(COLOR_PAIR(4)); + for (short int i = 0; i < 7; i++) { + printw("%s \n", FM_banner2[i]); } + attroff(COLOR_PAIR(4)); + printw("Sync: no sync\n"); + refresh(); } noCarrier (opts, state); return (-1); diff --git a/src/dsd_main.c b/src/dsd_main.c index 075175e..c52b5a6 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -28,6 +28,17 @@ #include "p25p1_heuristics.h" #include "pa_devs.h" +#include +#include +char * FM_banner[9] = { + " CTRL + C twice to exit", + "██████╗ ██████╗██████╗    ███████╗███╗ ███╗███████╗", + "██╔══██╗██╔════╝██╔══██╗   ██╔════╝████╗ ████║██╔════╝", + "██║ ██║╚█████╗ ██║ ██║   █████╗ ██╔████╔██║█████╗ ", + "██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ ", + "██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗", + "╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝", +}; int comp (const void *a, const void *b) @@ -79,6 +90,11 @@ noCarrier (dsd_opts * opts, dsd_state * state) sprintf (state->algid, "________"); sprintf (state->keyid, "________________"); mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + //test below + //uint16_t sample; + //get_rtlsdr_sample(&sample); + //Pa_StartStream(sample); + //end test } void @@ -141,6 +157,8 @@ initOpts (dsd_opts * opts) opts->delay = 0; opts->use_cosine_filter = 1; opts->unmute_encrypted_p25 = 0; + opts->rtl_dev_index = 0; //actual device index since rtl:0 or rtl:1 doesn't do jack shit asshole! + opts->rtl_gain_value = 0; //set actual gain and not this automatic gain bullshit } void @@ -266,16 +284,20 @@ usage () printf (" -z Frame rate for datascope\n"); printf ("\n"); printf ("Input/Output options:\n"); - printf (" -i Audio input device (default is /dev/audio, - for piped stdin)\n"); + printf (" -i Audio input device (default is /dev/audio, - for piped stdin, rtl for rtl device)\n"); printf (" -o Audio output device (default is /dev/audio)\n"); printf (" -d Create mbe data files, use this directory\n"); - printf (" -r Read/Play saved mbe data from file(s)\n"); + printf (" -r Read/Play saved mbe data from file(s)\n"); printf (" -g Audio output gain (default = 0 = auto, disable = -1)\n"); printf (" -n Do not send synthesized speech to audio output device\n"); - printf (" -w Output synthesized speech to a .wav file\n"); + printf (" -w Output synthesized speech to a .wav file\n"); printf (" -a Display port audio devices\n"); - printf (" -c RTL-SDR center frequency\n"); + printf ("\n"); + printf ("RTL-SDR options:\n"); + printf (" -c RTL-SDR tune to 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 ("\n"); printf ("Scanner control options:\n"); printf (" -B Serial port baud rate (default=115200)\n"); @@ -286,7 +308,7 @@ usage () printf (" -fa Auto-detect frame type (default)\n"); printf (" -f1 Decode only P25 Phase 1\n"); printf (" -fd Decode only D-STAR\n"); - printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\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 (" -fr Decode only DMR/MOTOTRBO\n"); @@ -323,9 +345,9 @@ liveScanner (dsd_opts * opts, dsd_state * state) PaError err = Pa_StartStream( opts->audio_in_pa_stream ); if( err != paNoError ) { - fprintf( stderr, "An error occured while starting the portaudio input stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + //fprintf( stderr, "An error occured while starting the portaudio input stream\n" ); + //fprintf( stderr, "Error number: %d\n", err ); + //fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return; } } @@ -385,9 +407,9 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) err = Pa_CloseStream( opts->audio_in_pa_stream ); if( err != paNoError ) { - fprintf( stderr, "An error occured while closing the portaudio input stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + //fprintf( stderr, "An error occured while closing the portaudio input stream\n" ); + //fprintf( stderr, "Error number: %d\n", err ); + //fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); } } if(opts->audio_out_pa_stream != NULL) @@ -397,24 +419,24 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) err = Pa_StopStream( opts->audio_out_pa_stream ); if( err != paNoError ) { - fprintf( stderr, "An error occured while closing the portaudio output stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + //fprintf( stderr, "An error occured while closing the portaudio output stream\n" ); + //fprintf( stderr, "Error number: %d\n", err ); + //fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); } err = Pa_CloseStream( opts->audio_out_pa_stream ); if( err != paNoError ) { - fprintf( stderr, "An error occured while closing the portaudio output stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + //fprintf( stderr, "An error occured while closing the portaudio output stream\n" ); + //fprintf( stderr, "Error number: %d\n", err ); + //fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); } } err = Pa_Terminate(); if( err != paNoError ) { - fprintf( stderr, "An error occured while terminating portaudio\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + //fprintf( stderr, "An error occured while terminating portaudio\n" ); + //fprintf( stderr, "Error number: %d\n", err ); + //fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); } } #endif @@ -468,6 +490,32 @@ sigfun (int sig) #endif } +//LEH version of sigfun +/* +void sigfun (int sig) +{ + UNUSED_VARIABLE(sig); //what is this and where is it defined? + exitflag = 1; + signal (SIGINT, SIG_DFL); +} + +//another LEH thing to free allocated memory +void freeAllocatedMemory(dsd_opts * opts, dsd_state * state) +{ + UNUSED_VARIABLE(opts); + + // Free allocated memory // + free(state->prev_mp_enhanced); + free(state->prev_mp); + free(state->cur_mp); + free(state->audio_out_float_buf); + free(state->audio_out_buf); + free(state->dibit_buf); +} + +*/ +//end LEH version of sigfun + double atofs(char *s) { char last; @@ -505,7 +553,12 @@ main (int argc, char **argv) char versionstr[25]; mbe_printVersion (versionstr); - printf ("Digital Speech Decoder 1.7.0-dev (build:%s)\n", GIT_TAG); + + for (short int i = 0; i < 7; i++) { + printf("%s \n", FM_banner[i]); + } + //printf ("Digital Speech Decoder 1.7.0-dev (build:%s)\n", GIT_TAG); + printf ("Digital Speech Decoder: Florida Man Edition\n"); printf ("mbelib version %s\n", versionstr); initOpts (&opts); @@ -514,7 +567,7 @@ main (int argc, char **argv) exitflag = 0; signal (SIGINT, sigfun); - while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1) + while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:rl")) != -1) { opterr = 0; switch (c) @@ -575,6 +628,18 @@ main (int argc, char **argv) case 'v': sscanf (optarg, "%d", &opts.verbose); break; + + case 'G': //Set rtl device gain + sscanf (optarg, "%d", &opts.rtl_gain_value); //multiple value by ten to make it consitent with the way rtl_fm really works + //opts->audio_in_type = 3; //set to use RTL this way and maybe ditch the other shitty way + break; + + case 'D': //Set rtl device index number + sscanf (optarg, "%d", &opts.rtl_dev_index); + //opts->audio_in_type = 3; //set to use RTL this way and maybe ditch the other shitty way + break; + + case 'z': sscanf (optarg, "%d", &opts.scoperate); opts.errorbars = 0; @@ -589,6 +654,7 @@ main (int argc, char **argv) case 'i': strncpy(opts.audio_in_dev, optarg, 1023); opts.audio_in_dev[1023] = '\0'; + //printf("audio_in_dev = %s\n", opts.audio_in_dev); break; case 'o': strncpy(opts.audio_out_dev, optarg, 1023); @@ -601,7 +667,7 @@ main (int argc, char **argv) break; case 'c': opts.rtlsdr_center_freq = (uint32_t)atofs(optarg); - printf("Using center freq: %i\n", opts.rtlsdr_center_freq); + printf("Tuning to frequency: %i\n", opts.rtlsdr_center_freq); break; case 'g': sscanf (optarg, "%f", &opts.audio_gain); @@ -866,9 +932,9 @@ main (int argc, char **argv) PaError err = Pa_Initialize(); if( err != paNoError ) { - fprintf( stderr, "An error occured while initializing portaudio\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + //fprintf( stderr, "An error occured while initializing portaudio\n" ); + //fprintf( stderr, "Error number: %d\n", err ); + //fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); exit(err); } } @@ -902,7 +968,25 @@ main (int argc, char **argv) openAudioOutDevice (&opts, SAMPLE_RATE_OUT); } openAudioInDevice (&opts); + setlocale(LC_ALL, ""); + //sleep(3); + //initscr(); //Initialize NCURSES screen window + start_color(); + 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 + noecho(); + cbreak(); + erase(); + for (short int i = 0; i < 7; i++) { + printw("%s \n", FM_banner[i]); } + attroff(COLOR_PAIR(4)); + refresh(); + printf("Press CTRL + C twice to close.\n"); //Kindly remind user to double tap CTRL + C } + else { opts.split = 0; @@ -916,10 +1000,12 @@ main (int argc, char **argv) { playMbeFiles (&opts, &state, argc, argv); } + else { liveScanner (&opts, &state); } cleanupAndExit (&opts, &state); + endwin(); return (0); } diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index 3e93a82..35c37c1 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -135,6 +135,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a if (opts->errorbars == 1) { printf ("%s", state->err_str); + //printw("%s", state->err_str); } state->debug_audio_errors += state->errs2; diff --git a/src/provoice.c b/src/provoice.c index 2c01329..799cbdd 100644 --- a/src/provoice.c +++ b/src/provoice.c @@ -5,25 +5,28 @@ void processProVoice (dsd_opts * opts, dsd_state * state) { int i, j, dibit; - + //char datestr[32]; char imbe7100_fr1[7][24]; char imbe7100_fr2[7][24]; const int *w, *x; + //struct tm timep; if (opts->errorbars == 1) { - printf ("VOICE e:"); + //strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep); + //printf ("%s VOICE e:", datestr); + //printf ("VOICE e:"); } for (i = 0; i < 64; i++) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif // lid @@ -31,22 +34,22 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif for (i = 0; i < 64; i++) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif // imbe frames 1,2 first half @@ -59,14 +62,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 6; x -= 6; @@ -74,14 +77,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif } @@ -89,14 +92,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 6; x -= 6; @@ -104,25 +107,25 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif // spacer bits dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); - printf (" "); + //printf ("%i", dibit); + //printf (" "); #endif // imbe frames 1,2 second half @@ -131,14 +134,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif for (i = 0; i < 3; i++) @@ -147,14 +150,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 6; x -= 6; @@ -162,14 +165,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif } @@ -177,14 +180,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 5; x -= 5; @@ -192,14 +195,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif for (i = 0; i < 7; i++) @@ -208,14 +211,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 6; x -= 6; @@ -223,14 +226,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif } @@ -238,14 +241,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 5; x -= 5; @@ -253,14 +256,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1); @@ -269,23 +272,23 @@ processProVoice (dsd_opts * opts, dsd_state * state) // spacer bits dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); - printf (" "); + //printf ("%i", dibit); + //printf (" "); #endif for (i = 0; i < 16; i++) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif // imbe frames 3,4 first half @@ -297,14 +300,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 6; x -= 6; @@ -312,28 +315,28 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif } for (j = 0; j < 6; j++) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 6; x -= 6; @@ -341,25 +344,25 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif // spacer bits dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); - printf ("_"); + //printf ("%i", dibit); + //printf ("_"); #endif // imbe frames 3,4 second half @@ -367,14 +370,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif for (i = 0; i < 3; i++) { @@ -382,14 +385,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 6; x -= 6; @@ -397,14 +400,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif } @@ -412,14 +415,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 5; x -= 5; @@ -427,14 +430,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif for (i = 0; i < 7; i++) @@ -443,14 +446,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 6; x -= 6; @@ -458,14 +461,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif } @@ -473,14 +476,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr1[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf ("_"); + //printf ("_"); #endif w -= 5; x -= 5; @@ -488,14 +491,14 @@ processProVoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif imbe7100_fr2[*w][*x] = dibit; w++; x++; } #ifdef PROVOICE_DUMP - printf (" "); + //printf (" "); #endif processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1); @@ -504,12 +507,12 @@ processProVoice (dsd_opts * opts, dsd_state * state) // spacer bits dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); + //printf ("%i", dibit); #endif dibit = getDibit (opts, state); #ifdef PROVOICE_DUMP - printf ("%i", dibit); - printf (" "); + //printf ("%i", dibit); + //printf (" "); #endif if (opts->errorbars == 1) diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index b8b6cb5..a33b218 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -31,9 +31,9 @@ #include #include "dsd.h" -#define DEFAULT_SAMPLE_RATE 48000 +#define DEFAULT_SAMPLE_RATE 48000 //48000 #define DEFAULT_BUF_LENGTH (1 * 16384) -#define MAXIMUM_OVERSAMPLE 16 +#define MAXIMUM_OVERSAMPLE 16 //16 #define MAXIMUM_BUF_LENGTH (MAXIMUM_OVERSAMPLE * DEFAULT_BUF_LENGTH) #define AUTO_GAIN -100 #define BUFFER_DUMP 4096 @@ -46,7 +46,11 @@ static int ACTUAL_BUF_LENGTH; static int *atan_lut = NULL; static int atan_lut_size = 131072; /* 512 KB */ static int atan_lut_coef = 8; - +//new for UDP +#include +#include +static pthread_t socket_freq; +// struct dongle_state { int exit_flag; @@ -585,6 +589,7 @@ static void *demod_thread_fn(void *arg) int nearest_gain(rtlsdr_dev_t *dev, int target_gain) { + //target_gain = 36; int i, r, err1, err2, count, nearest; int* gains; r = rtlsdr_set_tuner_gain_mode(dev, 1); @@ -617,7 +622,8 @@ int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency) if (r < 0) { fprintf(stderr, "WARNING: Failed to set center freq.\n"); } else { - fprintf(stderr, "Tuned to %u Hz.\n", frequency); + //fprintf(stderr, "Tuned to %u Hz.\n", frequency); + fprintf(stderr, "Tuned to center frequency %u Hz.\n", frequency); } return r; } @@ -665,6 +671,7 @@ int verbose_offset_tuning(rtlsdr_dev_t *dev) int verbose_auto_gain(rtlsdr_dev_t *dev) { + int r; r = rtlsdr_set_tuner_gain_mode(dev, 0); if (r != 0) { @@ -677,6 +684,7 @@ int verbose_auto_gain(rtlsdr_dev_t *dev) int verbose_gain_set(rtlsdr_dev_t *dev, int gain) { + //gain = 36; int r; r = rtlsdr_set_tuner_gain_mode(dev, 1); if (r < 0) { @@ -694,6 +702,7 @@ int verbose_gain_set(rtlsdr_dev_t *dev, int gain) int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error) { + //ppm_error = -2; //fix this opt arg to accept negative float values, i.e. float or double?? int r; if (ppm_error == 0) { return 0;} @@ -715,10 +724,12 @@ int verbose_reset_buffer(rtlsdr_dev_t *dev) return r; } -static void optimal_settings(int freq, int rate) +//static void optimal_settings(struct fm_state *fm, int freq, int hopping) +static void optimal_settings(int freq, int rate) //why did you fuck with optimal settings? { // giant ball of hacks // seems unable to do a single pass, 2:1 + //int r, capture_freq, capture_rate; int capture_freq, capture_rate; struct dongle_state *d = &dongle; struct demod_state *dm = &demod; @@ -771,6 +782,7 @@ static void *controller_thread_fn(void *arg) /* Set the sample rate */ verbose_set_sample_rate(dongle.dev, dongle.rate); fprintf(stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample); + fprintf(stderr, "Press CTRL + C to close.\n"); //Kindly remind user to double tap CTRL + C while (!exitflag) { safe_cond_wait(&s->hop, &s->hop_m); @@ -791,8 +803,9 @@ void dongle_init(struct dongle_state *s) s->gain = AUTO_GAIN; // tenths of a dB s->mute = 0; s->direct_sampling = 0; - s->offset_tuning = 0; + s->offset_tuning = 0; //0 by default, but don't think it listens to proper frequency when 0, offset and tuned seem to be mixed up s->demod_target = &demod; + //s->dev_index = 1; //need to set dev_index from dsd_main as well... } void demod_init(struct demod_state *s) @@ -879,11 +892,148 @@ void sanity_checks(void) } } +//UDP remote all below HERE +static unsigned int chars_to_int(unsigned char* buf) { + + int i; + unsigned int val = 0; + + for(i=1; i<5; i++) { + val = val | ((buf[i]) << ((i-1)*8)); + } + + return val; +} + +static void *socket_thread_fn(void *arg) { + //struct fm_state *fm = arg; + struct demod_state *d = static_cast(arg); + int port = 6020; + int r, n; + int sockfd, newsockfd, portno; + socklen_t clilen; + unsigned char buffer[5]; + struct sockaddr_in serv_addr, cli_addr; + + sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if (sockfd < 0) { + perror("ERROR opening socket"); + } + + bzero((char *) &serv_addr, sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(port); + + if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + perror("ERROR on binding"); + } + + bzero(buffer,5); + + fprintf (stderr, "Main socket started! :-) Tuning enabled on UDP/%d \n", port); + + int new_freq, demod_type, new_squelch, new_gain, agc_mode; + + while((n = read(sockfd,buffer,5)) != 0) { + if(buffer[0] == 0) { + new_freq = chars_to_int(buffer); + dongle.freq = new_freq; //not sure if still needed, or ever was needed lul + optimal_settings(new_freq, demod.rate_in); + rtlsdr_set_center_freq(dongle.dev, dongle.freq); + //fprintf (stderr, "Tuning to: %d [Hz] (central freq: %d [Hz])\n", new_freq, new_freq + freq_offset); + fprintf (stderr, "Tuning to: %d [Hz] \n", new_freq); + } +/* + if(buffer[0] == 1) { + // change demod type + int type = chars_to_int(buffer); + + switch(type) { + case 0: + fprintf (stderr, "Changing demod type to FM\n"); + fm->mode_demod = &fm_demod; + break; + case 1: + fprintf (stderr, "Changing demod type to AM\n"); + fm->mode_demod = &am_demod; + break; + case 2: + fprintf (stderr, "Changing demod type to USB\n"); + fm->mode_demod = &usb_demod; + fm->custom_atan = 1; + break; + case 3: + fprintf (stderr, "Changing demod type to LSB\n"); + fm->mode_demod = &lsb_demod; + break; + default: + fprintf (stderr, "Unknown demod type %d\n", type); + break; + } + } +*/ + +//SQUELCH HERE + + if (buffer[0] == 2) { + new_squelch = chars_to_int(buffer); + demod.squelch_level = new_squelch; //demod, or d*? or d-> + //full_demod(d); + //new_freq = 850000000; + //dongle.freq = new_freq; + //optimal_settings(new_freq, demod.rate_in); //hacky way to 'squelch', just setting it to a dead freq instead + //rtlsdr_set_center_freq(dongle.dev, dongle.freq); + fprintf (stderr, "Changing squelch to %d \n", new_squelch); + } + +/* + if (buffer[0] == 3) { + new_gain = chars_to_int(buffer); + if (new_gain == AUTO_GAIN) { + r = rtlsdr_set_tuner_gain_mode(dev, 0); + } else { + r = rtlsdr_set_tuner_gain_mode(dev, 1); + new_gain = nearest_gain(new_gain); + r = rtlsdr_set_tuner_gain(dev, new_gain); + } + + if (r != 0) { + fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); + } else if (new_gain == AUTO_GAIN) { + fprintf(stderr, "Tuner gain set to automatic.\n"); + } else { + fprintf(stderr, "Tuner gain set to %0.2f dB.\n", new_gain/10.0); + } + } +*/ +/* + if (buffer[0] == 8) { + agc_mode = chars_to_int(buffer); + if (agc_mode == 0 || agc_mode == 1) { + fprintf(stderr, "Setting AGC to %d\n", agc_mode); + rtlsdr_set_agc_mode(dev, agc_mode); + } else { + fprintf(stderr, "Failed to set AGC to %d\n", agc_mode); + } + } +*/ + } + + close(sockfd); + return 0; +} +//UDP Control all above HERE void rtlsdr_sighandler() { fprintf(stderr, "Signal caught, exiting!\n"); + fprintf(stderr, "Press CTRL + C again to close. Thanks. \n"); //Kindly remind user to double tap CTRL + C rtlsdr_cancel_async(dongle.dev); + //cleanup_rtlsdr_stream(); //thank the wraith for this one...if it works...didn't work + //_Exit(1); } void open_rtlsdr_stream(dsd_opts *opts) @@ -901,10 +1051,18 @@ void open_rtlsdr_stream(dsd_opts *opts) controller.freq_len++; } - if (opts->rtlsdr_ppm_error > 0) { + if (opts->rtlsdr_ppm_error > 0 || opts->rtlsdr_ppm_error < 0) { //this way will adjust PPM based on negative values as well dongle.ppm_error = opts->rtlsdr_ppm_error; } + if (opts->audio_in_type == 3) { + dongle.dev_index = opts->rtl_dev_index; + } + + if (opts->rtl_gain_value > 0) { + dongle.gain = opts->rtl_gain_value * 10; //multiple by ten to make it consitent with the way rtl_fm really works + } + /* quadruple sample_rate to limit to Δθ to ±π/2 */ demod.rate_in *= demod.post_downsample; @@ -915,13 +1073,15 @@ void open_rtlsdr_stream(dsd_opts *opts) if (controller.freq_len > 1) demod.terminate_on_squelch = 0; ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH; - r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index); + if (r < 0) { fprintf(stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index); exit(1); - } + } else { + fprintf(stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index); //Kindly tell us which device we are using + } // sigact.sa_handler = sighandler; // sigemptyset(&sigact.sa_mask); @@ -952,6 +1112,7 @@ void open_rtlsdr_stream(dsd_opts *opts) usleep(100000); pthread_create(&demod.thread, NULL, demod_thread_fn, (void*)(&demod)); pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void*)(&dongle)); + pthread_create(&socket_freq, NULL, socket_thread_fn, (void *)(&controller)); } void cleanup_rtlsdr_stream() @@ -971,6 +1132,7 @@ void cleanup_rtlsdr_stream() controller_cleanup(&controller); rtlsdr_close(dongle.dev); + } void get_rtlsdr_sample(int16_t *sample) diff --git a/src/todolist b/src/todolist new file mode 100644 index 0000000..9a02ab9 --- /dev/null +++ b/src/todolist @@ -0,0 +1,9 @@ + opts->rtl_dev_index = 1; //actual device index since rtl:0 or rtl:1 doesn't do jack shit asshole! + opts->rtl_gain_value = 360; //set actual gain and not this automatic gain bullshit + + +while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1) + +G and D, well God Damn + +check on/work on offset tuning 'issue' From 97a17df9d1779540492ef92d50fd8f660c1771a7 Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Sat, 29 Jan 2022 21:58:03 -0500 Subject: [PATCH 08/14] Delete todolist Didn't mean to upload the todolist --- src/todolist | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 src/todolist diff --git a/src/todolist b/src/todolist deleted file mode 100644 index 9a02ab9..0000000 --- a/src/todolist +++ /dev/null @@ -1,9 +0,0 @@ - opts->rtl_dev_index = 1; //actual device index since rtl:0 or rtl:1 doesn't do jack shit asshole! - opts->rtl_gain_value = 360; //set actual gain and not this automatic gain bullshit - - -while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1) - -G and D, well God Damn - -check on/work on offset tuning 'issue' From 3c11d72652745cd3ea2a60438e3c1a5a0d61e641 Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Sat, 29 Jan 2022 21:59:55 -0500 Subject: [PATCH 09/14] Delete old ASCII art Delete old ASCII art and printer --- src/dsd_frame_sync.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index 796bf06..52999d3 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -18,15 +18,7 @@ #include "dsd.h" #include #include -char * FM_banner2[9] = { - " Digital Speech Decoder: Florida Man Edition - mbelib version 1.3.0 ", - " ███████╗██████╗ █████╗ █████╗ ██████╗ ███████╗███╗ ███╗ ██████╗ ", - " ██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝ ██╔════╝████╗ ████║ ██╔══██╗", - " █████╗ ██║ ██║███████║██║ ╚═╝╚█████╗ ███ █████╗ ██╔████╔██║█████████║", - " ██╔══╝ ██║ ██║██╔══██║██║ ██╗ ╚═══██╗ ██╔══╝ ██║╚██╔╝██║ ██║ ██║", - " ███████╗██████╔╝██║ ██║╚█████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║ ██████╔╝", - " ╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ", -}; + time_t now; char * getTime(void) //get pretty hh:mm:ss timestamp { @@ -879,13 +871,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { printf ("Sync: no sync\n"); printf("Press CTRL + C to close.\n"); //Kindly remind user to double tap CTRL + C - erase(); - attron(COLOR_PAIR(4)); - for (short int i = 0; i < 7; i++) { - printw("%s \n", FM_banner2[i]); } - attroff(COLOR_PAIR(4)); - printw("Sync: no sync\n"); - refresh(); } noCarrier (opts, state); return (-1); From fad831d1aa9002061f653f748d87e3ce85956ea9 Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Sat, 29 Jan 2022 22:03:42 -0500 Subject: [PATCH 10/14] Delete FindNCURSES.cmake Didn't mean to include this file --- cmake/FindNCURSES.cmake | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 cmake/FindNCURSES.cmake diff --git a/cmake/FindNCURSES.cmake b/cmake/FindNCURSES.cmake deleted file mode 100644 index 93b8210..0000000 --- a/cmake/FindNCURSES.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# - Try to find NCURSES -# Once done this will define -# -# ITPP_FOUND - System has ITPP -# ITPP_INCLUDE_DIR - The ITPP include directory -# ITPP_LIBRARY - The library needed to use ITPP -# - -find_path(ITPP_INCLUDE_DIR itpp/itcomm.h) - -set(NCURSES_NAMES ${NCURSES_NAMES} curses.h ncurses ncurses5w ncurses6w ncurses6 ncurses5 libncursesw) -FIND_LIBRARY(NCURSES_LIBRARY NAMES ${NCURSES_NAMES}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(NCURSES DEFAULT_MSG NCURSES_LIBRARY NCURSES_INCLUDE_DIR) From 60593dcce980b3927a92aaf723220b336324d3b2 Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Sat, 29 Jan 2022 22:05:15 -0500 Subject: [PATCH 11/14] Clean up some naughty language Clean up some naughty language --- src/dsd_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dsd_main.c b/src/dsd_main.c index c52b5a6..17af283 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -157,8 +157,8 @@ initOpts (dsd_opts * opts) opts->delay = 0; opts->use_cosine_filter = 1; opts->unmute_encrypted_p25 = 0; - opts->rtl_dev_index = 0; //actual device index since rtl:0 or rtl:1 doesn't do jack shit asshole! - opts->rtl_gain_value = 0; //set actual gain and not this automatic gain bullshit + opts->rtl_dev_index = 0; //choose which device we want by index number + opts->rtl_gain_value = 0; //set actual gain and not automatic gain } void From d0086a5f96e639aa9c4f87f6922ecfa8aff2f3fd Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Sat, 29 Jan 2022 22:11:28 -0500 Subject: [PATCH 12/14] Update README.md Add warnings to README file --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ea0d4e9..0f9e9f2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ [![Build Status](https://travis-ci.org/szechyjs/dsd.svg?branch=master)](https://travis-ci.org/szechyjs/dsd) -# Digital Speech Decoder 1.7.0-dev +# Digital Speech Decoder - Florida Man Edition +This version of DSD shouldn't be used by anybody wanting a stable DSD experience, please see the original version for that. +Also, please don't submit bug reports to the links on this page, those will direct them to the original version. Links will be updated at a later date. + +The purpose of this is to experiment with the RTL code and other things, and is purely for academic research into the inner workings of DSD. Basically, its for me to poke around with and see what I can manage to break. + DSD is able to decode [several digital voice formats](https://github.com/szechyjs/dsd/wiki/Supported-formats) from discriminator tap audio and synthesize the decoded speech. Speech synthesis requires mbelib, which is a separate package. From b67a3bb6dea3c73abba7522b795d59f7edabea93 Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Sat, 29 Jan 2022 22:17:19 -0500 Subject: [PATCH 13/14] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0f9e9f2..2b224d5 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Also, please don't submit bug reports to the links on this page, those will dire The purpose of this is to experiment with the RTL code and other things, and is purely for academic research into the inner workings of DSD. Basically, its for me to poke around with and see what I can manage to break. + +## DSD is able to decode [several digital voice formats](https://github.com/szechyjs/dsd/wiki/Supported-formats) from discriminator tap audio and synthesize the decoded speech. Speech synthesis requires mbelib, which is a separate package. From 6ed5e0bcab46d1da5a7d7147e4432eab12306890 Mon Sep 17 00:00:00 2001 From: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Sat, 29 Jan 2022 22:34:05 -0500 Subject: [PATCH 14/14] fix things so stupid checker will pass --- src/dsd_frame_sync.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index 52999d3..90ceb76 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -53,11 +53,11 @@ printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, { //char datestr[32]; //struct tm timep; - erase(); - attron(COLOR_PAIR(4)); - for (short int i = 0; i < 7; i++) { - printw("%s \n", FM_banner2[i]);} - attroff(COLOR_PAIR(4)); + //erase(); + //attron(COLOR_PAIR(4)); + //for (short int i = 0; i < 7; i++) { + //printw("%s \n", FM_banner2[i]);} + //attroff(COLOR_PAIR(4)); if (opts->verbose > 0) {