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.
localinput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2019 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 "SWGLocalInputReport.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 "localinput.h"
37 
42 
44  m_deviceAPI(deviceAPI),
45  m_settings(),
46  m_centerFrequency(0),
47  m_deviceDescription("LocalInput")
48 {
49  m_sampleFifo.setSize(96000 * 4);
50 
51  m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
52  m_deviceAPI->setNbSourceStreams(1);
53  m_deviceAPI->addAncillarySink(m_fileSink);
54 
55  m_networkManager = new QNetworkAccessManager();
56  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
57 }
58 
60 {
61  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
62  delete m_networkManager;
63  stop();
65  delete m_fileSink;
66 }
67 
69 {
70  delete this;
71 }
72 
74 {
76 }
77 
79 {
80  qDebug() << "LocalInput::start";
81  return true;
82 }
83 
85 {
86  qDebug() << "LocalInput::stop";
87 }
88 
89 QByteArray LocalInput::serialize() const
90 {
91  return m_settings.serialize();
92 }
93 
94 bool LocalInput::deserialize(const QByteArray& data)
95 {
96  bool success = true;
97 
98  if (!m_settings.deserialize(data))
99  {
101  success = false;
102  }
103 
105  m_inputMessageQueue.push(message);
106 
107  if (m_guiMessageQueue)
108  {
110  m_guiMessageQueue->push(messageToGUI);
111  }
112 
113  return success;
114 }
115 
117 {
118  m_guiMessageQueue = queue;
119 }
120 
121 const QString& LocalInput::getDeviceDescription() const
122 {
123  return m_deviceDescription;
124 }
125 
127 {
128  return m_sampleRate;
129 }
130 
131 void LocalInput::setSampleRate(int sampleRate)
132 {
133  m_sampleRate = sampleRate;
134 
135  DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency); // Frequency in Hz for the DSP engine
137 
138  if (getMessageQueueToGUI())
139  {
141  getMessageQueueToGUI()->push(msg);
142  }
143 }
144 
146 {
147  return m_centerFrequency;
148 }
149 
150 void LocalInput::setCenterFrequency(qint64 centerFrequency)
151 {
152  m_centerFrequency = centerFrequency;
153 
154  DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency); // Frequency in Hz for the DSP engine
156 
157  if (getMessageQueueToGUI())
158  {
160  getMessageQueueToGUI()->push(msg);
161  }
162 }
163 
164 bool LocalInput::handleMessage(const Message& message)
165 {
166  if (DSPSignalNotification::match(message))
167  {
168  DSPSignalNotification& notif = (DSPSignalNotification&) message;
169  return m_fileSink->handleMessage(notif); // forward to file sink
170  }
171  else if (MsgFileRecord::match(message))
172  {
173  MsgFileRecord& conf = (MsgFileRecord&) message;
174  qDebug() << "LocalInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
175 
176  if (conf.getStartStop())
177  {
178  if (m_settings.m_fileRecordName.size() != 0) {
180  } else {
182  }
183 
185  }
186  else
187  {
189  }
190 
191  return true;
192  }
193  else if (MsgStartStop::match(message))
194  {
195  MsgStartStop& cmd = (MsgStartStop&) message;
196  qDebug() << "LocalInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
197 
198  if (cmd.getStartStop())
199  {
201  {
203  }
204  }
205  else
206  {
208  }
209 
212  }
213 
214  return true;
215  }
216  else if (MsgConfigureLocalInput::match(message))
217  {
218  qDebug() << "LocalInput::handleMessage:" << message.getIdentifier();
220  applySettings(conf.getSettings(), conf.getForce());
221  return true;
222  }
223  else
224  {
225  return false;
226  }
227 }
228 
229 void LocalInput::applySettings(const LocalInputSettings& settings, bool force)
230 {
231  QMutexLocker mutexLocker(&m_mutex);
232  std::ostringstream os;
233  QString remoteAddress;
234  QList<QString> reverseAPIKeys;
235 
236  if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) {
237  reverseAPIKeys.append("dcBlock");
238  }
239  if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) {
240  reverseAPIKeys.append("iqCorrection");
241  }
242  if ((m_settings.m_fileRecordName != settings.m_fileRecordName) || force) {
243  reverseAPIKeys.append("fileRecordName");
244  }
245 
246  if ((m_settings.m_dcBlock != settings.m_dcBlock) || (m_settings.m_iqCorrection != settings.m_iqCorrection) || force)
247  {
249  qDebug("LocalInput::applySettings: corrections: DC block: %s IQ imbalance: %s",
250  settings.m_dcBlock ? "true" : "false",
251  settings.m_iqCorrection ? "true" : "false");
252  }
253 
254  mutexLocker.unlock();
255 
256  if (settings.m_useReverseAPI)
257  {
258  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
262  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
263  }
264 
265  m_settings = settings;
266  m_remoteAddress = remoteAddress;
267 
268  qDebug() << "LocalInput::applySettings: "
269  << " m_dcBlock: " << m_settings.m_dcBlock
270  << " m_iqCorrection: " << m_settings.m_iqCorrection
271  << " m_fileRecordName: " << m_settings.m_fileRecordName
272  << " m_remoteAddress: " << m_remoteAddress;
273 }
274 
276  SWGSDRangel::SWGDeviceState& response,
277  QString& errorMessage)
278 {
279  (void) errorMessage;
281  return 200;
282 }
283 
285  bool run,
286  SWGSDRangel::SWGDeviceState& response,
287  QString& errorMessage)
288 {
289  (void) errorMessage;
291  MsgStartStop *message = MsgStartStop::create(run);
292  m_inputMessageQueue.push(message);
293 
294  if (m_guiMessageQueue) // forward to GUI if any
295  {
296  MsgStartStop *msgToGUI = MsgStartStop::create(run);
297  m_guiMessageQueue->push(msgToGUI);
298  }
299 
300  return 200;
301 }
302 
305  QString& errorMessage)
306 {
307  (void) errorMessage;
309  response.getLocalInputSettings()->init();
311  return 200;
312 }
313 
315  bool force,
316  const QStringList& deviceSettingsKeys,
317  SWGSDRangel::SWGDeviceSettings& response, // query + response
318  QString& errorMessage)
319 {
320  (void) errorMessage;
321  LocalInputSettings settings = m_settings;
322 
323  if (deviceSettingsKeys.contains("dcBlock")) {
324  settings.m_dcBlock = response.getLocalInputSettings()->getDcBlock() != 0;
325  }
326  if (deviceSettingsKeys.contains("iqCorrection")) {
327  settings.m_iqCorrection = response.getLocalInputSettings()->getIqCorrection() != 0;
328  }
329  if (deviceSettingsKeys.contains("fileRecordName")) {
330  settings.m_fileRecordName = *response.getLocalInputSettings()->getFileRecordName();
331  }
332  if (deviceSettingsKeys.contains("useReverseAPI")) {
333  settings.m_useReverseAPI = response.getLocalInputSettings()->getUseReverseApi() != 0;
334  }
335  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
337  }
338  if (deviceSettingsKeys.contains("reverseAPIPort")) {
340  }
341  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
343  }
344 
347 
348  if (m_guiMessageQueue) // forward to GUI if any
349  {
350  MsgConfigureLocalInput *msgToGUI = MsgConfigureLocalInput::create(settings, force);
351  m_guiMessageQueue->push(msgToGUI);
352  }
353 
354  webapiFormatDeviceSettings(response, settings);
355  return 200;
356 }
357 
359 {
360  response.getLocalInputSettings()->setDcBlock(settings.m_dcBlock ? 1 : 0);
362 
363  if (response.getLocalInputSettings()->getFileRecordName()) {
364  *response.getLocalInputSettings()->getFileRecordName() = settings.m_fileRecordName;
365  } else {
366  response.getLocalInputSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
367  }
368 
369  response.getLocalInputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
370 
371  if (response.getLocalInputSettings()->getReverseApiAddress()) {
373  } else {
374  response.getLocalInputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
375  }
376 
379 }
380 
383  QString& errorMessage)
384 {
385  (void) errorMessage;
387  response.getLocalInputReport()->init();
388  webapiFormatDeviceReport(response);
389  return 200;
390 }
391 
393 {
396 }
397 
398 void LocalInput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const LocalInputSettings& settings, bool force)
399 {
401  swgDeviceSettings->setDirection(0); // single Rx
402  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
403  swgDeviceSettings->setDeviceHwType(new QString("LocalInput"));
405  SWGSDRangel::SWGLocalInputSettings *swgLocalInputSettings = swgDeviceSettings->getLocalInputSettings();
406 
407  // transfer data that has been modified. When force is on transfer all data except reverse API data
408 
409  if (deviceSettingsKeys.contains("dcBlock") || force) {
410  swgLocalInputSettings->setDcBlock(settings.m_dcBlock ? 1 : 0);
411  }
412  if (deviceSettingsKeys.contains("iqCorrection") || force) {
413  swgLocalInputSettings->setIqCorrection(settings.m_iqCorrection ? 1 : 0);
414  }
415  if (deviceSettingsKeys.contains("fileRecordName") || force) {
416  swgLocalInputSettings->setFileRecordName(new QString(settings.m_fileRecordName));
417  }
418 
419  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
420  .arg(settings.m_reverseAPIAddress)
421  .arg(settings.m_reverseAPIPort)
422  .arg(settings.m_reverseAPIDeviceIndex);
423  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
424  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
425 
426  QBuffer *buffer=new QBuffer();
427  buffer->open((QBuffer::ReadWrite));
428  buffer->write(swgDeviceSettings->asJson().toUtf8());
429  buffer->seek(0);
430 
431  // Always use PATCH to avoid passing reverse API settings
432  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
433 
434  delete swgDeviceSettings;
435 }
436 
438 {
440  swgDeviceSettings->setDirection(0); // single Rx
441  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
442  swgDeviceSettings->setDeviceHwType(new QString("LocalInput"));
443 
444  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
448  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
449  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
450 
451  QBuffer *buffer=new QBuffer();
452  buffer->open((QBuffer::ReadWrite));
453  buffer->write(swgDeviceSettings->asJson().toUtf8());
454  buffer->seek(0);
455 
456  if (start) {
457  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
458  } else {
459  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
460  }
461 
462  delete swgDeviceSettings;
463 }
464 
465 void LocalInput::networkManagerFinished(QNetworkReply *reply)
466 {
467  QNetworkReply::NetworkError replyError = reply->error();
468 
469  if (replyError)
470  {
471  qWarning() << "LocalInput::networkManagerFinished:"
472  << " error(" << (int) replyError
473  << "): " << replyError
474  << ": " << reply->errorString();
475  return;
476  }
477 
478  QString answer = reply->readAll();
479  answer.chop(1); // remove last \n
480  qDebug("LocalInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
481 }
QString m_remoteAddress
Definition: localinput.h:174
virtual quint64 getCenterFrequency() const
Center frequency exposed by the source.
Definition: localinput.cpp:145
QNetworkAccessManager * m_networkManager
Definition: localinput.h:177
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
static MsgStartStop * create(bool startStop)
Definition: localinput.h:90
void setLocalInputSettings(SWGLocalInputSettings *local_input_settings)
SWGLocalInputSettings * getLocalInputSettings()
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
Definition: localinput.cpp:392
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
Definition: localinput.cpp:381
void push(Message *message, bool emitSignal=true)
Push message onto queue.
DeviceAPI * m_deviceAPI
Definition: localinput.h:169
void stopDeviceEngine()
Stop the device engine corresponding to the stream type.
Definition: deviceapi.cpp:266
void setFileName(const QString &filename)
Definition: filerecord.cpp:59
uint getDeviceUID() const
Return the current device engine unique ID.
Definition: deviceapi.cpp:303
int m_sampleRate
Definition: localinput.h:173
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
virtual bool deserialize(const QByteArray &data)
Definition: localinput.cpp:94
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
Definition: localinput.cpp:275
SWGLocalInputReport * getLocalInputReport()
void startRecording()
Definition: filerecord.cpp:105
virtual QByteArray serialize() const
Definition: localinput.cpp:89
MessageQueue m_inputMessageQueue
Input queue to the source.
virtual QString asJson() override
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
virtual void setSampleRate(int sampleRate)
For when the source sample rate is set externally.
Definition: localinput.cpp:131
virtual ~LocalInput()
Definition: localinput.cpp:59
QNetworkRequest m_networkRequest
Definition: localinput.h:178
void setSampleRate(qint32 sample_rate)
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
Definition: localinput.cpp:284
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
virtual void setCenterFrequency(qint64 centerFrequency)
Definition: localinput.cpp:150
void setCenterFrequency(qint32 center_frequency)
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
Definition: localinput.cpp:73
void setOriginatorIndex(qint32 originator_index)
MessageQueue * getMessageQueueToGUI()
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 applySettings(const LocalInputSettings &settings, bool force=false)
Definition: localinput.cpp:229
LocalInputSettings m_settings
Definition: localinput.h:171
QString m_deviceDescription
Definition: localinput.h:175
int getDeviceSetIndex() const
Definition: deviceapi.h:131
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
void genUniqueFileName(uint deviceUID, int istream=-1)
Definition: filerecord.cpp:67
FileRecord * m_fileSink
File sink to record device I/Q output.
Definition: localinput.h:176
virtual bool start()
Definition: localinput.cpp:78
QByteArray serialize() const
void setReverseApiAddress(QString *reverse_api_address)
void setIqCorrection(qint32 iq_correction)
void stopRecording()
Definition: filerecord.cpp:117
void webapiReverseSendStartStop(bool start)
Definition: localinput.cpp:437
static bool match(const Message *message)
Definition: message.cpp:45
void removeAncillarySink(BasebandSampleSink *sink, unsigned int index=0)
Removes it.
Definition: deviceapi.cpp:100
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
Definition: localinput.cpp:314
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
static MsgReportSampleRateAndFrequency * create(int sampleRate, qint64 centerFrequency)
Definition: localinput.h:110
bool getStartStop() const
Definition: localinput.h:69
const LocalInputSettings & getSettings() const
Definition: localinput.h:46
virtual void setMessageQueueToGUI(MessageQueue *queue)
Definition: localinput.cpp:116
void setUseReverseApi(qint32 use_reverse_api)
void setReverseApiPort(qint32 reverse_api_port)
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
uint16_t m_reverseAPIDeviceIndex
void setLocalInputReport(SWGLocalInputReport *local_input_report)
QMutex m_mutex
Definition: localinput.h:170
void setFileRecordName(QString *file_record_name)
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const LocalInputSettings &settings, bool force)
Definition: localinput.cpp:398
virtual int getSampleRate() const
Sample rate exposed by the source.
Definition: localinput.cpp:126
virtual const char * getIdentifier() const
Definition: message.cpp:35
virtual const QString & getDeviceDescription() const
Definition: localinput.cpp:121
virtual bool handleMessage(const Message &message)
Definition: localinput.cpp:164
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const LocalInputSettings &settings)
Definition: localinput.cpp:358
void networkManagerFinished(QNetworkReply *reply)
Definition: localinput.cpp:465
virtual void destroy()
Definition: localinput.cpp:68
virtual void stop()
Definition: localinput.cpp:84
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
Definition: localinput.cpp:303
void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection, int streamIndex=0)
Configure current device engine DSP corrections (Rx)
Definition: deviceapi.cpp:355
void setDirection(qint32 direction)
bool getStartStop() const
Definition: localinput.h:88
void setDeviceHwType(QString *device_hw_type)
bool deserialize(const QByteArray &data)
static MsgConfigureLocalInput * create(const LocalInputSettings &settings, bool force=false)
Definition: localinput.h:49
qint64 m_centerFrequency
Definition: localinput.h:172