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