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