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