1 /* -*- c++ -*- */
2 /*
3 * Copyright 2015 SDRplay Ltd <support@sdrplay.com>
4 * Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net>
5 * Copyright 2012 Steve Markgraf <steve@steve-m.de>
6 *
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 /*
24 * config.h is generated by configure. It contains the results
25 * of probing for features, options etc. It should be the first
26 * file included in your .cc file.
27 */
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "sdrplay_source_c.h"
33 #include <gnuradio/io_signature.h>
34 #include "osmosdr/source.h"
35
36 #include <boost/assign.hpp>
37 #include <boost/format.hpp>
38
39 #include <stdexcept>
40 #include <iostream>
41 #include <stdio.h>
42 #include <math.h>
43
44 #include <mirsdrapi-rsp.h>
45
46 #include "arg_helpers.h"
47
48 #define MAX_SUPPORTED_DEVICES 4
49
50 struct sdrplay_dev
51 {
52 int gRdB;
53 double gain_dB;
54 double fsHz;
55 double rfHz;
56 mir_sdr_Bw_MHzT bwType;
57 mir_sdr_If_kHzT ifType;
58 int samplesPerPacket;
59 int maxGain;
60 int minGain;
61 int dcMode;
62 };
63
64 using namespace boost::assign;
65
66 #define BYTES_PER_SAMPLE 4 // sdrplay device delivers 16 bit signed IQ data
67 // containing 12 bits of information
68
69 #define SDRPLAY_AM_MIN 150e3
70 #define SDRPLAY_AM_MAX 30e6
71 #define SDRPLAY_FM_MIN 64e6
72 #define SDRPLAY_FM_MAX 108e6
73 #define SDRPLAY_B3_MIN 162e6
74 #define SDRPLAY_B3_MAX 240e6
75 #define SDRPLAY_B45_MIN 470e6
76 #define SDRPLAY_B45_MAX 960e6
77 #define SDRPLAY_L_MIN 1450e6
78 #define SDRPLAY_L_MAX 1675e6
79
80 #define SDRPLAY_MAX_BUF_SIZE 504
81
82 /*
83 * Create a new instance of sdrplay_source_c and return
84 * a boost shared_ptr. This is effectively the public constructor.
85 */
86 sdrplay_source_c_sptr
make_sdrplay_source_c(const std::string & args)87 make_sdrplay_source_c (const std::string &args)
88 {
89 return gnuradio::get_initial_sptr(new sdrplay_source_c (args));
90 }
91
92 /*
93 * Specify constraints on number of input and output streams.
94 * This info is used to construct the input and output signatures
95 * (2nd & 3rd args to gr::block's constructor). The input and
96 * output signatures are used by the runtime system to
97 * check that a valid number and type of inputs and outputs
98 * are connected to this block. In this case, we accept
99 * only 0 input and 1 output.
100 */
101 static const int MIN_IN = 0; // mininum number of input streams
102 static const int MAX_IN = 0; // maximum number of input streams
103 static const int MIN_OUT = 1; // minimum number of output streams
104 static const int MAX_OUT = 1; // maximum number of output streams
105
106 /*
107 * The private constructor
108 */
sdrplay_source_c(const std::string & args)109 sdrplay_source_c::sdrplay_source_c (const std::string &args)
110 : gr::sync_block ("sdrplay_source_c",
111 gr::io_signature::make(MIN_IN, MAX_IN, sizeof (gr_complex)),
112 gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (gr_complex))),
113 _running(false),
114 _uninit(false),
115 _auto_gain(false)
116 {
117 _dev = (sdrplay_dev_t *)malloc(sizeof(sdrplay_dev_t));
118 if (_dev == NULL)
119 {
120 return;
121 }
122 _dev->fsHz = 2048e3;
123 _dev->rfHz = 200e6;
124 _dev->bwType = mir_sdr_BW_1_536;
125 _dev->ifType = mir_sdr_IF_Zero;
126 _dev->samplesPerPacket = 0;
127 _dev->dcMode = 0;
128 _dev->gRdB = 60;
129 set_gain_limits(_dev->rfHz);
130 _dev->gain_dB = _dev->maxGain - _dev->gRdB;
131
132 _bufi.reserve(SDRPLAY_MAX_BUF_SIZE);
133 _bufq.reserve(SDRPLAY_MAX_BUF_SIZE);
134
135 _buf_mutex.lock();
136 _buf_offset = 0;
137 _buf_mutex.unlock();
138 }
139
140 /*
141 * Our virtual destructor.
142 */
~sdrplay_source_c()143 sdrplay_source_c::~sdrplay_source_c ()
144 {
145 free(_dev);
146 _dev = NULL;
147 _buf_mutex.lock();
148 if (_running)
149 {
150 _running = false;
151 }
152 _uninit = true;
153 _buf_mutex.unlock();
154 }
155
reinit_device()156 void sdrplay_source_c::reinit_device()
157 {
158 std::cerr << "reinit_device started" << std::endl;
159 _buf_mutex.lock();
160 std::cerr << "after mutex.lock" << std::endl;
161 if (_running)
162 {
163 std::cerr << "mir_sdr_Uninit started" << std::endl;
164 mir_sdr_Uninit();
165 }
166
167 std::cerr << "mir_sdr_Init started" << std::endl;
168 mir_sdr_Init(_dev->gRdB, _dev->fsHz / 1e6, _dev->rfHz / 1e6, _dev->bwType, _dev->ifType, &_dev->samplesPerPacket);
169
170 if (_dev->dcMode)
171 {
172 std::cerr << "mir_sdr_SetDcMode started" << std::endl;
173 mir_sdr_SetDcMode(4, 1);
174 }
175
176 _buf_offset = 0;
177 _buf_mutex.unlock();
178 std::cerr << "reinit_device end" << std::endl;
179 }
180
set_gain_limits(double freq)181 void sdrplay_source_c::set_gain_limits(double freq)
182 {
183 if (freq <= SDRPLAY_AM_MAX)
184 {
185 _dev->minGain = -4;
186 _dev->maxGain = 98;
187 }
188 else if (freq <= SDRPLAY_FM_MAX)
189 {
190 _dev->minGain = 1;
191 _dev->maxGain = 103;
192 }
193 else if (freq <= SDRPLAY_B3_MAX)
194 {
195 _dev->minGain = 5;
196 _dev->maxGain = 107;
197 }
198 else if (freq <= SDRPLAY_B45_MAX)
199 {
200 _dev->minGain = 9;
201 _dev->maxGain = 94;
202 }
203 else if (freq <= SDRPLAY_L_MAX)
204 {
205 _dev->minGain = 24;
206 _dev->maxGain = 105;
207 }
208 }
209
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)210 int sdrplay_source_c::work( int noutput_items,
211 gr_vector_const_void_star &input_items,
212 gr_vector_void_star &output_items )
213 {
214 gr_complex *out = (gr_complex *)output_items[0];
215 int cnt = noutput_items;
216 unsigned int sampNum;
217 int grChanged;
218 int rfChanged;
219 int fsChanged;
220
221 if (_uninit)
222 {
223 return WORK_DONE;
224 }
225
226 if (!_running)
227 {
228 reinit_device();
229 _running = true;
230 }
231
232 _buf_mutex.lock();
233
234 if (_buf_offset)
235 {
236 for (int i = _buf_offset; i < _dev->samplesPerPacket; i++)
237 {
238 *out++ = gr_complex( float(_bufi[i]) * (1.0f/2048.0f), float(_bufq[i]) * (1.0f/2048.0f) );
239 }
240 cnt -= (_dev->samplesPerPacket - _buf_offset);
241 }
242
243 while ((cnt - _dev->samplesPerPacket) >= 0)
244 {
245 mir_sdr_ReadPacket(_bufi.data(), _bufq.data(), &sampNum, &grChanged, &rfChanged, &fsChanged);
246 for (int i = 0; i < _dev->samplesPerPacket; i++)
247 {
248 *out++ = gr_complex( float(_bufi[i]) * (1.0f/2048.0f), float(_bufq[i]) * (1.0f/2048.0f) );
249 }
250 cnt -= _dev->samplesPerPacket;
251 }
252
253 _buf_offset = 0;
254 if (cnt)
255 {
256 mir_sdr_ReadPacket(_bufi.data(), _bufq.data(), &sampNum, &grChanged, &rfChanged, &fsChanged);
257 for (int i = 0; i < cnt; i++)
258 {
259 *out++ = gr_complex( float(_bufi[i]) * (1.0f/2048.0f), float(_bufq[i]) * (1.0f/2048.0f) );
260 }
261 _buf_offset = cnt;
262 }
263 _buf_mutex.unlock();
264
265 return noutput_items;
266 }
267
get_devices()268 std::vector<std::string> sdrplay_source_c::get_devices()
269 {
270 std::vector<std::string> devices;
271 std::cerr << "get_devices started" << std::endl;
272
273 unsigned int dev_cnt = 0;
274 int samplesPerPacket;
275 while(mir_sdr_Init(60, 2.048, 200.0, mir_sdr_BW_1_536, mir_sdr_IF_Zero, &samplesPerPacket) == mir_sdr_Success)
276 {
277 dev_cnt++;
278 }
279
280 std::cerr << "Device count: " << dev_cnt << std::endl;
281
282 for (unsigned int i = 0; i < dev_cnt; i++)
283 {
284 mir_sdr_Uninit();
285 std::string args = "sdrplay=" + boost::lexical_cast< std::string >( i );
286 args += ",label='" + std::string("SDRplay RSP") + "'";
287 std::cerr << args << std::endl;
288 devices.push_back( args );
289 }
290
291 std::cerr << "get_devices end" << std::endl;
292 return devices;
293 }
294
get_num_channels()295 size_t sdrplay_source_c::get_num_channels()
296 {
297 std::cerr << "get_num_channels: 1" << std::endl;
298 return 1;
299 }
300
get_sample_rates()301 osmosdr::meta_range_t sdrplay_source_c::get_sample_rates()
302 {
303 osmosdr::meta_range_t range;
304
305 range += osmosdr::range_t( 2000e3, 12000e3 );
306
307 return range;
308 }
309
set_sample_rate(double rate)310 double sdrplay_source_c::set_sample_rate(double rate)
311 {
312 std::cerr << "set_sample_rate start" << std::endl;
313 double diff = rate - _dev->fsHz;
314 _dev->fsHz = rate;
315
316 std::cerr << "rate = " << rate << std::endl;
317 std::cerr << "diff = " << diff << std::endl;
318 if (_running)
319 {
320 if (fabs(diff) < 10000.0)
321 {
322 std::cerr << "mir_sdr_SetFs started" << std::endl;
323 mir_sdr_SetFs(diff, 0, 0, 0);
324 }
325 else
326 {
327 std::cerr << "reinit_device started" << std::endl;
328 reinit_device();
329 }
330 }
331 std::cerr << "set_sample_rate end" << std::endl;
332
333 return get_sample_rate();
334 }
335
get_sample_rate()336 double sdrplay_source_c::get_sample_rate()
337 {
338 if (_running)
339 {
340 return _dev->fsHz;
341 }
342
343 // return 0;
344 return _dev->fsHz;
345 }
346
get_freq_range(size_t chan)347 osmosdr::freq_range_t sdrplay_source_c::get_freq_range( size_t chan )
348 {
349 osmosdr::freq_range_t range;
350
351 range += osmosdr::range_t( SDRPLAY_AM_MIN, SDRPLAY_AM_MAX ); /* LW/MW/SW (150 kHz - 30 MHz) */
352 range += osmosdr::range_t( SDRPLAY_FM_MIN, SDRPLAY_FM_MAX ); /* VHF Band II (64 - 108 MHz) */
353 range += osmosdr::range_t( SDRPLAY_B3_MIN, SDRPLAY_B3_MAX ); /* Band III (162 - 240 MHz) */
354 range += osmosdr::range_t( SDRPLAY_B45_MIN, SDRPLAY_B45_MAX ); /* Band IV/V (470 - 960 MHz) */
355 range += osmosdr::range_t( SDRPLAY_L_MIN, SDRPLAY_L_MAX ); /* L-Band (1450 - 1675 MHz) */
356
357 return range;
358 }
359
set_center_freq(double freq,size_t chan)360 double sdrplay_source_c::set_center_freq( double freq, size_t chan )
361 {
362 std::cerr << "set_center_freq start" << std::endl;
363 std::cerr << "freq = " << freq << std::endl;
364 double diff = freq - _dev->rfHz;
365 std::cerr << "diff = " << diff << std::endl;
366 _dev->rfHz = freq;
367 set_gain_limits(freq);
368 if (_running)
369 {
370 if (fabs(diff) < 10000.0)
371 {
372 std::cerr << "mir_sdr_SetRf started" << std::endl;
373 mir_sdr_SetRf(diff, 0, 0);
374 }
375 else
376 {
377 std::cerr << "reinit_device started" << std::endl;
378 reinit_device();
379 }
380 }
381
382 std::cerr << "set_center_freq end" << std::endl;
383 return get_center_freq( chan );
384 }
385
get_center_freq(size_t chan)386 double sdrplay_source_c::get_center_freq( size_t chan )
387 {
388 if (_running)
389 {
390 return _dev->rfHz;
391 }
392
393 // return 0;
394 return _dev->rfHz;
395 }
396
set_freq_corr(double ppm,size_t chan)397 double sdrplay_source_c::set_freq_corr( double ppm, size_t chan )
398 {
399 return get_freq_corr( chan );
400 }
401
get_freq_corr(size_t chan)402 double sdrplay_source_c::get_freq_corr( size_t chan )
403 {
404 return 0;
405 }
406
get_gain_names(size_t chan)407 std::vector<std::string> sdrplay_source_c::get_gain_names( size_t chan )
408 {
409 std::vector< std::string > gains;
410
411 gains += "LNA_MIX_BB";
412
413 return gains;
414 }
415
get_gain_range(size_t chan)416 osmosdr::gain_range_t sdrplay_source_c::get_gain_range( size_t chan )
417 {
418 osmosdr::gain_range_t range;
419
420 for (int i = _dev->minGain; i < _dev->maxGain; i++)
421 {
422 range += osmosdr::range_t( (float)i );
423 }
424
425 return range;
426 }
427
get_gain_range(const std::string & name,size_t chan)428 osmosdr::gain_range_t sdrplay_source_c::get_gain_range( const std::string & name, size_t chan )
429 {
430 return get_gain_range( chan );
431 }
432
set_gain_mode(bool automatic,size_t chan)433 bool sdrplay_source_c::set_gain_mode( bool automatic, size_t chan )
434 {
435 std::cerr << "set_gain_mode started" << std::endl;
436 _auto_gain = automatic;
437 std::cerr << "automatic = " << automatic << std::endl;
438 if (automatic)
439 {
440 /* Start AGC */
441 std::cerr << "AGC not yet implemented" << std::endl;
442 }
443
444 std::cerr << "set_gain_mode end" << std::endl;
445 return get_gain_mode(chan);
446 }
447
get_gain_mode(size_t chan)448 bool sdrplay_source_c::get_gain_mode( size_t chan )
449 {
450 return _auto_gain;
451 }
452
set_gain(double gain,size_t chan)453 double sdrplay_source_c::set_gain( double gain, size_t chan )
454 {
455 std::cerr << "set_gain started" << std::endl;
456 _dev->gain_dB = gain;
457 std::cerr << "gain = " << gain << std::endl;
458 if (gain < _dev->minGain)
459 {
460 _dev->gain_dB = _dev->minGain;
461 }
462 if (gain > _dev->maxGain)
463 {
464 _dev->gain_dB = _dev->maxGain;
465 }
466 _dev->gRdB = (int)(_dev->maxGain - gain);
467
468 if (_running)
469 {
470 std::cerr << "mir_sdr_SetGr started" << std::endl;
471 mir_sdr_SetGr(_dev->gRdB, 1, 0);
472 }
473
474 std::cerr << "set_gain end" << std::endl;
475 return get_gain( chan );
476 }
477
set_gain(double gain,const std::string & name,size_t chan)478 double sdrplay_source_c::set_gain( double gain, const std::string & name, size_t chan)
479 {
480 return set_gain( gain, chan );
481 }
482
get_gain(size_t chan)483 double sdrplay_source_c::get_gain( size_t chan )
484 {
485 if ( _running )
486 {
487 return _dev->gain_dB;
488 }
489
490 // return 0;
491 return _dev->gain_dB;
492 }
493
get_gain(const std::string & name,size_t chan)494 double sdrplay_source_c::get_gain( const std::string & name, size_t chan )
495 {
496 return get_gain( chan );
497 }
498
get_antennas(size_t chan)499 std::vector< std::string > sdrplay_source_c::get_antennas( size_t chan )
500 {
501 std::vector< std::string > antennas;
502
503 antennas += get_antenna( chan );
504
505 return antennas;
506 }
507
set_antenna(const std::string & antenna,size_t chan)508 std::string sdrplay_source_c::set_antenna( const std::string & antenna, size_t chan )
509 {
510 return get_antenna( chan );
511 }
512
get_antenna(size_t chan)513 std::string sdrplay_source_c::get_antenna( size_t chan )
514 {
515 return "RX";
516 }
517
set_dc_offset_mode(int mode,size_t chan)518 void sdrplay_source_c::set_dc_offset_mode( int mode, size_t chan )
519 {
520 if ( osmosdr::source::DCOffsetOff == mode )
521 {
522 _dev->dcMode = 0;
523 if (_running)
524 {
525 mir_sdr_SetDcMode(4, 1);
526 }
527 }
528 else if ( osmosdr::source::DCOffsetManual == mode )
529 {
530 std::cerr << "Manual DC correction mode is not implemented." << std::endl;
531 _dev->dcMode = 0;
532 if (_running)
533 {
534 mir_sdr_SetDcMode(4, 1);
535 }
536 }
537 else if ( osmosdr::source::DCOffsetAutomatic == mode )
538 {
539 _dev->dcMode = 1;
540 if (_running)
541 {
542 mir_sdr_SetDcMode(4, 1);
543 }
544 }
545 }
546
set_dc_offset(const std::complex<double> & offset,size_t chan)547 void sdrplay_source_c::set_dc_offset( const std::complex<double> &offset, size_t chan )
548 {
549 std::cerr << "Manual DC correction mode is not implemented." << std::endl;
550 }
551
set_bandwidth(double bandwidth,size_t chan)552 double sdrplay_source_c::set_bandwidth( double bandwidth, size_t chan )
553 {
554 if (bandwidth <= 200e3) _dev->bwType = mir_sdr_BW_0_200;
555 else if (bandwidth <= 300e3) _dev->bwType = mir_sdr_BW_0_300;
556 else if (bandwidth <= 600e3) _dev->bwType = mir_sdr_BW_0_600;
557 else if (bandwidth <= 1536e3) _dev->bwType = mir_sdr_BW_1_536;
558 else if (bandwidth <= 5000e3) _dev->bwType = mir_sdr_BW_5_000;
559 else if (bandwidth <= 6000e3) _dev->bwType = mir_sdr_BW_6_000;
560 else if (bandwidth <= 7000e3) _dev->bwType = mir_sdr_BW_7_000;
561 else _dev->bwType = mir_sdr_BW_8_000;
562
563 if (_running)
564 {
565 reinit_device();
566 }
567
568 return get_bandwidth( chan );
569 }
570
get_bandwidth(size_t chan)571 double sdrplay_source_c::get_bandwidth( size_t chan )
572 {
573 double tmpbw=0.0f;
574 if (_dev->bwType == mir_sdr_BW_0_200) tmpbw = 200e3;
575 else if (_dev->bwType == mir_sdr_BW_0_300) tmpbw = 300e3;
576 else if (_dev->bwType == mir_sdr_BW_0_600) tmpbw = 600e3;
577 else if (_dev->bwType == mir_sdr_BW_1_536) tmpbw = 1536e3;
578 else if (_dev->bwType == mir_sdr_BW_5_000) tmpbw = 5000e3;
579 else if (_dev->bwType == mir_sdr_BW_6_000) tmpbw = 6000e3;
580 else if (_dev->bwType == mir_sdr_BW_7_000) tmpbw = 7000e3;
581 else tmpbw = 8000e3;
582
583 return (double)tmpbw;
584 }
585
get_bandwidth_range(size_t chan)586 osmosdr::freq_range_t sdrplay_source_c::get_bandwidth_range( size_t chan )
587 {
588 osmosdr::freq_range_t range;
589
590 range += osmosdr::range_t( 200e3 );
591 range += osmosdr::range_t( 300e3 );
592 range += osmosdr::range_t( 600e3 );
593 range += osmosdr::range_t( 1536e3 );
594 range += osmosdr::range_t( 5000e3 );
595 range += osmosdr::range_t( 6000e3 );
596 range += osmosdr::range_t( 7000e3 );
597 range += osmosdr::range_t( 8000e3 );
598
599 return range;
600 }
601