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.
remoteinput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2016 Edouard Griffiths, F4EXB //
3 // //
4 // This program is free software; you can redistribute it and/or modify //
5 // it under the terms of the GNU General Public License as published by //
6 // the Free Software Foundation as version 3 of the License, or //
7 // (at your option) any later version. //
8 // //
9 // This program is distributed in the hope that it will be useful, //
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
12 // GNU General Public License V3 for more details. //
13 // //
14 // You should have received a copy of the GNU General Public License //
15 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
17 
18 #include <string.h>
19 #include <errno.h>
20 
21 #include <QDebug>
22 #include <QNetworkReply>
23 #include <QBuffer>
24 
25 #include "SWGDeviceSettings.h"
26 #include "SWGDeviceState.h"
27 #include "SWGDeviceReport.h"
28 #include "SWGRemoteInputReport.h"
29 
30 #include "util/simpleserializer.h"
31 #include "dsp/dspcommands.h"
32 #include "dsp/dspengine.h"
33 #include "device/deviceapi.h"
34 #include "dsp/filerecord.h"
35 
36 #include "remoteinput.h"
37 #include "remoteinputudphandler.h"
38 
46 
48  m_deviceAPI(deviceAPI),
49  m_settings(),
50  m_remoteInputUDPHandler(0),
51  m_deviceDescription(),
52  m_startingTimeStamp(0)
53 {
54  m_sampleFifo.setSize(96000 * 4);
55  m_remoteInputUDPHandler = new RemoteInputUDPHandler(&m_sampleFifo, m_deviceAPI);
56 
57  m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
58  m_deviceAPI->setNbSourceStreams(1);
59  m_deviceAPI->addAncillarySink(m_fileSink);
60 
61  m_networkManager = new QNetworkAccessManager();
62  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
63 }
64 
66 {
67  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
68  delete m_networkManager;
69  stop();
71  delete m_fileSink;
73 }
74 
76 {
77  delete this;
78 }
79 
81 {
83 }
84 
86 {
87  qDebug() << "RemoteInput::start";
89  return true;
90 }
91 
93 {
94  qDebug() << "RemoteInput::stop";
96 }
97 
98 QByteArray RemoteInput::serialize() const
99 {
100  return m_settings.serialize();
101 }
102 
103 bool RemoteInput::deserialize(const QByteArray& data)
104 {
105  bool success = true;
106 
107  if (!m_settings.deserialize(data))
108  {
110  success = false;
111  }
112 
114  m_inputMessageQueue.push(message);
115 
116  if (m_guiMessageQueue)
117  {
119  m_guiMessageQueue->push(messageToGUI);
120  }
121 
122  return success;
123 }
124 
126 {
127  m_guiMessageQueue = queue;
129 }
130 
131 const QString& RemoteInput::getDeviceDescription() const
132 {
133  return m_deviceDescription;
134 }
135 
137 {
139 }
140 
142 {
144 }
145 
146 void RemoteInput::setCenterFrequency(qint64 centerFrequency)
147 {
148  (void) centerFrequency;
149 }
150 
152 {
153  return m_startingTimeStamp;
154 }
155 
157 {
159 }
160 
162 {
163  if (DSPSignalNotification::match(message))
164  {
165  DSPSignalNotification& notif = (DSPSignalNotification&) message;
166  return m_fileSink->handleMessage(notif); // forward to file sink
167  }
168  else if (MsgFileRecord::match(message))
169  {
170  MsgFileRecord& conf = (MsgFileRecord&) message;
171  qDebug() << "RemoteInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
172 
173  if (conf.getStartStop())
174  {
175  if (m_settings.m_fileRecordName.size() != 0) {
177  } else {
179  }
180 
182  }
183  else
184  {
186  }
187 
188  return true;
189  }
190  else if (MsgStartStop::match(message))
191  {
192  MsgStartStop& cmd = (MsgStartStop&) message;
193  qDebug() << "RemoteInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
194 
195  if (cmd.getStartStop())
196  {
198  {
200  }
201  }
202  else
203  {
205  }
206 
209  }
210 
211  return true;
212  }
213  else if (MsgConfigureRemoteInput::match(message))
214  {
215  qDebug() << "RemoteInput::handleMessage:" << message.getIdentifier();
217  applySettings(conf.getSettings(), conf.getForce());
218  return true;
219  }
220  else
221  {
222  return false;
223  }
224 }
225 
226 void RemoteInput::applySettings(const RemoteInputSettings& settings, bool force)
227 {
228  QMutexLocker mutexLocker(&m_mutex);
229  std::ostringstream os;
230  QString remoteAddress;
232  QList<QString> reverseAPIKeys;
233 
234  if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) {
235  reverseAPIKeys.append("dcBlock");
236  }
237  if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) {
238  reverseAPIKeys.append("iqCorrection");
239  }
240  if ((m_settings.m_dataAddress != settings.m_dataAddress) || force) {
241  reverseAPIKeys.append("dataAddress");
242  }
243  if ((m_settings.m_dataPort != settings.m_dataPort) || force) {
244  reverseAPIKeys.append("dataPort");
245  }
246  if ((m_settings.m_apiAddress != settings.m_apiAddress) || force) {
247  reverseAPIKeys.append("apiAddress");
248  }
249  if ((m_settings.m_apiPort != settings.m_apiPort) || force) {
250  reverseAPIKeys.append("apiPort");
251  }
252  if ((m_settings.m_fileRecordName != settings.m_fileRecordName) || force) {
253  reverseAPIKeys.append("fileRecordName");
254  }
255 
256  if ((m_settings.m_dcBlock != settings.m_dcBlock) || (m_settings.m_iqCorrection != settings.m_iqCorrection) || force)
257  {
259  qDebug("RemoteInput::applySettings: corrections: DC block: %s IQ imbalance: %s",
260  settings.m_dcBlock ? "true" : "false",
261  settings.m_iqCorrection ? "true" : "false");
262  }
263 
266 
267  mutexLocker.unlock();
268 
269  if (settings.m_useReverseAPI)
270  {
271  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
275  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
276  }
277 
278  m_settings = settings;
279  m_remoteAddress = remoteAddress;
280 
281  qDebug() << "RemoteInput::applySettings: "
282  << " m_dataAddress: " << m_settings.m_dataAddress
283  << " m_dataPort: " << m_settings.m_dataPort
284  << " m_apiAddress: " << m_settings.m_apiAddress
285  << " m_apiPort: " << m_settings.m_apiPort
286  << " m_remoteAddress: " << m_remoteAddress;
287 }
288 
290  SWGSDRangel::SWGDeviceState& response,
291  QString& errorMessage)
292 {
293  (void) errorMessage;
295  return 200;
296 }
297 
299  bool run,
300  SWGSDRangel::SWGDeviceState& response,
301  QString& errorMessage)
302 {
303  (void) errorMessage;
305  MsgStartStop *message = MsgStartStop::create(run);
306  m_inputMessageQueue.push(message);
307 
308  if (m_guiMessageQueue) // forward to GUI if any
309  {
310  MsgStartStop *msgToGUI = MsgStartStop::create(run);
311  m_guiMessageQueue->push(msgToGUI);
312  }
313 
314  return 200;
315 }
316 
319  QString& errorMessage)
320 {
321  (void) errorMessage;
323  response.getRemoteInputSettings()->init();
325  return 200;
326 }
327 
329  bool force,
330  const QStringList& deviceSettingsKeys,
331  SWGSDRangel::SWGDeviceSettings& response, // query + response
332  QString& errorMessage)
333 {
334  (void) errorMessage;
335  RemoteInputSettings settings = m_settings;
336 
337  if (deviceSettingsKeys.contains("apiAddress")) {
338  settings.m_apiAddress = *response.getRemoteInputSettings()->getApiAddress();
339  }
340  if (deviceSettingsKeys.contains("apiPort")) {
341  settings.m_apiPort = response.getRemoteInputSettings()->getApiPort();
342  }
343  if (deviceSettingsKeys.contains("dataAddress")) {
344  settings.m_dataAddress = *response.getRemoteInputSettings()->getDataAddress();
345  }
346  if (deviceSettingsKeys.contains("dataPort")) {
347  settings.m_dataPort = response.getRemoteInputSettings()->getDataPort();
348  }
349  if (deviceSettingsKeys.contains("dcBlock")) {
350  settings.m_dcBlock = response.getRemoteInputSettings()->getDcBlock() != 0;
351  }
352  if (deviceSettingsKeys.contains("iqCorrection")) {
353  settings.m_iqCorrection = response.getRemoteInputSettings()->getIqCorrection() != 0;
354  }
355  if (deviceSettingsKeys.contains("fileRecordName")) {
357  }
358  if (deviceSettingsKeys.contains("useReverseAPI")) {
359  settings.m_useReverseAPI = response.getRemoteInputSettings()->getUseReverseApi() != 0;
360  }
361  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
363  }
364  if (deviceSettingsKeys.contains("reverseAPIPort")) {
366  }
367  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
369  }
370 
373 
374  if (m_guiMessageQueue) // forward to GUI if any
375  {
376  MsgConfigureRemoteInput *msgToGUI = MsgConfigureRemoteInput::create(settings, force);
377  m_guiMessageQueue->push(msgToGUI);
378  }
379 
380  webapiFormatDeviceSettings(response, settings);
381  return 200;
382 }
383 
385 {
386  response.getRemoteInputSettings()->setApiAddress(new QString(settings.m_apiAddress));
387  response.getRemoteInputSettings()->setApiPort(settings.m_apiPort);
388  response.getRemoteInputSettings()->setDataAddress(new QString(settings.m_dataAddress));
389  response.getRemoteInputSettings()->setDataPort(settings.m_dataPort);
390  response.getRemoteInputSettings()->setDcBlock(settings.m_dcBlock ? 1 : 0);
392 
393  if (response.getRemoteInputSettings()->getFileRecordName()) {
395  } else {
396  response.getRemoteInputSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
397  }
398 
399  response.getRemoteInputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
400 
401  if (response.getRemoteInputSettings()->getReverseApiAddress()) {
403  } else {
404  response.getRemoteInputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
405  }
406 
409 }
410 
413  QString& errorMessage)
414 {
415  (void) errorMessage;
417  response.getRemoteInputReport()->init();
418  webapiFormatDeviceReport(response);
419  return 200;
420 }
421 
423 {
427 
428  QDateTime dt = QDateTime::fromMSecsSinceEpoch(m_remoteInputUDPHandler->getTVmSec());
429  response.getRemoteInputReport()->setRemoteTimestamp(new QString(dt.toString("yyyy-MM-dd HH:mm:ss.zzz")));
430 
433 }
434 
435 void RemoteInput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const RemoteInputSettings& settings, bool force)
436 {
438  swgDeviceSettings->setDirection(0); // single Rx
439  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
440  swgDeviceSettings->setDeviceHwType(new QString("RemoteInput"));
442  SWGSDRangel::SWGRemoteInputSettings *swgRemoteInputSettings = swgDeviceSettings->getRemoteInputSettings();
443 
444  // transfer data that has been modified. When force is on transfer all data except reverse API data
445 
446  if (deviceSettingsKeys.contains("apiAddress") || force) {
447  swgRemoteInputSettings->setApiAddress(new QString(settings.m_apiAddress));
448  }
449  if (deviceSettingsKeys.contains("apiPort") || force) {
450  swgRemoteInputSettings->setApiPort(settings.m_apiPort);
451  }
452  if (deviceSettingsKeys.contains("dataAddress") || force) {
453  swgRemoteInputSettings->setDataAddress(new QString(settings.m_dataAddress));
454  }
455  if (deviceSettingsKeys.contains("dataPort") || force) {
456  swgRemoteInputSettings->setDataPort(settings.m_dataPort);
457  }
458  if (deviceSettingsKeys.contains("dcBlock") || force) {
459  swgRemoteInputSettings->setDcBlock(settings.m_dcBlock ? 1 : 0);
460  }
461  if (deviceSettingsKeys.contains("iqCorrection") || force) {
462  swgRemoteInputSettings->setIqCorrection(settings.m_iqCorrection ? 1 : 0);
463  }
464  if (deviceSettingsKeys.contains("fileRecordName") || force) {
465  swgRemoteInputSettings->setFileRecordName(new QString(settings.m_fileRecordName));
466  }
467 
468  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
469  .arg(settings.m_reverseAPIAddress)
470  .arg(settings.m_reverseAPIPort)
471  .arg(settings.m_reverseAPIDeviceIndex);
472  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
473  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
474 
475  QBuffer *buffer=new QBuffer();
476  buffer->open((QBuffer::ReadWrite));
477  buffer->write(swgDeviceSettings->asJson().toUtf8());
478  buffer->seek(0);
479 
480  // Always use PATCH to avoid passing reverse API settings
481  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
482 
483  delete swgDeviceSettings;
484 }
485 
487 {
489  swgDeviceSettings->setDirection(0); // single Rx
490  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
491  swgDeviceSettings->setDeviceHwType(new QString("RemoteInput"));
492 
493  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
497  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
498  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
499 
500  QBuffer *buffer=new QBuffer();
501  buffer->open((QBuffer::ReadWrite));
502  buffer->write(swgDeviceSettings->asJson().toUtf8());
503  buffer->seek(0);
504 
505  if (start) {
506  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
507  } else {
508  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
509  }
510 
511  delete swgDeviceSettings;
512 }
513 
514 void RemoteInput::networkManagerFinished(QNetworkReply *reply)
515 {
516  QNetworkReply::NetworkError replyError = reply->error();
517 
518  if (replyError)
519  {
520  qWarning() << "RemoteInput::networkManagerFinished:"
521  << " error(" << (int) replyError
522  << "): " << replyError
523  << ": " << reply->errorString();
524  return;
525  }
526 
527  QString answer = reply->readAll();
528  answer.chop(1); // remove last \n
529  qDebug("RemoteInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
530 }
void setDataAddress(QString *data_address)
FileRecord * m_fileSink
File sink to record device I/Q output.
Definition: remoteinput.h:324
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
bool isStreaming() const
void setMessageQueueToGUI(MessageQueue *queue)
void setMinNbBlocks(qint32 min_nb_blocks)
void setRemoteTimestamp(QString *remote_timestamp)
QMutex m_mutex
Definition: remoteinput.h:318
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void stopDeviceEngine()
Stop the device engine corresponding to the stream type.
Definition: deviceapi.cpp:266
void getRemoteAddress(QString &s) const
void setFileName(const QString &filename)
Definition: filerecord.cpp:59
uint getDeviceUID() const
Return the current device engine unique ID.
Definition: deviceapi.cpp:303
void setReverseApiPort(qint32 reverse_api_port)
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
void setRemoteInputReport(SWGRemoteInputReport *remote_input_report)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
void startRecording()
Definition: filerecord.cpp:105
void applySettings(const RemoteInputSettings &settings, bool force=false)
MessageQueue m_inputMessageQueue
Input queue to the source.
RemoteInputSettings m_settings
Definition: remoteinput.h:319
virtual QString asJson() override
QNetworkRequest m_networkRequest
Definition: remoteinput.h:326
virtual QByteArray serialize() const
Definition: remoteinput.cpp:98
SWGRemoteInputReport * getRemoteInputReport()
virtual quint64 getCenterFrequency() const
Center frequency exposed by the source.
QNetworkAccessManager * m_networkManager
Definition: remoteinput.h:325
RemoteInputUDPHandler * m_remoteInputUDPHandler
Definition: remoteinput.h:320
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
QByteArray serialize() const
static MsgConfigureRemoteInput * create(const RemoteInputSettings &settings, bool force=false)
Definition: remoteinput.h:50
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
virtual ~RemoteInput()
Definition: remoteinput.cpp:65
void setOriginatorIndex(qint32 originator_index)
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
virtual bool handleMessage(const Message &message)
Processing of a message. Returns true if message has actually been processed.
Definition: filerecord.cpp:128
void setUseReverseApi(qint32 use_reverse_api)
void setCenterFrequency(qint32 center_frequency)
void setMaxNbRecovery(qint32 max_nb_recovery)
int getDeviceSetIndex() const
Definition: deviceapi.h:131
virtual const QString & getDeviceDescription() const
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
void genUniqueFileName(uint deviceUID, int istream=-1)
Definition: filerecord.cpp:67
virtual void setMessageQueueToGUI(MessageQueue *queue)
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
std::time_t m_startingTimeStamp
Definition: remoteinput.h:323
virtual int getSampleRate() const
Sample rate exposed by the source.
void stopRecording()
Definition: filerecord.cpp:117
static bool match(const Message *message)
Definition: message.cpp:45
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const RemoteInputSettings &settings)
QString m_remoteAddress
Definition: remoteinput.h:321
virtual void setCenterFrequency(qint64 centerFrequency)
void removeAncillarySink(BasebandSampleSink *sink, unsigned int index=0)
Removes it.
Definition: deviceapi.cpp:100
void configureUDPLink(const QString &address, quint16 port)
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
static MsgStartStop * create(bool startStop)
Definition: remoteinput.h:258
virtual bool start()
Definition: remoteinput.cpp:85
virtual void stop()
Definition: remoteinput.cpp:92
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
void setRemoteInputSettings(SWGRemoteInputSettings *remote_input_settings)
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
void setBufferRwBalance(qint32 buffer_rw_balance)
std::time_t getStartingTimeStamp() const
DeviceAPI * m_deviceAPI
Definition: remoteinput.h:317
QString m_deviceDescription
Definition: remoteinput.h:322
virtual const char * getIdentifier() const
Definition: message.cpp:35
void networkManagerFinished(QNetworkReply *reply)
virtual void destroy()
Definition: remoteinput.cpp:75
bool deserialize(const QByteArray &data)
void setFileRecordName(QString *file_record_name)
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
Definition: remoteinput.cpp:80
void webapiReverseSendStartStop(bool start)
SWGRemoteInputSettings * getRemoteInputSettings()
void setReverseApiAddress(QString *reverse_api_address)
const RemoteInputSettings & getSettings() const
Definition: remoteinput.h:47
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
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
void setDirection(qint32 direction)
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const RemoteInputSettings &settings, bool force)
virtual bool deserialize(const QByteArray &data)
void setDeviceHwType(QString *device_hw_type)
virtual bool handleMessage(const Message &message)