1 /* -*- c++ -*- */
2 /*
3  * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
4  *           https://gqrx.dk/
5  *
6  * Copyright 2011-2016 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 <iostream>
25 #include <QDebug>
26 #include "receivers/nbrx.h"
27 
28 // NB: Remember to adjust filter ranges in MainWindow
29 #define PREF_QUAD_RATE  96000.f
30 
make_nbrx(float quad_rate,float audio_rate)31 nbrx_sptr make_nbrx(float quad_rate, float audio_rate)
32 {
33     return gnuradio::get_initial_sptr(new nbrx(quad_rate, audio_rate));
34 }
35 
nbrx(float quad_rate,float audio_rate)36 nbrx::nbrx(float quad_rate, float audio_rate)
37     : receiver_base_cf("NBRX"),
38       d_running(false),
39       d_quad_rate(quad_rate),
40       d_audio_rate(audio_rate),
41       d_demod(NBRX_DEMOD_FM)
42 {
43     iq_resamp = make_resampler_cc(PREF_QUAD_RATE/d_quad_rate);
44 
45     nb = make_rx_nb_cc(PREF_QUAD_RATE, 3.3, 2.5);
46     filter = make_rx_filter(PREF_QUAD_RATE, -5000.0, 5000.0, 1000.0);
47     agc = make_rx_agc_cc(PREF_QUAD_RATE, true, -100, 0, 0, 500, false);
48     sql = gr::analog::simple_squelch_cc::make(-150.0, 0.001);
49     meter = make_rx_meter_c(PREF_QUAD_RATE);
50     demod_raw = gr::blocks::complex_to_float::make(1);
51     demod_ssb = gr::blocks::complex_to_real::make(1);
52     demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, 5000.0, 75.0e-6);
53     demod_am = make_rx_demod_am(PREF_QUAD_RATE, true);
54     demod_amsync = make_rx_demod_amsync(PREF_QUAD_RATE, true, 0.001);
55 
56     audio_rr0.reset();
57     audio_rr1.reset();
58     if (d_audio_rate != PREF_QUAD_RATE)
59     {
60         std::cout << "Resampling audio " << PREF_QUAD_RATE << " -> "
61                   << d_audio_rate << std::endl;
62         audio_rr0 = make_resampler_ff(d_audio_rate/PREF_QUAD_RATE);
63         audio_rr1 = make_resampler_ff(d_audio_rate/PREF_QUAD_RATE);
64     }
65 
66     demod = demod_fm;
67     connect(self(), 0, iq_resamp, 0);
68     connect(iq_resamp, 0, nb, 0);
69     connect(nb, 0, filter, 0);
70     connect(filter, 0, meter, 0);
71     connect(filter, 0, sql, 0);
72     connect(sql, 0, agc, 0);
73     connect(agc, 0, demod, 0);
74 
75     if (audio_rr0)
76     {
77         connect(demod, 0, audio_rr0, 0);
78 
79         connect(audio_rr0, 0, self(), 0); // left  channel
80         connect(audio_rr0, 0, self(), 1); // right channel
81     }
82     else
83     {
84         connect(demod, 0, self(), 0);
85         connect(demod, 0, self(), 1);
86     }
87 }
88 
start()89 bool nbrx::start()
90 {
91     d_running = true;
92 
93     return true;
94 }
95 
stop()96 bool nbrx::stop()
97 {
98     d_running = false;
99 
100     return true;
101 }
102 
set_quad_rate(float quad_rate)103 void nbrx::set_quad_rate(float quad_rate)
104 {
105     if (std::abs(d_quad_rate-quad_rate) > 0.5)
106     {
107         qDebug() << "Changing NB_RX quad rate:"  << d_quad_rate << "->" << quad_rate;
108         d_quad_rate = quad_rate;
109         lock();
110         iq_resamp->set_rate(PREF_QUAD_RATE/d_quad_rate);
111         unlock();
112     }
113 }
114 
set_audio_rate(float audio_rate)115 void nbrx::set_audio_rate(float audio_rate)
116 {
117     (void) audio_rate;
118     std::cout << "**** FIXME: nbrx::set_audio_rate() not implemented" << std::endl;
119 }
120 
set_filter(double low,double high,double tw)121 void nbrx::set_filter(double low, double high, double tw)
122 {
123     filter->set_param(low, high, tw);
124 }
125 
set_cw_offset(double offset)126 void nbrx::set_cw_offset(double offset)
127 {
128     filter->set_cw_offset(offset);
129 }
130 
get_signal_level()131 float nbrx::get_signal_level()
132 {
133     return meter->get_level_db();
134 }
135 
set_nb_on(int nbid,bool on)136 void nbrx::set_nb_on(int nbid, bool on)
137 {
138     if (nbid == 1)
139         nb->set_nb1_on(on);
140     else if (nbid == 2)
141         nb->set_nb2_on(on);
142 }
143 
set_nb_threshold(int nbid,float threshold)144 void nbrx::set_nb_threshold(int nbid, float threshold)
145 {
146     if (nbid == 1)
147         nb->set_threshold1(threshold);
148     else if (nbid == 2)
149         nb->set_threshold2(threshold);
150 }
151 
set_sql_level(double level_db)152 void nbrx::set_sql_level(double level_db)
153 {
154     sql->set_threshold(level_db);
155 }
156 
set_sql_alpha(double alpha)157 void nbrx::set_sql_alpha(double alpha)
158 {
159     sql->set_alpha(alpha);
160 }
161 
set_agc_on(bool agc_on)162 void nbrx::set_agc_on(bool agc_on)
163 {
164     agc->set_agc_on(agc_on);
165 }
166 
set_agc_hang(bool use_hang)167 void nbrx::set_agc_hang(bool use_hang)
168 {
169     agc->set_use_hang(use_hang);
170 }
171 
set_agc_threshold(int threshold)172 void nbrx::set_agc_threshold(int threshold)
173 {
174     agc->set_threshold(threshold);
175 }
176 
set_agc_slope(int slope)177 void nbrx::set_agc_slope(int slope)
178 {
179     agc->set_slope(slope);
180 }
181 
set_agc_decay(int decay_ms)182 void nbrx::set_agc_decay(int decay_ms)
183 {
184     agc->set_decay(decay_ms);
185 }
186 
set_agc_manual_gain(int gain)187 void nbrx::set_agc_manual_gain(int gain)
188 {
189     agc->set_manual_gain(gain);
190 }
191 
set_demod(int rx_demod)192 void nbrx::set_demod(int rx_demod)
193 {
194     nbrx_demod current_demod = d_demod;
195 
196     /* check if new demodulator selection is valid */
197     if ((rx_demod < NBRX_DEMOD_NONE) || (rx_demod >= NBRX_DEMOD_NUM))
198         return;
199 
200     if (rx_demod == current_demod) {
201         /* nothing to do */
202         return;
203     }
204 
205     disconnect(agc, 0, demod, 0);
206     if (audio_rr0)
207     {
208         if (current_demod == NBRX_DEMOD_NONE)
209         {
210             disconnect(demod, 0, audio_rr0, 0);
211             disconnect(demod, 1, audio_rr1, 0);
212 
213             disconnect(audio_rr0, 0, self(), 0);
214             disconnect(audio_rr1, 0, self(), 1);
215         }
216         else
217         {
218             disconnect(demod, 0, audio_rr0, 0);
219 
220             disconnect(audio_rr0, 0, self(), 0);
221             disconnect(audio_rr0, 0, self(), 1);
222         }
223     }
224     else
225     {
226         if (current_demod == NBRX_DEMOD_NONE)
227         {
228             disconnect(demod, 0, self(), 0);
229             disconnect(demod, 1, self(), 1);
230         }
231         else
232         {
233             disconnect(demod, 0, self(), 0);
234             disconnect(demod, 0, self(), 1);
235         }
236     }
237 
238     switch (rx_demod) {
239 
240     case NBRX_DEMOD_NONE:
241         d_demod = NBRX_DEMOD_NONE;
242         demod = demod_raw;
243         break;
244 
245     case NBRX_DEMOD_SSB:
246         d_demod = NBRX_DEMOD_SSB;
247         demod = demod_ssb;
248         break;
249 
250     case NBRX_DEMOD_AM:
251         d_demod = NBRX_DEMOD_AM;
252         demod = demod_am;
253         break;
254 
255     case NBRX_DEMOD_AMSYNC:
256         d_demod = NBRX_DEMOD_AMSYNC;
257         demod = demod_amsync;
258         break;
259 
260     case NBRX_DEMOD_FM:
261     default:
262         d_demod = NBRX_DEMOD_FM;
263         demod = demod_fm;
264         break;
265     }
266 
267     connect(agc, 0, demod, 0);
268     if (audio_rr0)
269     {
270         if (d_demod == NBRX_DEMOD_NONE)
271         {
272             connect(demod, 0, audio_rr0, 0);
273             connect(demod, 1, audio_rr1, 0);
274 
275             connect(audio_rr0, 0, self(), 0);
276             connect(audio_rr1, 0, self(), 1);
277         }
278         else
279         {
280             connect(demod, 0, audio_rr0, 0);
281 
282             connect(audio_rr0, 0, self(), 0);
283             connect(audio_rr0, 0, self(), 1);
284         }
285     }
286     else
287     {
288         if (d_demod == NBRX_DEMOD_NONE)
289         {
290             connect(demod, 0, self(), 0);
291             connect(demod, 1, self(), 1);
292         }
293         else
294         {
295             connect(demod, 0, self(), 0);
296             connect(demod, 0, self(), 1);
297         }
298     }
299 }
300 
set_fm_maxdev(float maxdev_hz)301 void nbrx::set_fm_maxdev(float maxdev_hz)
302 {
303     demod_fm->set_max_dev(maxdev_hz);
304 }
305 
set_fm_deemph(double tau)306 void nbrx::set_fm_deemph(double tau)
307 {
308     demod_fm->set_tau(tau);
309 }
310 
set_am_dcr(bool enabled)311 void nbrx::set_am_dcr(bool enabled)
312 {
313     demod_am->set_dcr(enabled);
314 }
315 
set_amsync_dcr(bool enabled)316 void nbrx::set_amsync_dcr(bool enabled)
317 {
318     demod_amsync->set_dcr(enabled);
319 }
320 
set_amsync_pll_bw(float pll_bw)321 void nbrx::set_amsync_pll_bw(float pll_bw)
322 {
323     demod_amsync->set_pll_bw(pll_bw);
324 }
325