1 /* -*- c++ -*- */
2 /*
3  * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
4  *           https://gqrx.dk/
5  *
6  * Copyright 2011-2014 Alexandru Csete OZ9AEC.
7  *
8  * Gqrx is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3, or (at your option)
11  * any later version.
12  *
13  * Gqrx is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Gqrx; see the file COPYING.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street,
21  * Boston, MA 02110-1301, USA.
22  */
23 #include <cmath>
24 #include <iomanip>
25 #include <iostream>
26 #include <sstream>
27 #include <QDebug>
28 
29 #include <gnuradio/prefs.h>
30 #include <gnuradio/top_block.h>
31 #include <osmosdr/source.h>
32 #include <osmosdr/ranges.h>
33 
34 #include "applications/gqrx/receiver.h"
35 #include "dsp/correct_iq_cc.h"
36 #include "dsp/filter/fir_decim.h"
37 #include "dsp/rx_fft.h"
38 #include "receivers/nbrx.h"
39 #include "receivers/wfmrx.h"
40 
41 #ifdef WITH_PULSEAUDIO
42 #include "pulseaudio/pa_sink.h"
43 #elif WITH_PORTAUDIO
44 #include "portaudio/portaudio_sink.h"
45 #else
46 #include <gnuradio/audio/sink.h>
47 #endif
48 
49 #define DEFAULT_AUDIO_GAIN -6.0
50 #define TARGET_QUAD_RATE 1e6
51 
52 /**
53  * @brief Public constructor.
54  * @param input_device Input device specifier.
55  * @param audio_device Audio output device specifier,
56  *                     e.g. hw:0 when using ALSA or Portaudio.
57  */
receiver(const std::string input_device,const std::string audio_device,unsigned int decimation)58 receiver::receiver(const std::string input_device,
59                    const std::string audio_device,
60                    unsigned int decimation)
61     : d_running(false),
62       d_input_rate(96000.0),
63       d_audio_rate(48000),
64       d_decim(decimation),
65       d_rf_freq(144800000.0),
66       d_filter_offset(0.0),
67       d_cw_offset(0.0),
68       d_recording_iq(false),
69       d_recording_wav(false),
70       d_sniffer_active(false),
71       d_iq_rev(false),
72       d_dc_cancel(false),
73       d_iq_balance(false),
74       d_demod(RX_DEMOD_OFF)
75 {
76 
77     tb = gr::make_top_block("gqrx");
78 
79     if (input_device.empty())
80     {
81         src = osmosdr::source::make("file="+escape_filename(get_zero_file())+",freq=428e6,rate=96000,repeat=true,throttle=true");
82     }
83     else
84     {
85         input_devstr = input_device;
86         src = osmosdr::source::make(input_device);
87     }
88 
89     // input decimator
90     if (d_decim >= 2)
91     {
92         try
93         {
94             input_decim = make_fir_decim_cc(d_decim);
95         }
96         catch (std::range_error &e)
97         {
98             std::cout << "Error creating input decimator " << d_decim
99                       << ": " << e.what() << std::endl
100                       << "Using decimation 1." << std::endl;
101             d_decim = 1;
102         }
103 
104         d_decim_rate = d_input_rate / (double)d_decim;
105     }
106     else
107     {
108         d_decim_rate = d_input_rate;
109     }
110 
111     d_ddc_decim = std::max(1, (int)(d_decim_rate / TARGET_QUAD_RATE));
112     d_quad_rate = d_decim_rate / d_ddc_decim;
113     ddc = make_downconverter_cc(d_ddc_decim, 0.0, d_decim_rate);
114     rx  = make_nbrx(d_quad_rate, d_audio_rate);
115 
116     iq_swap = make_iq_swap_cc(false);
117     dc_corr = make_dc_corr_cc(d_decim_rate, 1.0);
118     iq_fft = make_rx_fft_c(8192u, d_decim_rate, gr::fft::window::WIN_HANN);
119 
120     audio_fft = make_rx_fft_f(8192u, d_audio_rate, gr::fft::window::WIN_HANN);
121     audio_gain0 = gr::blocks::multiply_const_ff::make(0);
122     audio_gain1 = gr::blocks::multiply_const_ff::make(0);
123     set_af_gain(DEFAULT_AUDIO_GAIN);
124 
125     audio_udp_sink = make_udp_sink_f();
126 
127 #ifdef WITH_PULSEAUDIO
128     audio_snk = make_pa_sink(audio_device, d_audio_rate, "GQRX", "Audio output");
129 #elif WITH_PORTAUDIO
130     audio_snk = make_portaudio_sink(audio_device, d_audio_rate, "GQRX", "Audio output");
131 #else
132     audio_snk = gr::audio::sink::make(d_audio_rate, audio_device, true);
133 #endif
134 
135     output_devstr = audio_device;
136 
137     /* wav sink and source is created when rec/play is started */
138     audio_null_sink0 = gr::blocks::null_sink::make(sizeof(float));
139     audio_null_sink1 = gr::blocks::null_sink::make(sizeof(float));
140     sniffer = make_sniffer_f();
141     /* sniffer_rr is created at each activation. */
142 
143     set_demod(RX_DEMOD_NFM);
144 
145     gr::prefs pref;
146     qDebug() << "Using audio backend:"
147              << pref.get_string("audio", "audio_module", "N/A").c_str();
148 }
149 
~receiver()150 receiver::~receiver()
151 {
152     tb->stop();
153 }
154 
155 
156 /** Start the receiver. */
start()157 void receiver::start()
158 {
159     if (!d_running)
160     {
161         tb->start();
162         d_running = true;
163     }
164 }
165 
166 /** Stop the receiver. */
stop()167 void receiver::stop()
168 {
169     if (d_running)
170     {
171         tb->stop();
172         tb->wait(); // If the graph is needed to run again, wait() must be called after stop
173         d_running = false;
174     }
175 }
176 
177 /**
178  * @brief Select new input device.
179  * @param device
180  */
set_input_device(const std::string device)181 void receiver::set_input_device(const std::string device)
182 {
183     qDebug() << "Set input device:";
184     qDebug() << "  old:" << input_devstr.c_str();
185     qDebug() << "  new:" << device.c_str();
186 
187     std::string error = "";
188 
189     if (device.empty())
190         return;
191 
192     input_devstr = device;
193 
194     // tb->lock() can hang occasionally
195     if (d_running)
196     {
197         tb->stop();
198         tb->wait();
199     }
200 
201     if (d_decim >= 2)
202     {
203         tb->disconnect(src, 0, input_decim, 0);
204         tb->disconnect(input_decim, 0, iq_swap, 0);
205     }
206     else
207     {
208         tb->disconnect(src, 0, iq_swap, 0);
209     }
210 
211     src.reset();
212 
213     try
214     {
215         src = osmosdr::source::make(device);
216     }
217     catch (std::exception &x)
218     {
219         error = x.what();
220         src = osmosdr::source::make("file="+escape_filename(get_zero_file())+",freq=428e6,rate=96000,repeat=true,throttle=true");
221     }
222 
223     if(src->get_sample_rate() != 0)
224         set_input_rate(src->get_sample_rate());
225 
226     if (d_decim >= 2)
227     {
228         tb->connect(src, 0, input_decim, 0);
229         tb->connect(input_decim, 0, iq_swap, 0);
230     }
231     else
232     {
233         tb->connect(src, 0, iq_swap, 0);
234     }
235 
236     if (d_running)
237         tb->start();
238 
239     if (error != "")
240     {
241         throw std::runtime_error(error);
242     }
243 }
244 
245 
246 /**
247  * @brief Select new audio output device.
248  * @param device
249  */
set_output_device(const std::string device)250 void receiver::set_output_device(const std::string device)
251 {
252     qDebug() << "Set output device:";
253     qDebug() << "   old:" << output_devstr.c_str();
254     qDebug() << "   new:" << device.c_str();
255 
256     output_devstr = device;
257 
258     tb->lock();
259 
260     if (d_demod != RX_DEMOD_OFF)
261     {
262         tb->disconnect(audio_gain0, 0, audio_snk, 0);
263         tb->disconnect(audio_gain1, 0, audio_snk, 1);
264     }
265     audio_snk.reset();
266 
267     try {
268 #ifdef WITH_PULSEAUDIO
269         audio_snk = make_pa_sink(device, d_audio_rate, "GQRX", "Audio output");
270 #elif WITH_PORTAUDIO
271         audio_snk = make_portaudio_sink(device, d_audio_rate, "GQRX", "Audio output");
272 #else
273         audio_snk = gr::audio::sink::make(d_audio_rate, device, true);
274 #endif
275 
276         if (d_demod != RX_DEMOD_OFF)
277         {
278             tb->connect(audio_gain0, 0, audio_snk, 0);
279             tb->connect(audio_gain1, 0, audio_snk, 1);
280         }
281 
282         tb->unlock();
283 
284     } catch (std::exception &x) {
285         tb->unlock();
286         // handle problems on non-freeing devices
287         throw x;
288     }
289 }
290 
291 /** Get a list of available antenna connectors. */
get_antennas(void) const292 std::vector<std::string> receiver::get_antennas(void) const
293 {
294     return src->get_antennas();
295 }
296 
297 /** Select antenna connector. */
set_antenna(const std::string & antenna)298 void receiver::set_antenna(const std::string &antenna)
299 {
300     if (!antenna.empty())
301     {
302         src->set_antenna(antenna);
303     }
304 }
305 
306 /**
307  * @brief Set new input sample rate.
308  * @param rate The desired input rate
309  * @return The actual sample rate set or 0 if there was an error with the
310  *         device.
311  */
set_input_rate(double rate)312 double receiver::set_input_rate(double rate)
313 {
314     double  current_rate;
315     bool    rate_has_changed;
316 
317     current_rate = src->get_sample_rate();
318     rate_has_changed = !(rate == current_rate ||
319             std::abs(rate - current_rate) < std::abs(std::min(rate, current_rate))
320             * std::numeric_limits<double>::epsilon());
321 
322     tb->lock();
323     try
324     {
325         d_input_rate = src->set_sample_rate(rate);
326     }
327     catch (std::runtime_error &e)
328     {
329         d_input_rate = 0;
330     }
331 
332     if (d_input_rate == 0)
333     {
334         // This can be the case when no device is attached and gr-osmosdr
335         // puts in a null_source with rate 100 ksps or if the rate has not
336         // changed
337         if (rate_has_changed)
338         {
339             std::cerr << std::endl;
340             std::cerr << "Failed to set RX input rate to " << rate << std::endl;
341             std::cerr << "Your device may not be working properly." << std::endl;
342             std::cerr << std::endl;
343         }
344         d_input_rate = rate;
345     }
346 
347     d_decim_rate = d_input_rate / (double)d_decim;
348     d_ddc_decim = std::max(1, (int)(d_decim_rate / TARGET_QUAD_RATE));
349     d_quad_rate = d_decim_rate / d_ddc_decim;
350     dc_corr->set_sample_rate(d_decim_rate);
351     ddc->set_decim_and_samp_rate(d_ddc_decim, d_decim_rate);
352     rx->set_quad_rate(d_quad_rate);
353     iq_fft->set_quad_rate(d_decim_rate);
354     tb->unlock();
355 
356     return d_input_rate;
357 }
358 
359 /** Set input decimation */
set_input_decim(unsigned int decim)360 unsigned int receiver::set_input_decim(unsigned int decim)
361 {
362     if (decim == d_decim)
363         return d_decim;
364 
365     if (d_running)
366     {
367         tb->stop();
368         tb->wait();
369     }
370 
371     if (d_decim >= 2)
372     {
373         tb->disconnect(src, 0, input_decim, 0);
374         tb->disconnect(input_decim, 0, iq_swap, 0);
375     }
376     else
377     {
378         tb->disconnect(src, 0, iq_swap, 0);
379     }
380 
381     input_decim.reset();
382     d_decim = decim;
383     if (d_decim >= 2)
384     {
385         try
386         {
387             input_decim = make_fir_decim_cc(d_decim);
388         }
389         catch (std::range_error &e)
390         {
391             std::cout << "Error opening creating input decimator " << d_decim
392                       << ": " << e.what() << std::endl
393                       << "Using decimation 1." << std::endl;
394             d_decim = 1;
395         }
396 
397         d_decim_rate = d_input_rate / (double)d_decim;
398     }
399     else
400     {
401         d_decim_rate = d_input_rate;
402     }
403 
404     // update quadrature rate
405     d_ddc_decim = std::max(1, (int)(d_decim_rate / TARGET_QUAD_RATE));
406     d_quad_rate = d_decim_rate / d_ddc_decim;
407     dc_corr->set_sample_rate(d_decim_rate);
408     ddc->set_decim_and_samp_rate(d_ddc_decim, d_decim_rate);
409     rx->set_quad_rate(d_quad_rate);
410     iq_fft->set_quad_rate(d_decim_rate);
411 
412     if (d_decim >= 2)
413     {
414         tb->connect(src, 0, input_decim, 0);
415         tb->connect(input_decim, 0, iq_swap, 0);
416     }
417     else
418     {
419         tb->connect(src, 0, iq_swap, 0);
420     }
421 
422 #ifdef CUSTOM_AIRSPY_KERNELS
423     if (input_devstr.find("airspy") != std::string::npos)
424         src->set_bandwidth(d_decim_rate);
425 #endif
426 
427     if (d_running)
428         tb->start();
429 
430     return d_decim;
431 }
432 
433 /**
434  * @brief Set new analog bandwidth.
435  * @param bw The new bandwidth.
436  * @return The actual bandwidth.
437  */
set_analog_bandwidth(double bw)438 double receiver::set_analog_bandwidth(double bw)
439 {
440     return src->set_bandwidth(bw);
441 }
442 
443 /** Get current analog bandwidth. */
get_analog_bandwidth(void) const444 double receiver::get_analog_bandwidth(void) const
445 {
446     return src->get_bandwidth();
447 }
448 
449 /** Set I/Q reversed. */
set_iq_swap(bool reversed)450 void receiver::set_iq_swap(bool reversed)
451 {
452     if (reversed == d_iq_rev)
453         return;
454 
455     d_iq_rev = reversed;
456     iq_swap->set_enabled(d_iq_rev);
457 }
458 
459 /**
460  * @brief Get current I/Q reversed setting.
461  * @retval true I/Q swappign is enabled.
462  * @retval false I/Q swapping is disabled.
463  */
get_iq_swap(void) const464 bool receiver::get_iq_swap(void) const
465 {
466     return d_iq_rev;
467 }
468 
469 /**
470  * @brief Enable/disable automatic DC removal in the I/Q stream.
471  * @param enable Whether DC removal should enabled or not.
472  */
set_dc_cancel(bool enable)473 void receiver::set_dc_cancel(bool enable)
474 {
475     if (enable == d_dc_cancel)
476         return;
477 
478     d_dc_cancel = enable;
479 
480     // until we have a way to switch on/off
481     // inside the dc_corr_cc we do a reconf
482     set_demod(d_demod, true);
483 }
484 
485 /**
486  * @brief Get auto DC cancel status.
487  * @retval true  Automatic DC removal is enabled.
488  * @retval false Automatic DC removal is disabled.
489  */
get_dc_cancel(void) const490 bool receiver::get_dc_cancel(void) const
491 {
492     return d_dc_cancel;
493 }
494 
495 /**
496  * @brief Enable/disable automatic I/Q balance.
497  * @param enable Whether automatic I/Q balance should be enabled.
498  */
set_iq_balance(bool enable)499 void receiver::set_iq_balance(bool enable)
500 {
501     if (enable == d_iq_balance)
502         return;
503 
504     d_iq_balance = enable;
505 
506     src->set_iq_balance_mode(enable ? 2 : 0);
507 }
508 
509 /**
510  * @brief Get auto I/Q balance status.
511  * @retval true  Automatic I/Q balance is enabled.
512  * @retval false Automatic I/Q balance is disabled.
513  */
get_iq_balance(void) const514 bool receiver::get_iq_balance(void) const
515 {
516     return d_iq_balance;
517 }
518 
519 /**
520  * @brief Set RF frequency.
521  * @param freq_hz The desired frequency in Hz.
522  * @return RX_STATUS_ERROR if an error occurs, e.g. the frequency is out of range.
523  * @sa get_rf_freq()
524  */
set_rf_freq(double freq_hz)525 receiver::status receiver::set_rf_freq(double freq_hz)
526 {
527     d_rf_freq = freq_hz;
528 
529     src->set_center_freq(d_rf_freq);
530     // FIXME: read back frequency?
531 
532     return STATUS_OK;
533 }
534 
535 /**
536  * @brief Get RF frequency.
537  * @return The current RF frequency.
538  * @sa set_rf_freq()
539  */
get_rf_freq(void)540 double receiver::get_rf_freq(void)
541 {
542     d_rf_freq = src->get_center_freq();
543 
544     return d_rf_freq;
545 }
546 
547 /**
548  * @brief Get the RF frequency range of the current input device.
549  * @param start The lower limit of the range in Hz.
550  * @param stop  The upper limit of the range in Hz.
551  * @param step  The frequency step in Hz.
552  * @returns STATUS_OK if the range could be retrieved, STATUS_ERROR if an error has occurred.
553  */
get_rf_range(double * start,double * stop,double * step)554 receiver::status receiver::get_rf_range(double *start, double *stop, double *step)
555 {
556     osmosdr::freq_range_t range;
557 
558     range = src->get_freq_range();
559 
560     // currently range is empty for all but E4000
561     if (!range.empty())
562     {
563         if (range.start() < range.stop())
564         {
565             *start = range.start();
566             *stop  = range.stop();
567             *step  = range.step();  /** FIXME: got 0 for rtl-sdr? **/
568 
569             return STATUS_OK;
570         }
571     }
572 
573     return STATUS_ERROR;
574 }
575 
576 /** Get the names of available gain stages. */
get_gain_names()577 std::vector<std::string> receiver::get_gain_names()
578 {
579     return src->get_gain_names();
580 }
581 
582 /**
583  * @brief Get gain range for a specific stage.
584  * @param[in]  name The name of the gain stage.
585  * @param[out] start Lower limit for this gain setting.
586  * @param[out] stop  Upper limit for this gain setting.
587  * @param[out] step  The resolution for this gain setting.
588  *
589  * This function returns the range for the requested gain stage.
590  */
get_gain_range(std::string & name,double * start,double * stop,double * step) const591 receiver::status receiver::get_gain_range(std::string &name, double *start,
592                                           double *stop, double *step) const
593 {
594     osmosdr::gain_range_t range;
595 
596     range = src->get_gain_range(name);
597     *start = range.start();
598     *stop  = range.stop();
599     *step  = range.step();
600 
601     return STATUS_OK;
602 }
603 
set_gain(std::string name,double value)604 receiver::status receiver::set_gain(std::string name, double value)
605 {
606     src->set_gain(value, name);
607 
608     return STATUS_OK;
609 }
610 
get_gain(std::string name) const611 double receiver::get_gain(std::string name) const
612 {
613     return src->get_gain(name);
614 }
615 
616 /**
617  * @brief Set RF gain.
618  * @param gain_rel The desired relative gain between 0.0 and 1.0 (use -1 for
619  *                 AGC where supported).
620  * @return RX_STATUS_ERROR if an error occurs, e.g. the gain is out of valid range.
621  */
set_auto_gain(bool automatic)622 receiver::status receiver::set_auto_gain(bool automatic)
623 {
624     src->set_gain_mode(automatic);
625 
626     return STATUS_OK;
627 }
628 
629 /**
630  * @brief Set filter offset.
631  * @param offset_hz The desired filter offset in Hz.
632  * @return RX_STATUS_ERROR if the tuning offset is out of range.
633  *
634  * This method sets a new tuning offset for the receiver. The tuning offset is used
635  * to tune within the passband, i.e. select a specific channel within the received
636  * spectrum.
637  *
638  * The valid range for the tuning is +/- 0.5 * the bandwidth although this is just a
639  * logical limit.
640  *
641  * @sa get_filter_offset()
642  */
set_filter_offset(double offset_hz)643 receiver::status receiver::set_filter_offset(double offset_hz)
644 {
645     d_filter_offset = offset_hz;
646     ddc->set_center_freq(d_filter_offset - d_cw_offset);
647 
648     return STATUS_OK;
649 }
650 
651 /**
652  * @brief Get filter offset.
653  * @return The current filter offset.
654  * @sa set_filter_offset()
655  */
get_filter_offset(void) const656 double receiver::get_filter_offset(void) const
657 {
658     return d_filter_offset;
659 }
660 
661 /* CW offset can serve as a "BFO" if the GUI needs it */
set_cw_offset(double offset_hz)662 receiver::status receiver::set_cw_offset(double offset_hz)
663 {
664     d_cw_offset = offset_hz;
665     ddc->set_center_freq(d_filter_offset - d_cw_offset);
666     rx->set_cw_offset(d_cw_offset);
667 
668     return STATUS_OK;
669 }
670 
get_cw_offset(void) const671 double receiver::get_cw_offset(void) const
672 {
673     return d_cw_offset;
674 }
675 
set_filter(double low,double high,filter_shape shape)676 receiver::status receiver::set_filter(double low, double high, filter_shape shape)
677 {
678     double trans_width;
679 
680     if ((low >= high) || (std::abs(high-low) < RX_FILTER_MIN_WIDTH))
681         return STATUS_ERROR;
682 
683     switch (shape) {
684 
685     case FILTER_SHAPE_SOFT:
686         trans_width = std::abs(high - low) * 0.5;
687         break;
688 
689     case FILTER_SHAPE_SHARP:
690         trans_width = std::abs(high - low) * 0.1;
691         break;
692 
693     case FILTER_SHAPE_NORMAL:
694     default:
695         trans_width = std::abs(high - low) * 0.2;
696         break;
697 
698     }
699 
700     rx->set_filter(low, high, trans_width);
701 
702     return STATUS_OK;
703 }
704 
set_freq_corr(double ppm)705 receiver::status receiver::set_freq_corr(double ppm)
706 {
707     src->set_freq_corr(ppm);
708 
709     return STATUS_OK;
710 }
711 
712 /**
713  * @brief Get current signal power.
714  * @param dbfs Whether to use dbfs or absolute power.
715  * @return The current signal power.
716  *
717  * This method returns the current signal power detected by the receiver. The detector
718  * is located after the band pass filter. The full scale is 1.0
719  */
get_signal_pwr() const720 float receiver::get_signal_pwr() const
721 {
722     return rx->get_signal_level();
723 }
724 
725 /** Set new FFT size. */
set_iq_fft_size(int newsize)726 void receiver::set_iq_fft_size(int newsize)
727 {
728     iq_fft->set_fft_size(newsize);
729 }
730 
set_iq_fft_window(int window_type)731 void receiver::set_iq_fft_window(int window_type)
732 {
733     iq_fft->set_window_type(window_type);
734 }
735 
736 /** Get latest baseband FFT data. */
get_iq_fft_data(std::complex<float> * fftPoints,unsigned int & fftsize)737 void receiver::get_iq_fft_data(std::complex<float>* fftPoints, unsigned int &fftsize)
738 {
739     iq_fft->get_fft_data(fftPoints, fftsize);
740 }
741 
742 /** Get latest audio FFT data. */
get_audio_fft_data(std::complex<float> * fftPoints,unsigned int & fftsize)743 void receiver::get_audio_fft_data(std::complex<float>* fftPoints, unsigned int &fftsize)
744 {
745     audio_fft->get_fft_data(fftPoints, fftsize);
746 }
747 
set_nb_on(int nbid,bool on)748 receiver::status receiver::set_nb_on(int nbid, bool on)
749 {
750     if (rx->has_nb())
751         rx->set_nb_on(nbid, on);
752 
753     return STATUS_OK; // FIXME
754 }
755 
set_nb_threshold(int nbid,float threshold)756 receiver::status receiver::set_nb_threshold(int nbid, float threshold)
757 {
758     if (rx->has_nb())
759         rx->set_nb_threshold(nbid, threshold);
760 
761     return STATUS_OK; // FIXME
762 }
763 
764 /**
765  * @brief Set squelch level.
766  * @param level_db The new level in dBFS.
767  */
set_sql_level(double level_db)768 receiver::status receiver::set_sql_level(double level_db)
769 {
770     if (rx->has_sql())
771         rx->set_sql_level(level_db);
772 
773     return STATUS_OK; // FIXME
774 }
775 
776 /** Set squelch alpha */
set_sql_alpha(double alpha)777 receiver::status receiver::set_sql_alpha(double alpha)
778 {
779     if (rx->has_sql())
780         rx->set_sql_alpha(alpha);
781 
782     return STATUS_OK; // FIXME
783 }
784 
785 /**
786  * @brief Enable/disable receiver AGC.
787  *
788  * When AGC is disabled a fixed manual gain is used, see set_agc_manual_gain().
789  */
set_agc_on(bool agc_on)790 receiver::status receiver::set_agc_on(bool agc_on)
791 {
792     if (rx->has_agc())
793         rx->set_agc_on(agc_on);
794 
795     return STATUS_OK; // FIXME
796 }
797 
798 /** Enable/disable AGC hang. */
set_agc_hang(bool use_hang)799 receiver::status receiver::set_agc_hang(bool use_hang)
800 {
801     if (rx->has_agc())
802         rx->set_agc_hang(use_hang);
803 
804     return STATUS_OK; // FIXME
805 }
806 
807 /** Set AGC threshold. */
set_agc_threshold(int threshold)808 receiver::status receiver::set_agc_threshold(int threshold)
809 {
810     if (rx->has_agc())
811         rx->set_agc_threshold(threshold);
812 
813     return STATUS_OK; // FIXME
814 }
815 
816 /** Set AGC slope. */
set_agc_slope(int slope)817 receiver::status receiver::set_agc_slope(int slope)
818 {
819     if (rx->has_agc())
820         rx->set_agc_slope(slope);
821 
822     return STATUS_OK; // FIXME
823 }
824 
825 /** Set AGC decay time. */
set_agc_decay(int decay_ms)826 receiver::status receiver::set_agc_decay(int decay_ms)
827 {
828     if (rx->has_agc())
829         rx->set_agc_decay(decay_ms);
830 
831     return STATUS_OK; // FIXME
832 }
833 
834 /** Set fixed gain used when AGC is OFF. */
set_agc_manual_gain(int gain)835 receiver::status receiver::set_agc_manual_gain(int gain)
836 {
837     if (rx->has_agc())
838         rx->set_agc_manual_gain(gain);
839 
840     return STATUS_OK; // FIXME
841 }
842 
set_demod(rx_demod demod,bool force)843 receiver::status receiver::set_demod(rx_demod demod, bool force)
844 {
845     status ret = STATUS_OK;
846 
847     if (!force && (demod == d_demod))
848         return ret;
849 
850     // tb->lock() seems to hang occasioanlly
851     if (d_running)
852     {
853         tb->stop();
854         tb->wait();
855     }
856 
857     tb->disconnect_all();
858 
859     switch (demod)
860     {
861     case RX_DEMOD_OFF:
862         connect_all(RX_CHAIN_NONE);
863         break;
864 
865     case RX_DEMOD_NONE:
866         connect_all(RX_CHAIN_NBRX);
867         rx->set_demod(nbrx::NBRX_DEMOD_NONE);
868         break;
869 
870     case RX_DEMOD_AM:
871         connect_all(RX_CHAIN_NBRX);
872         rx->set_demod(nbrx::NBRX_DEMOD_AM);
873         break;
874 
875     case RX_DEMOD_AMSYNC:
876         connect_all(RX_CHAIN_NBRX);
877         rx->set_demod(nbrx::NBRX_DEMOD_AMSYNC);
878         break;
879 
880     case RX_DEMOD_NFM:
881         connect_all(RX_CHAIN_NBRX);
882         rx->set_demod(nbrx::NBRX_DEMOD_FM);
883         break;
884 
885     case RX_DEMOD_WFM_M:
886         connect_all(RX_CHAIN_WFMRX);
887         rx->set_demod(wfmrx::WFMRX_DEMOD_MONO);
888         break;
889 
890     case RX_DEMOD_WFM_S:
891         connect_all(RX_CHAIN_WFMRX);
892         rx->set_demod(wfmrx::WFMRX_DEMOD_STEREO);
893         break;
894 
895     case RX_DEMOD_WFM_S_OIRT:
896         connect_all(RX_CHAIN_WFMRX);
897         rx->set_demod(wfmrx::WFMRX_DEMOD_STEREO_UKW);
898         break;
899 
900     case RX_DEMOD_SSB:
901         connect_all(RX_CHAIN_NBRX);
902         rx->set_demod(nbrx::NBRX_DEMOD_SSB);
903         break;
904 
905     default:
906         ret = STATUS_ERROR;
907         break;
908     }
909 
910     d_demod = demod;
911 
912     if (d_running)
913         tb->start();
914 
915     return ret;
916 }
917 
918 /**
919  * @brief Set maximum deviation of the FM demodulator.
920  * @param maxdev_hz The new maximum deviation in Hz.
921  */
set_fm_maxdev(float maxdev_hz)922 receiver::status receiver::set_fm_maxdev(float maxdev_hz)
923 {
924     if (rx->has_fm())
925         rx->set_fm_maxdev(maxdev_hz);
926 
927     return STATUS_OK;
928 }
929 
set_fm_deemph(double tau)930 receiver::status receiver::set_fm_deemph(double tau)
931 {
932     if (rx->has_fm())
933         rx->set_fm_deemph(tau);
934 
935     return STATUS_OK;
936 }
937 
set_am_dcr(bool enabled)938 receiver::status receiver::set_am_dcr(bool enabled)
939 {
940     if (rx->has_am())
941         rx->set_am_dcr(enabled);
942 
943     return STATUS_OK;
944 }
945 
set_amsync_dcr(bool enabled)946 receiver::status receiver::set_amsync_dcr(bool enabled)
947 {
948     if (rx->has_amsync())
949         rx->set_amsync_dcr(enabled);
950 
951     return STATUS_OK;
952 }
953 
set_amsync_pll_bw(float pll_bw)954 receiver::status receiver::set_amsync_pll_bw(float pll_bw)
955 {
956     if (rx->has_amsync())
957         rx->set_amsync_pll_bw(pll_bw);
958 
959     return STATUS_OK;
960 }
961 
set_af_gain(float gain_db)962 receiver::status receiver::set_af_gain(float gain_db)
963 {
964     float k;
965 
966     /* convert dB to factor */
967     k = pow(10.0, gain_db / 20.0);
968     //std::cout << "G:" << gain_db << "dB / K:" << k << std::endl;
969     audio_gain0->set_k(k);
970     audio_gain1->set_k(k);
971 
972     return STATUS_OK;
973 }
974 
975 
976 /**
977  * @brief Start WAV file recorder.
978  * @param filename The filename where to record.
979  *
980  * A new recorder object is created every time we start recording and deleted every time
981  * we stop recording. The idea of creating one object and starting/stopping using different
982  * file names does not work with WAV files (the initial /tmp/gqrx.wav will not be stopped
983  * because the wav file can not be empty). See https://github.com/gqrx-sdr/gqrx/issues/36
984  */
start_audio_recording(const std::string filename)985 receiver::status receiver::start_audio_recording(const std::string filename)
986 {
987     if (d_recording_wav)
988     {
989         /* error - we are already recording */
990         std::cout << "ERROR: Can not start audio recorder (already recording)" << std::endl;
991 
992         return STATUS_ERROR;
993     }
994     if (!d_running)
995     {
996         /* receiver is not running */
997         std::cout << "Can not start audio recorder (receiver not running)" << std::endl;
998 
999         return STATUS_ERROR;
1000     }
1001 
1002     // if this fails, we don't want to go and crash now, do we
1003     try {
1004 #if GNURADIO_VERSION < 0x030900
1005         wav_sink = gr::blocks::wavfile_sink::make(filename.c_str(), 2,
1006                                                   (unsigned int) d_audio_rate,
1007                                                   16);
1008 #else
1009         wav_sink = gr::blocks::wavfile_sink::make(filename.c_str(), 2,
1010                                                   (unsigned int) d_audio_rate,
1011                                                   gr::blocks::FORMAT_WAV, gr::blocks::FORMAT_PCM_16);
1012 #endif
1013     }
1014     catch (std::runtime_error &e) {
1015         std::cout << "Error opening " << filename << ": " << e.what() << std::endl;
1016         return STATUS_ERROR;
1017     }
1018 
1019     tb->lock();
1020     tb->connect(rx, 0, wav_sink, 0);
1021     tb->connect(rx, 1, wav_sink, 1);
1022     tb->unlock();
1023     d_recording_wav = true;
1024 
1025     std::cout << "Recording audio to " << filename << std::endl;
1026 
1027     return STATUS_OK;
1028 }
1029 
1030 /** Stop WAV file recorder. */
stop_audio_recording()1031 receiver::status receiver::stop_audio_recording()
1032 {
1033     if (!d_recording_wav) {
1034         /* error: we are not recording */
1035         std::cout << "ERROR: Can not stop audio recorder (not recording)" << std::endl;
1036 
1037         return STATUS_ERROR;
1038     }
1039     if (!d_running)
1040     {
1041         /* receiver is not running */
1042         std::cout << "Can not stop audio recorder (receiver not running)" << std::endl;
1043 
1044         return STATUS_ERROR;
1045     }
1046 
1047     // not strictly necessary to lock but I think it is safer
1048     tb->lock();
1049     wav_sink->close();
1050     tb->disconnect(rx, 0, wav_sink, 0);
1051     tb->disconnect(rx, 1, wav_sink, 1);
1052     tb->unlock();
1053     wav_sink.reset();
1054     d_recording_wav = false;
1055 
1056     std::cout << "Audio recorder stopped" << std::endl;
1057 
1058     return STATUS_OK;
1059 }
1060 
1061 /** Start audio playback. */
start_audio_playback(const std::string filename)1062 receiver::status receiver::start_audio_playback(const std::string filename)
1063 {
1064     if (!d_running)
1065     {
1066         /* receiver is not running */
1067         std::cout << "Can not start audio playback (receiver not running)" << std::endl;
1068 
1069         return STATUS_ERROR;
1070     }
1071 
1072     try {
1073         // output ports set automatically from file
1074         wav_src = gr::blocks::wavfile_source::make(filename.c_str(), false);
1075     }
1076     catch (std::runtime_error &e) {
1077         std::cout << "Error loading " << filename << ": " << e.what() << std::endl;
1078         return STATUS_ERROR;
1079     }
1080 
1081     /** FIXME: We can only handle native rate (should maybe use the audio_rr)? */
1082     unsigned int audio_rate = (unsigned int) d_audio_rate;
1083     if (wav_src->sample_rate() != audio_rate)
1084     {
1085         std::cout << "BUG: Can not handle sample rate " << wav_src->sample_rate() << std::endl;
1086         wav_src.reset();
1087 
1088         return STATUS_ERROR;
1089     }
1090 
1091     /** FIXME: We can only handle stereo files */
1092     if (wav_src->channels() != 2)
1093     {
1094         std::cout << "BUG: Can not handle other than 2 channels. File has " << wav_src->channels() << std::endl;
1095         wav_src.reset();
1096 
1097         return STATUS_ERROR;
1098     }
1099 
1100     stop();
1101     /* route demodulator output to null sink */
1102     tb->disconnect(rx, 0, audio_gain0, 0);
1103     tb->disconnect(rx, 1, audio_gain1, 0);
1104     tb->disconnect(rx, 0, audio_fft, 0);
1105     tb->disconnect(rx, 0, audio_udp_sink, 0);
1106     tb->disconnect(rx, 1, audio_udp_sink, 1);
1107     tb->connect(rx, 0, audio_null_sink0, 0); /** FIXME: other channel? */
1108     tb->connect(rx, 1, audio_null_sink1, 0); /** FIXME: other channel? */
1109     tb->connect(wav_src, 0, audio_gain0, 0);
1110     tb->connect(wav_src, 1, audio_gain1, 0);
1111     tb->connect(wav_src, 0, audio_fft, 0);
1112     tb->connect(wav_src, 0, audio_udp_sink, 0);
1113     tb->connect(wav_src, 1, audio_udp_sink, 1);
1114     start();
1115 
1116     std::cout << "Playing audio from " << filename << std::endl;
1117 
1118     return STATUS_OK;
1119 }
1120 
1121 /** Stop audio playback. */
stop_audio_playback()1122 receiver::status receiver::stop_audio_playback()
1123 {
1124     /* disconnect wav source and reconnect receiver */
1125     stop();
1126     tb->disconnect(wav_src, 0, audio_gain0, 0);
1127     tb->disconnect(wav_src, 1, audio_gain1, 0);
1128     tb->disconnect(wav_src, 0, audio_fft, 0);
1129     tb->disconnect(wav_src, 0, audio_udp_sink, 0);
1130     tb->disconnect(wav_src, 1, audio_udp_sink, 1);
1131     tb->disconnect(rx, 0, audio_null_sink0, 0);
1132     tb->disconnect(rx, 1, audio_null_sink1, 0);
1133     tb->connect(rx, 0, audio_gain0, 0);
1134     tb->connect(rx, 1, audio_gain1, 0);
1135     tb->connect(rx, 0, audio_fft, 0);  /** FIXME: other channel? */
1136     tb->connect(rx, 0, audio_udp_sink, 0);
1137     tb->connect(rx, 1, audio_udp_sink, 1);
1138     start();
1139 
1140     /* delete wav_src since we can not change file name */
1141     wav_src.reset();
1142 
1143     return STATUS_OK;
1144 }
1145 
1146 /** Start UDP streaming of audio. */
start_udp_streaming(const std::string host,int port,bool stereo)1147 receiver::status receiver::start_udp_streaming(const std::string host, int port, bool stereo)
1148 {
1149     audio_udp_sink->start_streaming(host, port, stereo);
1150     return STATUS_OK;
1151 }
1152 
1153 /** Stop UDP streaming of audio. */
stop_udp_streaming()1154 receiver::status receiver::stop_udp_streaming()
1155 {
1156     audio_udp_sink->stop_streaming();
1157     return STATUS_OK;
1158 }
1159 
1160 /**
1161  * @brief Start I/Q data recorder.
1162  * @param filename The filename where to record.
1163  */
start_iq_recording(const std::string filename)1164 receiver::status receiver::start_iq_recording(const std::string filename)
1165 {
1166     receiver::status status = STATUS_OK;
1167 
1168     if (d_recording_iq) {
1169         std::cout << __func__ << ": already recording" << std::endl;
1170         return STATUS_ERROR;
1171     }
1172 
1173     try
1174     {
1175         iq_sink = gr::blocks::file_sink::make(sizeof(gr_complex), filename.c_str(), true);
1176     }
1177     catch (std::runtime_error &e)
1178     {
1179         std::cout << __func__ << ": couldn't open I/Q file" << std::endl;
1180         return STATUS_ERROR;
1181     }
1182 
1183     tb->lock();
1184     if (d_decim >= 2)
1185         tb->connect(input_decim, 0, iq_sink, 0);
1186     else
1187         tb->connect(src, 0, iq_sink, 0);
1188     d_recording_iq = true;
1189     tb->unlock();
1190 
1191     return status;
1192 }
1193 
1194 /** Stop I/Q data recorder. */
stop_iq_recording()1195 receiver::status receiver::stop_iq_recording()
1196 {
1197     if (!d_recording_iq) {
1198         /* error: we are not recording */
1199         return STATUS_ERROR;
1200     }
1201 
1202     tb->lock();
1203     iq_sink->close();
1204 
1205     if (d_decim >= 2)
1206         tb->disconnect(input_decim, 0, iq_sink, 0);
1207     else
1208         tb->disconnect(src, 0, iq_sink, 0);
1209 
1210     tb->unlock();
1211     iq_sink.reset();
1212     d_recording_iq = false;
1213 
1214     return STATUS_OK;
1215 }
1216 
1217 /**
1218  * @brief Seek to position in IQ file source.
1219  * @param pos Byte offset from the beginning of the file.
1220  */
seek_iq_file(long pos)1221 receiver::status receiver::seek_iq_file(long pos)
1222 {
1223     receiver::status status = STATUS_OK;
1224 
1225     tb->lock();
1226 
1227     if (src->seek(pos, SEEK_SET))
1228     {
1229         status = STATUS_OK;
1230     }
1231     else
1232     {
1233         status = STATUS_ERROR;
1234     }
1235 
1236     tb->unlock();
1237 
1238     return status;
1239 }
1240 
1241 /**
1242  * @brief Start data sniffer.
1243  * @param buffsize The buffer that should be used in the sniffer.
1244  * @return STATUS_OK if the sniffer was started, STATUS_ERROR if the sniffer is already in use.
1245  */
start_sniffer(unsigned int samprate,int buffsize)1246 receiver::status receiver::start_sniffer(unsigned int samprate, int buffsize)
1247 {
1248     if (d_sniffer_active) {
1249         /* sniffer already in use */
1250         return STATUS_ERROR;
1251     }
1252 
1253     sniffer->set_buffer_size(buffsize);
1254     sniffer_rr = make_resampler_ff((float)samprate/(float)d_audio_rate);
1255     tb->lock();
1256     tb->connect(rx, 0, sniffer_rr, 0);
1257     tb->connect(sniffer_rr, 0, sniffer, 0);
1258     tb->unlock();
1259     d_sniffer_active = true;
1260 
1261     return STATUS_OK;
1262 }
1263 
1264 /**
1265  * @brief Stop data sniffer.
1266  * @return STATUS_ERROR i the sniffer is not currently active.
1267  */
stop_sniffer()1268 receiver::status receiver::stop_sniffer()
1269 {
1270     if (!d_sniffer_active) {
1271         return STATUS_ERROR;
1272     }
1273 
1274     tb->lock();
1275     tb->disconnect(rx, 0, sniffer_rr, 0);
1276     tb->disconnect(sniffer_rr, 0, sniffer, 0);
1277     tb->unlock();
1278     d_sniffer_active = false;
1279 
1280     /* delete resampler */
1281     sniffer_rr.reset();
1282 
1283     return STATUS_OK;
1284 }
1285 
1286 /** Get sniffer data. */
get_sniffer_data(float * outbuff,unsigned int & num)1287 void receiver::get_sniffer_data(float * outbuff, unsigned int &num)
1288 {
1289     sniffer->get_samples(outbuff, num);
1290 }
1291 
1292 /** Convenience function to connect all blocks. */
connect_all(rx_chain type)1293 void receiver::connect_all(rx_chain type)
1294 {
1295     gr::basic_block_sptr b;
1296 
1297     // Setup source
1298     b = src;
1299 
1300     // Pre-processing
1301     if (d_decim >= 2)
1302     {
1303         tb->connect(b, 0, input_decim, 0);
1304         b = input_decim;
1305     }
1306 
1307     if (d_recording_iq)
1308     {
1309         // We record IQ with minimal pre-processing
1310         tb->connect(b, 0, iq_sink, 0);
1311     }
1312 
1313     tb->connect(b, 0, iq_swap, 0);
1314     b = iq_swap;
1315 
1316     if (d_dc_cancel)
1317     {
1318         tb->connect(b, 0, dc_corr, 0);
1319         b = dc_corr;
1320     }
1321 
1322     // Visualization
1323     tb->connect(b, 0, iq_fft, 0);
1324 
1325     // RX demod chain
1326     switch (type)
1327     {
1328     case RX_CHAIN_NBRX:
1329         if (rx->name() != "NBRX")
1330         {
1331             rx.reset();
1332             rx = make_nbrx(d_quad_rate, d_audio_rate);
1333         }
1334         break;
1335 
1336     case RX_CHAIN_WFMRX:
1337         if (rx->name() != "WFMRX")
1338         {
1339             rx.reset();
1340             rx = make_wfmrx(d_quad_rate, d_audio_rate);
1341         }
1342         break;
1343 
1344     default:
1345         break;
1346     }
1347 
1348     // Audio path (if there is a receiver)
1349     if (type != RX_CHAIN_NONE)
1350     {
1351         tb->connect(b, 0, ddc, 0);
1352         tb->connect(ddc, 0, rx, 0);
1353         tb->connect(rx, 0, audio_fft, 0);
1354         tb->connect(rx, 0, audio_udp_sink, 0);
1355         tb->connect(rx, 1, audio_udp_sink, 1);
1356         tb->connect(rx, 0, audio_gain0, 0);
1357         tb->connect(rx, 1, audio_gain1, 0);
1358         tb->connect(audio_gain0, 0, audio_snk, 0);
1359         tb->connect(audio_gain1, 0, audio_snk, 1);
1360     }
1361 
1362     // Recorders and sniffers
1363     if (d_recording_wav)
1364     {
1365         tb->connect(rx, 0, wav_sink, 0);
1366         tb->connect(rx, 1, wav_sink, 1);
1367     }
1368 
1369     if (d_sniffer_active)
1370     {
1371         tb->connect(rx, 0, sniffer_rr, 0);
1372         tb->connect(sniffer_rr, 0, sniffer, 0);
1373     }
1374 }
1375 
get_rds_data(std::string & outbuff,int & num)1376 void receiver::get_rds_data(std::string &outbuff, int &num)
1377 {
1378     rx->get_rds_data(outbuff, num);
1379 }
1380 
start_rds_decoder(void)1381 void receiver::start_rds_decoder(void)
1382 {
1383     if (d_running)
1384     {
1385         stop();
1386         rx->start_rds_decoder();
1387         start();
1388     }
1389     else
1390     {
1391         rx->start_rds_decoder();
1392     }
1393 }
1394 
stop_rds_decoder(void)1395 void receiver::stop_rds_decoder(void)
1396 {
1397     if (d_running)
1398     {
1399         stop();
1400         rx->stop_rds_decoder();
1401         start();
1402     }
1403     else
1404     {
1405         rx->stop_rds_decoder();
1406     }
1407 }
1408 
is_rds_decoder_active(void) const1409 bool receiver::is_rds_decoder_active(void) const
1410 {
1411     return rx->is_rds_decoder_active();
1412 }
1413 
reset_rds_parser(void)1414 void receiver::reset_rds_parser(void)
1415 {
1416     rx->reset_rds_parser();
1417 }
1418 
escape_filename(std::string filename)1419 std::string receiver::escape_filename(std::string filename)
1420 {
1421     std::stringstream ss1;
1422     std::stringstream ss2;
1423 
1424     ss1 << std::quoted(filename, '\'', '\\');
1425     ss2 << std::quoted(ss1.str(), '\'', '\\');
1426     return ss2.str();
1427 }
1428