diff --git a/include/dsd.h b/include/dsd.h index 4a75702..3cf085e 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -317,6 +317,7 @@ typedef struct long int rtl_rms; int monitor_input_audio; int analog_only; + int ghosts_only; int pulse_raw_rate_in; int pulse_raw_rate_out; int pulse_digi_rate_in; @@ -1342,6 +1343,8 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency); long int GetCurrentFreq(int sockfd); bool SetFreq(int sockfd, long int freq); bool SetModulation(int sockfd, int bandwidth); +bool SetModulationWFM(int sockfd, int bandwidth); +void death (dsd_opts * opts, dsd_state * state); //commands below unique to GQRX only, not usable on SDR++ bool GetSignalLevel(int sockfd, double *dBFS); bool GetSquelchLevel(int sockfd, double *dBFS); diff --git a/src/3.c b/src/3.c index e104993..b9033bd 100644 --- a/src/3.c +++ b/src/3.c @@ -591,4 +591,176 @@ long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as rms = (long int)sqrt((p-err) / len); if (rms < 0) rms = 150; return rms; -} \ No newline at end of file +} + + +//Ghosts +void death (dsd_opts * opts, dsd_state * state) +{ + int i, x, result = 0; + short ghosts[960]; + short spooks[960]; + short demons[960]; + short sample = 0; + + memset (ghosts, 0, 960*sizeof(short)); + memset (spooks, 0, 960*sizeof(short)); + memset (demons, 0, 960*sizeof(short)); + + while (!exitflag) //while the software is running + { + //death on speaks at 48k/1 short output + if (opts->audio_in_type == 0) + { + for (i = 0; i < 960; i++) + { + pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL ); + ghosts[i] = sample; + } + + for (i = 0; i < 960; i++) + { + pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL ); + spooks[i] = sample; + } + + for (i = 0; i < 960; i++) + { + pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL ); + demons[i] = sample; + } + } + + if (opts->audio_in_type == 8) + { + for (i = 0; i < 960; i++) + { + result = sf_read_short(opts->tcp_file_in, &sample, 1); + if (result == 0) + { + sf_close(opts->tcp_file_in); + fprintf (stderr, "Connection to the Underworld Severed.\n"); + fprintf (stderr, "Closing Death Speech Decoder.\n"); + cleanupAndExit(opts, state); + } + ghosts[i] = sample; + } + + for (i = 0; i < 960; i++) + { + result = sf_read_short(opts->tcp_file_in, &sample, 1); + if (result == 0) + { + sf_close(opts->tcp_file_in); + fprintf (stderr, "Connection to the Underworld Severed.\n"); + fprintf (stderr, "Closing Death Speech Decoder.\n"); + cleanupAndExit(opts, state); + } + spooks[i] = sample; + } + + for (i = 0; i < 960; i++) + { + result = sf_read_short(opts->tcp_file_in, &sample, 1); + if (result == 0) + { + sf_close(opts->tcp_file_in); + fprintf (stderr, "Connection to the Underworld Severed.\n"); + fprintf (stderr, "Closing Death Speech Decoder.\n"); + cleanupAndExit(opts, state); + } + demons[i] = sample; + } + } + + //RTL Input + #ifdef USE_RTLSDR + if (opts->audio_in_type == 3) + { + for (i = 0; i < 960; i++) + { + get_rtlsdr_sample(&sample, opts, state); + ghosts[i] = sample; + } + + for (i = 0; i < 960; i++) + { + get_rtlsdr_sample(&sample, opts, state); + spooks[i] = sample; + } + + for (i = 0; i < 960; i++) + { + get_rtlsdr_sample(&sample, opts, state); + demons[i] = sample; + } + } + #endif + + //The Dead Don't Like OSS input yet + + //Listen to the Howls of the Deceased + if (opts->audio_out_type == 0 && opts->slot1_on == 1) + { + pa_simple_write(opts->pulse_raw_dev_out, ghosts, 960*2, NULL); + pa_simple_write(opts->pulse_raw_dev_out, spooks, 960*2, NULL); + pa_simple_write(opts->pulse_raw_dev_out, demons, 960*2, NULL); + } + + if (opts->audio_out_type == 8) //UDP Audio + { + udp_socket_blasterA (opts, state, 960*2, ghosts); + udp_socket_blasterA (opts, state, 960*2, spooks); + udp_socket_blasterA (opts, state, 960*2, demons); + } + + //added a condition check so that if OSS output and 8K, switches to 48K when opening OSS + if (opts->audio_out_type == 5 && opts->floating_point == 0 && opts->slot1_on == 1) + { + write (opts->audio_out_fd, ghosts, 960*2); + write (opts->audio_out_fd, spooks, 960*2); + write (opts->audio_out_fd, demons, 960*2); + } + + //STDOUT -- I don't see the harm of adding this here, will be fine for analog only or digital only (non-mixed analog and digital) + if (opts->audio_out_type == 1 && opts->floating_point == 0 && opts->slot1_on == 1) + { + write (opts->audio_out_fd, ghosts, 960*2); + write (opts->audio_out_fd, spooks, 960*2); + write (opts->audio_out_fd, demons, 960*2); + } + + //Undulate the Crystal Ball + if (x >= opts->trunk_hangtime) + { + long int spook_channel = state->trunk_lcn_freq[0]; + + //rigctl + if (opts->use_rigctl == 1) + { + if (opts->setmod_bw != 0 ) SetModulationWFM(opts->rigctl_sockfd, opts->setmod_bw); + SetFreq(opts->rigctl_sockfd, spook_channel); + } + + //rtl + if (opts->audio_in_type == 3) + { + #ifdef USE_RTLSDR + rtl_dev_tune(opts, spook_channel); + #endif + } + + // + state->trunk_lcn_freq[0] += 200000; + + if (state->trunk_lcn_freq[0] > 106100000) + state->trunk_lcn_freq[0] = 87900000; + + x = 0; + + } + + x++; + + } //end while loop +} //end ghosts \ No newline at end of file diff --git a/src/dsd_main.c b/src/dsd_main.c index ca878e9..f14995d 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -696,6 +696,7 @@ initOpts (dsd_opts * opts) opts->monitor_input_audio = 0; //enable with -8 opts->analog_only = 0; //only turned on with -fA + opts->ghosts_only = 0; //ghostbox mode with -fG opts->inverted_p2 = 0; opts->p2counter = 0; @@ -1358,6 +1359,7 @@ usage () printf ("Decoder options:\n"); printf (" -fa Auto Detection\n"); printf (" -fA Passive Analog Audio Monitor\n"); + printf (" -fG Ghosts, Demons, Specters, Ghouls, and Skeletons (Ghost Box)\n"); printf (" -ft TDMA Trunking P25p1 Control and Voice, P25p2 Trunked Channels, and DMR\n"); printf (" -fs DMR TDMA BS and MS Simplex\n"); printf (" -f1 Decode only P25 Phase 1\n"); @@ -2172,6 +2174,35 @@ main (int argc, char **argv) sprintf (opts.output_name, "Analog Monitor"); fprintf (stderr,"Only Monitoring Passive Analog Signal\n"); } + else if (optarg[0] == 'G') //listen to spooky scary skeletons + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_p25p2 = 0; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 0; + opts.frame_dpmr = 0; + opts.frame_provoice = 0; + opts.frame_ysf = 0; + opts.frame_m17 = 0; + opts.pulse_digi_rate_out = 8000; + opts.pulse_digi_out_channels = 1; + opts.dmr_stereo = 0; + state.dmr_stereo = 0; + opts.dmr_mono = 0; + state.rf_mod = 0; + opts.monitor_input_audio = 1; + opts.ghosts_only = 1; + state.trunk_lcn_freq[0] = 87900000; //everybody knows ghosts live on the Broadcast FM band + opts.setmod_bw = 150000; //Ghosts annunciate clearly with about 150,000 PB + opts.trunk_hangtime = 0; + opts.rtlsdr_center_freq = 850000000; + opts.rtl_bandwidth = 48; + sprintf (opts.output_name, "Ghost Box"); + fprintf (stderr,"Sounds of the Dead.\n"); + } else if (optarg[0] == 'd') { opts.frame_dstar = 1; @@ -3462,6 +3493,22 @@ main (int argc, char **argv) processM17IPF(&opts, &state); } + else if (opts.ghosts_only == 1) + { + #ifdef USE_RTLSDR + if(opts.audio_in_type == 3) + open_rtlsdr_stream(&opts); + #endif + + if (opts.audio_in_type == 0) + openPulseInput(&opts); + + if (opts.audio_out_type == 0) + openPulseOutput(&opts); + + death(&opts, &state); + } + else { diff --git a/src/dsd_rigctl.c b/src/dsd_rigctl.c index 820ac7e..f12bacc 100644 --- a/src/dsd_rigctl.c +++ b/src/dsd_rigctl.c @@ -163,6 +163,28 @@ bool SetModulation(int sockfd, int bandwidth) return true; } +bool SetModulationWFM(int sockfd, int bandwidth) +{ + char buf[BUFSIZE]; + //the bandwidth is now a user/system based configurable variable + sprintf (buf, "M WFM %d\n", bandwidth); //SDR++ has changed the token from FM to NFM, even if Ryzerth fixes it later, users may still have an older version + Send(sockfd, buf); + Recv(sockfd, buf); + + //if it fails the first time, send the other token instead + if (strcmp(buf, "RPRT 1\n") == 0 ) //sdr++ has a linebreak here, is that in all versions of the protocol? + { + sprintf (buf, "M WFM %d\n", bandwidth); //anything not SDR++ + Send(sockfd, buf); + Recv(sockfd, buf); + } + + if (strcmp(buf, "RPRT 1\n") == 0 ) + return false; + + return true; +} + bool GetSignalLevel(int sockfd, double *dBFS) { char buf[BUFSIZE]; diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index ad04667..dd6566c 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -1034,7 +1034,7 @@ void open_rtlsdr_stream(dsd_opts *opts) //init with low pass if decoding P25 or EDACS/Provoice if (opts->frame_p25p1 == 1 || opts->frame_p25p2 == 1 || opts->frame_provoice == 1) demod_init_ro2(&demod); - else if (opts->analog_only == 1 || opts->m17encoder == 1) + else if (opts->analog_only == 1 || opts->m17encoder == 1 || opts->ghosts_only == 1) demod_init_analog(&demod); else demod_init(&demod); output_init(&output);