1 #include "receiver.hh"
2 #include <QTime>
3 
4 using namespace sdr;
5 
Receiver(SourceType type,QObject * parent)6 Receiver::Receiver(SourceType type, QObject *parent)
7   : QObject(parent), _Fbfo(15e2), _sourceType(type), _source(0),
8     _agc(), _wspr(_Fbfo), _audio(), _queue(Queue::get()), _monitor(true), _timer(),
9     _settings("com.github.hmatuschek", "sdr-wspr")
10 {
11   // Load BFO frequency from config
12   _Fbfo = _settings.value("Fbfo", 1.5e3).toDouble();
13   _wspr.setBfoFrequency(_Fbfo);
14 
15   switch (_sourceType) {
16   case AUDIO_SOURCE: _source = new WsprAudioSource(10.1402e6, _Fbfo); break;
17   case RTL_SOURCE: _source = new WsprRtlSource(10.1402e6, _Fbfo); break;
18   case FILE_SOURCE: _source = new WsprFileSource(10.1402e6, _Fbfo); break;
19   }
20 
21   _source->source()->connect(&_agc, true);
22   _agc.connect(&_wspr);
23   if (_monitor) {
24     _agc.connect(&_audio);
25   }
26   // disable AGC by default
27   _agc.enable(false);
28 
29   _queue.addStart(this, &Receiver::_onQueueStart);
30   _queue.addStop(this, &Receiver::_onQueueStop);
31 
32   _timer.setSingleShot(true);
33   QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(_onStartRX()));
34 
35   _messages = new QStandardItemModel();
36   _messages->setColumnCount(5);
37   QStringList headers; headers << "Time" << "Callsign" << "Locator" << "Power" << "Distance"
38                                << "SNR" << "Frequency" << "Delay";
39   _messages->setHorizontalHeaderLabels(headers);
40 
41   // Register message handler
42   _wspr.addMsgReceived(this, &Receiver::_onMessagesReceived);
43 }
44 
~Receiver()45 Receiver::~Receiver() {
46   // pass...
47 }
48 
49 gui::SpectrumProvider *
spectrum()50 Receiver::spectrum() {
51   return &_wspr;
52 }
53 
54 void
join()55 Receiver::join() {
56   _wspr.join();
57 }
58 
59 Receiver::SourceType
sourceType() const60 Receiver::sourceType() const {
61   return _sourceType;
62 }
63 
64 void
setSourceType(SourceType type)65 Receiver::setSourceType(SourceType type) {
66   // Get the current frequency and BFO freq.
67   double F = _source->frequency();
68   double Fbfo = _source->bfoFrequency();
69   // Stop queue (if running)
70   bool is_running = sdr::Queue::get().isRunning();
71   if (is_running) {
72     sdr::Queue::get().stop();
73     sdr::Queue::get().wait();
74   }
75   // Delete current source:
76   delete _source;
77   // Create new source
78   _sourceType = type;
79   switch (_sourceType) {
80   case AUDIO_SOURCE: _source = new WsprAudioSource(F, Fbfo); break;
81   case RTL_SOURCE: _source = new WsprRtlSource(F, Fbfo); break;
82   case FILE_SOURCE: _source = new WsprFileSource(F, Fbfo); break;
83   }
84   // Connect source
85   _source->source()->connect(&_agc, true);
86   // Restart queue (if running)
87   if (is_running) { sdr::Queue::get().start(); }
88 }
89 
90 double
frequency() const91 Receiver::frequency() const {
92   return _source->frequency();
93 }
94 
95 void
setFrequency(double F)96 Receiver::setFrequency(double F) {
97   _source->setFrequency(F);
98 }
99 
100 double
bfoFrequency() const101 Receiver::bfoFrequency() const {
102   return _Fbfo;
103 }
104 
105 void
setBfoFrequency(double F)106 Receiver::setBfoFrequency(double F) {
107   // Update WSPR and source
108   _Fbfo = F;
109   _source->setBfoFrequency(F);
110   _wspr.setBfoFrequency(F);
111   // Store BFO frequency in settings
112   _settings.setValue("Fbfo", _Fbfo);
113 }
114 
115 
116 bool
audioAGCEnabled() const117 Receiver::audioAGCEnabled() const {
118   return _agc.enabled();
119 }
120 
121 void
enableAudioAGC(bool enabled)122 Receiver::enableAudioAGC(bool enabled) {
123   _agc.enable(enabled);
124   if (! enabled) { _agc.setGain(1); }
125 }
126 
127 bool
monitorEnabled() const128 Receiver::monitorEnabled() const {
129   return _monitor;
130 }
131 
132 void
enableMonitor(bool enabled)133 Receiver::enableMonitor(bool enabled) {
134   if (_monitor && !enabled) {
135     // disconnect AGC & audio sink
136     _agc.disconnect(&_audio);
137   } else if ( (!_monitor) && enabled) {
138     _agc.connect(&_audio);
139   }
140   _monitor = enabled;
141 }
142 
143 QString
locator() const144 Receiver::locator() const {
145   return _settings.value("locator", "JO62PK").toString();
146 }
147 
148 void
setLocator(const QString & loc)149 Receiver::setLocator(const QString &loc) {
150   _settings.setValue("locator", loc);
151 }
152 
153 QStandardItemModel *
messages()154 Receiver::messages() {
155   return _messages;
156 }
157 
158 QWidget *
createSourceControl()159 Receiver::createSourceControl() {
160   return _source->createView();
161 }
162 
163 void
_onQueueStart()164 Receiver::_onQueueStart() {
165   _wspr.stopRX();
166   if ((AUDIO_SOURCE == _sourceType) || (RTL_SOURCE == _sourceType)) {
167     QTime t = QTime::currentTime();
168 
169     // Compute seconds til next start
170     int sec = 60-t.second();
171     if (0 == (t.minute() % 2)) { sec += 60; }
172 
173     LogMessage msg(LOG_DEBUG);
174     msg << "Wait for " << sec << " seconds.";
175     Logger::get().log(msg);
176 
177     // Start timer to trigger recording
178     _timer.start(sec*1000);
179   } else {
180     _onStartRX();
181   }
182 }
183 
184 void
_onQueueStop()185 Receiver::_onQueueStop() {
186   _wspr.stopRX();
187   LogMessage msg(LOG_DEBUG);
188   msg << "RX stopped...";
189   Logger::get().log(msg);
190 }
191 
192 void
_onStartRX()193 Receiver::_onStartRX() {
194   _wspr.startRX();
195   LogMessage msg(LOG_DEBUG);
196   msg << "RX Started...";
197   Logger::get().log(msg);
198 }
199 
200 void
_onMessagesReceived()201 Receiver::_onMessagesReceived() {
202   while (_wspr.messages().size()) {
203     WSPRMessage msg = _wspr.messages().front(); _wspr.messages().pop_front();
204     QList<QStandardItem *> row;
205     row.append(new QStandardItem(QTime::currentTime().toString()));
206     row.append(new QStandardItem(QString(msg.callsign().c_str())));
207     row.append(new QStandardItem(QString(msg.locator().c_str())));
208     row.append(new QStandardItem(QString::number(msg.powerW(), 'g', 3)));
209     row.append(new QStandardItem(QString::number(loc_dist(msg.locator(), locator().toStdString()), 'f', 0)));
210     row.append(new QStandardItem(QString::number(msg.snr, 'f', 1)));
211     row.append(new QStandardItem(QString::number(msg.df, 'f', 0)));
212     row.append(new QStandardItem(QString::number(msg.dt, 'f', 1)));
213     _messages->insertRow(0, row);
214   }
215 }
216