SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
kiwisdrinput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2019 Vort //
3 // Copyright (C) 2019 Edouard Griffiths, F4EXB //
4 // //
5 // This program is free software; you can redistribute it and/or modify //
6 // it under the terms of the GNU General Public License as published by //
7 // the Free Software Foundation as version 3 of the License, or //
8 // (at your option) any later version. //
9 // //
10 // This program is distributed in the hope that it will be useful, //
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
13 // GNU General Public License V3 for more details. //
14 // //
15 // You should have received a copy of the GNU General Public License //
16 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
18 
19 #include <string.h>
20 #include <errno.h>
21 
22 #include <QDebug>
23 #include <QNetworkReply>
24 #include <QNetworkAccessManager>
25 #include <QBuffer>
26 
27 #include "SWGDeviceSettings.h"
28 #include "SWGDeviceState.h"
29 #include "SWGDeviceReport.h"
30 #include "SWGKiwiSDRReport.h"
31 
32 #include "kiwisdrinput.h"
33 #include "device/deviceapi.h"
34 #include "kiwisdrworker.h"
35 #include "dsp/dspcommands.h"
36 #include "dsp/dspengine.h"
37 #include "dsp/filerecord.h"
38 
43 
44 
46  m_deviceAPI(deviceAPI),
47  m_settings(),
48  m_kiwiSDRWorker(nullptr),
49  m_deviceDescription(),
50  m_running(false),
51  m_masterTimer(deviceAPI->getMasterTimer())
52 {
53  m_kiwiSDRWorkerThread.start();
54 
55  m_fileSink = new FileRecord();
56  m_deviceAPI->setNbSourceStreams(1);
57  m_deviceAPI->addAncillarySink(m_fileSink);
58 
59  if (!m_sampleFifo.setSize(getSampleRate() * 2)) {
60  qCritical("KiwiSDRInput::KiwiSDRInput: Could not allocate SampleFifo");
61  }
62 
63  m_networkManager = new QNetworkAccessManager();
64  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
65 }
66 
68 {
69  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
70  delete m_networkManager;
71 
72  if (m_running) {
73  stop();
74  }
75 
76  m_kiwiSDRWorkerThread.quit();
77  m_kiwiSDRWorkerThread.wait();
78 
80  delete m_fileSink;
81 }
82 
84 {
85  delete this;
86 }
87 
89 {
91 }
92 
94 {
95  QMutexLocker mutexLocker(&m_mutex);
96 
97  if (m_running) stop();
98 
100  m_kiwiSDRWorker->moveToThread(&m_kiwiSDRWorkerThread);
101 
106 
107  mutexLocker.unlock();
108 
109  applySettings(m_settings, true);
110  m_running = true;
111 
112  return true;
113 }
114 
116 {
117  QMutexLocker mutexLocker(&m_mutex);
118 
119  setWorkerStatus(0);
120 
121  if (m_kiwiSDRWorker != 0)
122  {
123  m_kiwiSDRWorker->deleteLater();
124  m_kiwiSDRWorker = 0;
125  }
126 
127  m_running = false;
128 }
129 
130 QByteArray KiwiSDRInput::serialize() const
131 {
132  return m_settings.serialize();
133 }
134 
135 bool KiwiSDRInput::deserialize(const QByteArray& data)
136 {
137  bool success = true;
138 
139  if (!m_settings.deserialize(data))
140  {
142  success = false;
143  }
144 
146  m_inputMessageQueue.push(message);
147 
148  if (m_guiMessageQueue)
149  {
151  m_guiMessageQueue->push(messageToGUI);
152  }
153 
154  return success;
155 }
156 
158 {
159  return m_deviceDescription;
160 }
161 
163 {
164  return 12000;
165 }
166 
168 {
170 }
171 
172 void KiwiSDRInput::setCenterFrequency(qint64 centerFrequency)
173 {
174  KiwiSDRSettings settings = m_settings;
175  settings.m_centerFrequency = centerFrequency;
176 
177  MsgConfigureKiwiSDR* message = MsgConfigureKiwiSDR::create(settings, false);
178  m_inputMessageQueue.push(message);
179 
180  if (m_guiMessageQueue)
181  {
182  MsgConfigureKiwiSDR* messageToGUI = MsgConfigureKiwiSDR::create(settings, false);
183  m_guiMessageQueue->push(messageToGUI);
184  }
185 }
186 
188 {
189  if (m_guiMessageQueue) {
191  }
192 }
193 
195 {
196  if (MsgConfigureKiwiSDR::match(message))
197  {
198  MsgConfigureKiwiSDR& conf = (MsgConfigureKiwiSDR&) message;
199  qDebug() << "KiwiSDRInput::handleMessage: MsgConfigureKiwiSDR";
200 
201  bool success = applySettings(conf.getSettings(), conf.getForce());
202 
203  if (!success)
204  {
205  qDebug("KiwiSDRInput::handleMessage: config error");
206  }
207 
208  return true;
209  }
210  else if (MsgFileRecord::match(message))
211  {
212  MsgFileRecord& conf = (MsgFileRecord&) message;
213  qDebug() << "KiwiSDRInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
214 
215  if (conf.getStartStop())
216  {
217  if (m_settings.m_fileRecordName.size() != 0) {
219  } else {
221  }
222 
224  }
225  else
226  {
228  }
229 
230  return true;
231  }
232  else if (MsgStartStop::match(message))
233  {
234  MsgStartStop& cmd = (MsgStartStop&) message;
235  qDebug() << "KiwiSDRInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
236 
237  if (cmd.getStartStop())
238  {
240  {
242  }
243  }
244  else
245  {
247  }
248 
251  }
252 
253  return true;
254  }
255  else
256  {
257  return false;
258  }
259 }
260 
262 {
263  if (m_kiwiSDRWorker) {
264  return m_kiwiSDRWorker->getStatus();
265  } else {
266  return 0;
267  }
268 }
269 
270 bool KiwiSDRInput::applySettings(const KiwiSDRSettings& settings, bool force)
271 {
272  qDebug() << "KiwiSDRInput::applySettings: "
273  << " m_serverAddress: " << settings.m_serverAddress
274  << " m_centerFrequency: " << settings.m_centerFrequency
275  << " m_gain: " << settings.m_gain
276  << " m_useAGC: " << settings.m_useAGC
277  << " m_fileRecordName: " << settings.m_fileRecordName
278  << " m_useAGC: " << settings.m_useAGC
279  << " m_useReverseAPI: " << settings.m_useReverseAPI
280  << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
281  << " m_reverseAPIPort: " << settings.m_reverseAPIPort
282  << " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex;
283 
284  QList<QString> reverseAPIKeys;
285 
286  if (m_settings.m_serverAddress != settings.m_serverAddress || force)
287  {
288  reverseAPIKeys.append("serverAddress");
290  }
291 
292  if (m_settings.m_gain != settings.m_gain || force) {
293  reverseAPIKeys.append("gain");
294  }
295  if (m_settings.m_useAGC != settings.m_useAGC || force) {
296  reverseAPIKeys.append("useAGC");
297  }
298 
299  if (m_settings.m_gain != settings.m_gain ||
300  m_settings.m_useAGC != settings.m_useAGC || force)
301  {
302  emit setWorkerGain(settings.m_gain, settings.m_useAGC);
303  }
304 
305  if (m_settings.m_dcBlock != settings.m_dcBlock)
306  {
307  reverseAPIKeys.append("dcBlock");
308  m_deviceAPI->configureCorrections(settings.m_dcBlock, false);
309  }
310 
311  if (m_settings.m_centerFrequency != settings.m_centerFrequency || force)
312  {
313  reverseAPIKeys.append("centerFrequency");
314 
316 
318  getSampleRate(), settings.m_centerFrequency);
319  m_fileSink->handleMessage(*notif); // forward to file sink
321  }
322 
323  if (settings.m_useReverseAPI)
324  {
325  qDebug("KiwiSDRInput::applySettings: call webapiReverseSendSettings");
326  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
330  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
331  }
332 
333  m_settings = settings;
334  return true;
335 }
336 
338  SWGSDRangel::SWGDeviceState& response,
339  QString& errorMessage)
340 {
341  (void) errorMessage;
343  return 200;
344 }
345 
347  bool run,
348  SWGSDRangel::SWGDeviceState& response,
349  QString& errorMessage)
350 {
351  (void) errorMessage;
353  MsgStartStop *message = MsgStartStop::create(run);
354  m_inputMessageQueue.push(message);
355 
356  if (m_guiMessageQueue) // forward to GUI if any
357  {
358  MsgStartStop *msgToGUI = MsgStartStop::create(run);
359  m_guiMessageQueue->push(msgToGUI);
360  }
361 
362  return 200;
363 }
364 
367  QString& errorMessage)
368 {
369  (void) errorMessage;
371  response.getKiwiSdrSettings()->init();
373  return 200;
374 }
375 
377  bool force,
378  const QStringList& deviceSettingsKeys,
379  SWGSDRangel::SWGDeviceSettings& response, // query + response
380  QString& errorMessage)
381 {
382  (void) errorMessage;
383  KiwiSDRSettings settings = m_settings;
384 
385  if (deviceSettingsKeys.contains("gain")) {
386  settings.m_gain = response.getKiwiSdrSettings()->getGain();
387  }
388  if (deviceSettingsKeys.contains("useAGC")) {
389  settings.m_useAGC = response.getKiwiSdrSettings()->getUseAgc();
390  }
391  if (deviceSettingsKeys.contains("dcBlock")) {
392  settings.m_dcBlock = response.getKiwiSdrSettings()->getDcBlock() != 0;
393  }
394  if (deviceSettingsKeys.contains("centerFrequency")) {
396  }
397  if (deviceSettingsKeys.contains("serverAddress")) {
398  settings.m_serverAddress = *response.getKiwiSdrSettings()->getServerAddress();
399  }
400  if (deviceSettingsKeys.contains("fileRecordName")) {
401  settings.m_fileRecordName = *response.getKiwiSdrSettings()->getFileRecordName();
402  }
403  if (deviceSettingsKeys.contains("useReverseAPI")) {
404  settings.m_useReverseAPI = response.getKiwiSdrSettings()->getUseReverseApi() != 0;
405  }
406  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
408  }
409  if (deviceSettingsKeys.contains("reverseAPIPort")) {
410  settings.m_reverseAPIPort = response.getKiwiSdrSettings()->getReverseApiPort();
411  }
412  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
414  }
415 
416  MsgConfigureKiwiSDR *msg = MsgConfigureKiwiSDR::create(settings, force);
418 
419  if (m_guiMessageQueue) // forward to GUI if any
420  {
421  MsgConfigureKiwiSDR *msgToGUI = MsgConfigureKiwiSDR::create(settings, force);
422  m_guiMessageQueue->push(msgToGUI);
423  }
424 
425  webapiFormatDeviceSettings(response, settings);
426  return 200;
427 }
428 
431  QString& errorMessage)
432 {
433  (void) errorMessage;
435  response.getKiwiSdrReport()->init();
436  webapiFormatDeviceReport(response);
437  return 200;
438 }
439 
441 {
442  response.getKiwiSdrSettings()->setGain(settings.m_gain);
443  response.getKiwiSdrSettings()->setUseAgc(settings.m_useAGC ? 1 : 0);
444  response.getKiwiSdrSettings()->setDcBlock(settings.m_dcBlock ? 1 : 0);
446 
447  if (response.getKiwiSdrSettings()->getServerAddress()) {
448  *response.getKiwiSdrSettings()->getServerAddress() = settings.m_serverAddress;
449  } else {
450  response.getKiwiSdrSettings()->setServerAddress(new QString(settings.m_serverAddress));
451  }
452 
453  if (response.getKiwiSdrSettings()->getFileRecordName()) {
454  *response.getKiwiSdrSettings()->getFileRecordName() = settings.m_fileRecordName;
455  } else {
456  response.getKiwiSdrSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
457  }
458 
459  response.getKiwiSdrSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
460 
461  if (response.getKiwiSdrSettings()->getReverseApiAddress()) {
463  } else {
464  response.getKiwiSdrSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
465  }
466 
469 }
470 
472 {
473  response.getKiwiSdrReport()->setStatus(getStatus());
474 }
475 
476 void KiwiSDRInput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const KiwiSDRSettings& settings, bool force)
477 {
479  swgDeviceSettings->setDirection(0); // single Rx
480  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
481  swgDeviceSettings->setDeviceHwType(new QString("KiwiSDR"));
482  swgDeviceSettings->setKiwiSdrSettings(new SWGSDRangel::SWGKiwiSDRSettings());
483  SWGSDRangel::SWGKiwiSDRSettings *swgKiwiSDRSettings = swgDeviceSettings->getKiwiSdrSettings();
484 
485  // transfer data that has been modified. When force is on transfer all data except reverse API data
486 
487  if (deviceSettingsKeys.contains("gain")) {
488  swgKiwiSDRSettings->setGain(settings.m_gain);
489  }
490  if (deviceSettingsKeys.contains("useAGC")) {
491  swgKiwiSDRSettings->setUseAgc(settings.m_useAGC ? 1 : 0);
492  }
493  if (deviceSettingsKeys.contains("dcBlock") || force) {
494  swgKiwiSDRSettings->setDcBlock(settings.m_dcBlock ? 1 : 0);
495  }
496  if (deviceSettingsKeys.contains("centerFrequency") || force) {
497  swgKiwiSDRSettings->setCenterFrequency(settings.m_centerFrequency);
498  }
499  if (deviceSettingsKeys.contains("serverAddress") || force) {
500  swgKiwiSDRSettings->setServerAddress(new QString(settings.m_serverAddress));
501  }
502  if (deviceSettingsKeys.contains("fileRecordName") || force) {
503  swgKiwiSDRSettings->setFileRecordName(new QString(settings.m_fileRecordName));
504  }
505 
506  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
507  .arg(settings.m_reverseAPIAddress)
508  .arg(settings.m_reverseAPIPort)
509  .arg(settings.m_reverseAPIDeviceIndex);
510  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
511  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
512 
513  QBuffer *buffer=new QBuffer();
514  buffer->open((QBuffer::ReadWrite));
515  buffer->write(swgDeviceSettings->asJson().toUtf8());
516  buffer->seek(0);
517 
518  // Always use PATCH to avoid passing reverse API settings
519  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
520 
521  delete swgDeviceSettings;
522 }
523 
525 {
527  swgDeviceSettings->setDirection(0); // single Rx
528  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
529  swgDeviceSettings->setDeviceHwType(new QString("KiwiSDR"));
530 
531  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
535  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
536  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
537 
538  QBuffer *buffer=new QBuffer();
539  buffer->open((QBuffer::ReadWrite));
540  buffer->write(swgDeviceSettings->asJson().toUtf8());
541  buffer->seek(0);
542 
543  if (start) {
544  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
545  } else {
546  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
547  }
548 
549  delete swgDeviceSettings;
550 }
551 
552 void KiwiSDRInput::networkManagerFinished(QNetworkReply *reply)
553 {
554  QNetworkReply::NetworkError replyError = reply->error();
555 
556  if (replyError)
557  {
558  qWarning() << "KiwiSDRInput::networkManagerFinished:"
559  << " error(" << (int) replyError
560  << "): " << replyError
561  << ": " << reply->errorString();
562  return;
563  }
564 
565  QString answer = reply->readAll();
566  answer.chop(1); // remove last \n
567  qDebug("KiwiSDRInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
568 }
int getStatus() const
Definition: kiwisdrworker.h:31
void setReverseApiPort(qint32 reverse_api_port)
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
void setWorkerServerAddress(QString serverAddress)
QNetworkAccessManager * m_networkManager
Definition: kiwisdrinput.h:173
DeviceAPI * m_deviceAPI
Definition: kiwisdrinput.h:164
QThread m_kiwiSDRWorkerThread
Definition: kiwisdrinput.h:169
int getStatus() const
void push(Message *message, bool emitSignal=true)
Push message onto queue.
QString m_serverAddress
void stopDeviceEngine()
Stop the device engine corresponding to the stream type.
Definition: deviceapi.cpp:266
bool applySettings(const KiwiSDRSettings &settings, bool force)
void setFileName(const QString &filename)
Definition: filerecord.cpp:59
void onCenterFrequencyChanged(quint64 centerFrequency)
uint getDeviceUID() const
Return the current device engine unique ID.
Definition: deviceapi.cpp:303
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
void startRecording()
Definition: filerecord.cpp:105
MessageQueue m_inputMessageQueue
Input queue to the source.
virtual QString asJson() override
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
void webapiReverseSendStartStop(bool start)
virtual bool start()
void setCenterFrequency(qint64 center_frequency)
virtual bool deserialize(const QByteArray &data)
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
void setKiwiSdrReport(SWGKiwiSDRReport *kiwi_sdr_report)
virtual bool handleMessage(const Message &message)
static MsgSetStatus * create(int status)
Definition: kiwisdrinput.h:107
QNetworkRequest m_networkRequest
Definition: kiwisdrinput.h:174
void setOriginatorIndex(qint32 originator_index)
virtual void destroy()
SampleSinkFifo m_sampleFifo
QString m_reverseAPIAddress
virtual void stop()
virtual bool handleMessage(const Message &message)
Processing of a message. Returns true if message has actually been processed.
Definition: filerecord.cpp:128
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
virtual QByteArray serialize() const
SWGKiwiSDRReport * getKiwiSdrReport()
void setServerAddress(QString *server_address)
int getDeviceSetIndex() const
Definition: deviceapi.h:131
void networkManagerFinished(QNetworkReply *reply)
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
void genUniqueFileName(uint deviceUID, int istream=-1)
Definition: filerecord.cpp:67
static MsgConfigureKiwiSDR * create(const KiwiSDRSettings &settings, bool force)
Definition: kiwisdrinput.h:47
void setFileRecordName(QString *file_record_name)
QString m_deviceDescription
Definition: kiwisdrinput.h:170
void updateStatus(int status)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
void stopRecording()
Definition: filerecord.cpp:117
virtual quint64 getCenterFrequency() const
Center frequency exposed by the source.
virtual ~KiwiSDRInput()
void setKiwiSdrSettings(SWGKiwiSDRSettings *kiwi_sdr_settings)
static bool match(const Message *message)
Definition: message.cpp:45
void setUseReverseApi(qint32 use_reverse_api)
uint16_t m_reverseAPIDeviceIndex
void setWorkerGain(quint32 gain, bool useAGC)
QString m_fileRecordName
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
void removeAncillarySink(BasebandSampleSink *sink, unsigned int index=0)
Removes it.
Definition: deviceapi.cpp:100
void onServerAddressChanged(QString serverAddress)
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
void setWorkerCenterFrequency(quint64 centerFrequency)
virtual const QString & getDeviceDescription() const
void setReverseApiAddress(QString *reverse_api_address)
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
static MsgStartStop * create(bool startStop)
Definition: kiwisdrinput.h:88
const KiwiSDRSettings & getSettings() const
Definition: kiwisdrinput.h:44
virtual int getSampleRate() const
Sample rate exposed by the source.
FileRecord * m_fileSink
File sink to record device I/Q output.
Definition: kiwisdrinput.h:165
bool deserialize(const QByteArray &data)
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const KiwiSDRSettings &settings, bool force)
void setWorkerStatus(int status)
uint16_t m_reverseAPIPort
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
quint64 m_centerFrequency
KiwiSDRSettings m_settings
Definition: kiwisdrinput.h:167
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection, int streamIndex=0)
Configure current device engine DSP corrections (Rx)
Definition: deviceapi.cpp:355
KiwiSDRWorker * m_kiwiSDRWorker
Definition: kiwisdrinput.h:168
void setDirection(qint32 direction)
void onGainChanged(quint32 gain, bool useAGC)
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const KiwiSDRSettings &settings)
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
QByteArray serialize() const
void setDeviceHwType(QString *device_hw_type)
SWGKiwiSDRSettings * getKiwiSdrSettings()
QMutex m_mutex
Definition: kiwisdrinput.h:166
virtual void setCenterFrequency(qint64 centerFrequency)