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.
soapysdrinput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2018 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 <QDebug>
19 #include <QNetworkReply>
20 #include <QBuffer>
21 
22 #include "util/simpleserializer.h"
23 
24 #include "SWGDeviceSettings.h"
26 #include "SWGDeviceState.h"
27 #include "SWGDeviceReport.h"
28 #include "SWGSoapySDRReport.h"
29 
30 #include "device/deviceapi.h"
31 #include "dsp/dspcommands.h"
32 #include "dsp/filerecord.h"
33 #include "dsp/dspengine.h"
35 
36 #include "soapysdrinputthread.h"
37 #include "soapysdrinput.h"
38 
43 
45  m_deviceAPI(deviceAPI),
46  m_settings(),
47  m_deviceDescription("SoapySDRInput"),
48  m_running(false),
49  m_thread(0)
50 {
51  openDevice();
52  initGainSettings(m_settings);
53  initTunableElementsSettings(m_settings);
54  initStreamArgSettings(m_settings);
55  initDeviceArgSettings(m_settings);
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 
70  if (m_running) {
71  stop();
72  }
73 
75  delete m_fileSink;
76 
77  closeDevice();
78 }
79 
81 {
82  delete this;
83 }
84 
86 {
87  if (!m_sampleFifo.setSize(96000 * 4))
88  {
89  qCritical("SoapySDRInput::openDevice: could not allocate SampleFifo");
90  return false;
91  }
92  else
93  {
94  qDebug("SoapySDRInput::openDevice: allocated SampleFifo");
95  }
96 
97  // look for Rx buddies and get reference to the device object
98  if (m_deviceAPI->getSourceBuddies().size() > 0) // look source sibling first
99  {
100  qDebug("SoapySDRInput::openDevice: look in Rx buddies");
101 
102  DeviceAPI *sourceBuddy = m_deviceAPI->getSourceBuddies()[0];
103  DeviceSoapySDRShared *deviceSoapySDRShared = (DeviceSoapySDRShared*) sourceBuddy->getBuddySharedPtr();
104 
105  if (deviceSoapySDRShared == 0)
106  {
107  qCritical("SoapySDRInput::openDevice: the source buddy shared pointer is null");
108  return false;
109  }
110 
111  SoapySDR::Device *device = deviceSoapySDRShared->m_device;
112 
113  if (device == 0)
114  {
115  qCritical("SoapySDRInput::openDevice: cannot get device pointer from Rx buddy");
116  return false;
117  }
118 
119  m_deviceShared.m_device = device;
120  m_deviceShared.m_deviceParams = deviceSoapySDRShared->m_deviceParams;
121  }
122  // look for Tx buddies and get reference to the device object
123  else if (m_deviceAPI->getSinkBuddies().size() > 0) // then sink
124  {
125  qDebug("SoapySDRInput::openDevice: look in Tx buddies");
126 
127  DeviceAPI *sinkBuddy = m_deviceAPI->getSinkBuddies()[0];
128  DeviceSoapySDRShared *deviceSoapySDRShared = (DeviceSoapySDRShared*) sinkBuddy->getBuddySharedPtr();
129 
130  if (deviceSoapySDRShared == 0)
131  {
132  qCritical("SoapySDRInput::openDevice: the sink buddy shared pointer is null");
133  return false;
134  }
135 
136  SoapySDR::Device *device = deviceSoapySDRShared->m_device;
137 
138  if (device == 0)
139  {
140  qCritical("SoapySDRInput::openDevice: cannot get device pointer from Tx buddy");
141  return false;
142  }
143 
144  m_deviceShared.m_device = device;
145  m_deviceShared.m_deviceParams = deviceSoapySDRShared->m_deviceParams;
146  }
147  // There are no buddies then create the first SoapySDR device
148  else
149  {
150  qDebug("SoapySDRInput::openDevice: open device here");
151  DeviceSoapySDR& deviceSoapySDR = DeviceSoapySDR::instance();
153 
155  {
156  qCritical("BladeRF2Input::openDevice: cannot open BladeRF2 device");
157  return false;
158  }
159 
161  }
162 
163  m_deviceShared.m_channel = m_deviceAPI->getDeviceItemIndex(); // publicly allocate channel
164  m_deviceShared.m_source = this;
165  m_deviceAPI->setBuddySharedPtr(&m_deviceShared); // propagate common parameters to API
166  return true;
167 }
168 
170 {
171  if (m_deviceShared.m_device == 0) { // was never open
172  return;
173  }
174 
175  if (m_running) {
176  stop();
177  }
178 
179  if (m_thread) { // stills own the thread => transfer to a buddy
181  }
182 
183  m_deviceShared.m_channel = -1; // publicly release channel
185 
186  // No buddies so effectively close the device and delete parameters
187 
188  if ((m_deviceAPI->getSinkBuddies().size() == 0) && (m_deviceAPI->getSourceBuddies().size() == 0))
189  {
192  DeviceSoapySDR& deviceSoapySDR = DeviceSoapySDR::instance();
193  deviceSoapySDR.closeSoapySdr(m_deviceShared.m_device);
195  }
196 }
197 
199 {
201 
202  if (channelSettings && (channelSettings->m_frequencySettings.size() > 0))
203  {
204  DeviceSoapySDRParams::FrequencySetting freqSettings = channelSettings->m_frequencySettings[0];
205  SoapySDR::RangeList rangeList = freqSettings.m_ranges;
206 
207  if (rangeList.size() > 0)
208  {
209  SoapySDR::Range range = rangeList[0];
210  min = range.minimum();
211  max = range.maximum();
212  }
213  else
214  {
215  min = 0;
216  max = 0;
217  }
218  }
219  else
220  {
221  min = 0;
222  max = 0;
223  }
224 }
225 
227 {
229 
230  if (channelSettings)
231  {
232  min = channelSettings->m_gainRange.minimum();
233  max = channelSettings->m_gainRange.maximum();
234  }
235  else
236  {
237  min = 0;
238  max = 0;
239  }
240 }
241 
243 {
245  return channelSettings->m_hasAGC;
246 }
247 
248 const std::vector<std::string>& SoapySDRInput::getAntennas()
249 {
251  return channelSettings->m_antennas;
252 }
253 
254 const SoapySDR::RangeList& SoapySDRInput::getRateRanges()
255 {
257  return channelSettings->m_ratesRanges;
258 }
259 
260 const SoapySDR::RangeList& SoapySDRInput::getBandwidthRanges()
261 {
263  return channelSettings->m_bandwidthsRanges;
264 }
265 
266 int SoapySDRInput::getAntennaIndex(const std::string& antenna)
267 {
268  const std::vector<std::string>& antennaList = getAntennas();
269  std::vector<std::string>::const_iterator it = std::find(antennaList.begin(), antennaList.end(), antenna);
270 
271  if (it == antennaList.end()) {
272  return -1;
273  } else {
274  return it - antennaList.begin();
275  }
276 }
277 
278 const std::vector<DeviceSoapySDRParams::FrequencySetting>& SoapySDRInput::getTunableElements()
279 {
281  return channelSettings->m_frequencySettings;
282 }
283 
284 const std::vector<DeviceSoapySDRParams::GainSetting>& SoapySDRInput::getIndividualGainsRanges()
285 {
287  return channelSettings->m_gainSettings;
288 }
289 
290 const SoapySDR::ArgInfoList& SoapySDRInput::getStreamArgInfoList()
291 {
293  return channelSettings->m_streamSettingsArgs;
294 }
295 
296 const SoapySDR::ArgInfoList& SoapySDRInput::getDeviceArgInfoList()
297 {
299 }
300 
302 {
304  settings.m_individualGains.clear();
305  settings.m_globalGain = 0;
306 
307  for (const auto &it : channelSettings->m_gainSettings) {
308  settings.m_individualGains[QString(it.m_name.c_str())] = 0.0;
309  }
310 
312 }
313 
315 {
317  settings.m_tunableElements.clear();
318  bool first = true;
319 
320  for (const auto &it : channelSettings->m_frequencySettings)
321  {
322  if (first)
323  {
324  first = false;
325  continue;
326  }
327 
328  settings.m_tunableElements[QString(it.m_name.c_str())] = 0.0;
329  }
330 
332 }
333 
335 {
337  settings.m_streamArgSettings.clear();
338 
339  for (const auto &it : channelSettings->m_streamSettingsArgs)
340  {
341  if (it.type == SoapySDR::ArgInfo::BOOL) {
342  settings.m_streamArgSettings[QString(it.key.c_str())] = QVariant(it.value == "true");
343  } else if (it.type == SoapySDR::ArgInfo::INT) {
344  settings.m_streamArgSettings[QString(it.key.c_str())] = QVariant(atoi(it.value.c_str()));
345  } else if (it.type == SoapySDR::ArgInfo::FLOAT) {
346  settings.m_streamArgSettings[QString(it.key.c_str())] = QVariant(atof(it.value.c_str()));
347  } else if (it.type == SoapySDR::ArgInfo::STRING) {
348  settings.m_streamArgSettings[QString(it.key.c_str())] = QVariant(it.value.c_str());
349  }
350  }
351 }
352 
354 {
355  settings.m_deviceArgSettings.clear();
356 
357  for (const auto &it : m_deviceShared.m_deviceParams->getDeviceArgs())
358  {
359  if (it.type == SoapySDR::ArgInfo::BOOL) {
360  settings.m_deviceArgSettings[QString(it.key.c_str())] = QVariant(it.value == "true");
361  } else if (it.type == SoapySDR::ArgInfo::INT) {
362  settings.m_deviceArgSettings[QString(it.key.c_str())] = QVariant(atoi(it.value.c_str()));
363  } else if (it.type == SoapySDR::ArgInfo::FLOAT) {
364  settings.m_deviceArgSettings[QString(it.key.c_str())] = QVariant(atof(it.value.c_str()));
365  } else if (it.type == SoapySDR::ArgInfo::STRING) {
366  settings.m_deviceArgSettings[QString(it.key.c_str())] = QVariant(it.value.c_str());
367  }
368  }
369 }
370 
372 {
374  return channelSettings->m_hasDCAutoCorrection;
375 }
376 
378 {
380  return channelSettings->m_hasDCOffsetValue;
381 }
382 
384 {
386  return channelSettings->m_hasIQBalanceValue;
387 }
388 
390 {
391  applySettings(m_settings, true);
392 }
393 
395 {
396  if (m_thread == 0) // this does not own the thread
397  {
398  SoapySDRInputThread *soapySDRInputThread = 0;
399 
400  // find a buddy that has allocated the thread
401  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
402  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
403 
404  for (; it != sourceBuddies.end(); ++it)
405  {
406  SoapySDRInput *buddySource = ((DeviceSoapySDRShared*) (*it)->getBuddySharedPtr())->m_source;
407 
408  if (buddySource)
409  {
410  soapySDRInputThread = buddySource->getThread();
411 
412  if (soapySDRInputThread) {
413  break;
414  }
415  }
416  }
417 
418  return soapySDRInputThread;
419  }
420  else
421  {
422  return m_thread; // own thread
423  }
424 }
425 
427 {
428  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
429  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
430 
431  for (; it != sourceBuddies.end(); ++it)
432  {
433  SoapySDRInput *buddySource = ((DeviceSoapySDRShared*) (*it)->getBuddySharedPtr())->m_source;
434 
435  if (buddySource)
436  {
437  buddySource->setThread(m_thread);
438  m_thread = 0; // zero for others
439  }
440  }
441 }
442 
444 {
445  // There is a single thread per physical device (Rx side). This thread is unique and referenced by a unique
446  // buddy in the group of source buddies associated with this physical device.
447  //
448  // This start method is responsible for managing the thread and number of channels when the streaming of a Rx channel is started
449  //
450  // It checks the following conditions
451  // - the thread is allocated or not (by itself or one of its buddies). If it is it grabs the thread pointer.
452  // - the requested channel is the first (0) or the following
453  //
454  // There are two possible working modes:
455  // - Single Input (SI) with only one channel streaming. This HAS to be channel 0.
456  // - Multiple Input (MI) with two or more channels. It MUST be in this configuration if any channel other than 0
457  // is used irrespective of what you actually do with samples coming from ignored channels.
458  // For example When we will run with only channel 2 streaming from the client perspective the channels 0 and 1 will actually
459  // be enabled and streaming but its samples will just be disregarded.
460  // This means that all channels up to the highest in index being used are activated.
461  //
462  // It manages the transition form SI where only one channel (the first or channel 0) should be running to the
463  // Multiple Input (MI) if the requested channel is 1 or more. More generally it checks if the requested channel is within the current
464  // channel range allocated in the thread or past it. To perform the transition it stops the thread, deletes it and creates a new one.
465  // It marks the thread as needing start.
466  //
467  // If the requested channel is within the thread channel range (this thread being already allocated) it simply adds its FIFO reference
468  // so that the samples are fed to the FIFO and leaves the thread unchanged (no stop, no delete/new)
469  //
470  // If there is no thread allocated it creates a new one with a number of channels that fits the requested channel. That is
471  // 1 if channel 0 is requested (SI mode) and 3 if channel 2 is requested (MI mode). It marks the thread as needing start.
472  //
473  // Eventually it registers the FIFO in the thread. If the thread has to be started it enables the channels up to the number of channels
474  // allocated in the thread and starts the thread.
475  //
476  // Note: this is quite similar to the BladeRF2 start handling. The main difference is that the channel allocation (enabling) process is
477  // done in the thread object.
478 
480  {
481  qDebug("SoapySDRInput::start: no device object");
482  return false;
483  }
484 
485  int requestedChannel = m_deviceAPI->getDeviceItemIndex();
486  SoapySDRInputThread *soapySDRInputThread = findThread();
487  bool needsStart = false;
488 
489  if (soapySDRInputThread) // if thread is already allocated
490  {
491  qDebug("SoapySDRInput::start: thread is already allocated");
492 
493  int nbOriginalChannels = soapySDRInputThread->getNbChannels();
494 
495  if (requestedChannel+1 > nbOriginalChannels) // expansion by deleting and re-creating the thread
496  {
497  qDebug("SoapySDRInput::start: expand channels. Re-allocate thread and take ownership");
498 
499  SampleSinkFifo **fifos = new SampleSinkFifo*[nbOriginalChannels];
500  unsigned int *log2Decims = new unsigned int[nbOriginalChannels];
501  int *fcPoss = new int[nbOriginalChannels];
502 
503  for (int i = 0; i < nbOriginalChannels; i++) // save original FIFO references and data
504  {
505  fifos[i] = soapySDRInputThread->getFifo(i);
506  log2Decims[i] = soapySDRInputThread->getLog2Decimation(i);
507  fcPoss[i] = soapySDRInputThread->getFcPos(i);
508  }
509 
510  soapySDRInputThread->stopWork();
511  delete soapySDRInputThread;
512  soapySDRInputThread = new SoapySDRInputThread(m_deviceShared.m_device, requestedChannel+1);
513  m_thread = soapySDRInputThread; // take ownership
514 
515  for (int i = 0; i < nbOriginalChannels; i++) // restore original FIFO references
516  {
517  soapySDRInputThread->setFifo(i, fifos[i]);
518  soapySDRInputThread->setLog2Decimation(i, log2Decims[i]);
519  soapySDRInputThread->setFcPos(i, fcPoss[i]);
520  }
521 
522  // remove old thread address from buddies (reset in all buddies). The address being held only in the owning source.
523  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
524  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
525 
526  for (; it != sourceBuddies.end(); ++it) {
527  ((DeviceSoapySDRShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0);
528  }
529 
530  delete[] fcPoss;
531  delete[] log2Decims;
532  delete[] fifos;
533 
534  needsStart = true;
535  }
536  else
537  {
538  qDebug("SoapySDRInput::start: keep buddy thread");
539  }
540  }
541  else // first allocation
542  {
543  qDebug("SoapySDRInput::start: allocate thread and take ownership");
544  soapySDRInputThread = new SoapySDRInputThread(m_deviceShared.m_device, requestedChannel+1);
545  m_thread = soapySDRInputThread; // take ownership
546  needsStart = true;
547  }
548 
549  soapySDRInputThread->setFifo(requestedChannel, &m_sampleFifo);
550  soapySDRInputThread->setLog2Decimation(requestedChannel, m_settings.m_log2Decim);
551  soapySDRInputThread->setFcPos(requestedChannel, (int) m_settings.m_fcPos);
552 
553  if (needsStart)
554  {
555  qDebug("SoapySDRInput::start: (re)sart buddy thread");
556  soapySDRInputThread->setSampleRate(m_settings.m_devSampleRate);
557  soapySDRInputThread->startWork();
558  }
559 
560  qDebug("SoapySDRInput::start: started");
561  m_running = true;
562 
563  return true;
564 }
565 
567 {
568  // This stop method is responsible for managing the thread and channel disabling when the streaming of
569  // a Rx channel is stopped
570  //
571  // If the thread is currently managing only one channel (SI mode). The thread can be just stopped and deleted.
572  // Then the channel is closed (disabled).
573  //
574  // If the thread is currently managing many channels (MI mode) and we are removing the last channel. The transition
575  // or reduction of MI size is handled by stopping the thread, deleting it and creating a new one
576  // with the maximum number of channels needed if (and only if) there is still a channel active.
577  //
578  // If the thread is currently managing many channels (MI mode) but the channel being stopped is not the last
579  // channel then the FIFO reference is simply removed from the thread so that it will not stream into this FIFO
580  // anymore. In this case the channel is not closed (this is managed in the thread object) so that other channels
581  // can continue with the same configuration. The device continues streaming on this channel but the samples are simply
582  // dropped (by removing FIFO reference).
583  //
584  // Note: this is quite similar to the BladeRF2 stop handling. The main difference is that the channel allocation (enabling) process is
585  // done in the thread object.
586 
587  if (!m_running) {
588  return;
589  }
590 
591  int requestedChannel = m_deviceAPI->getDeviceItemIndex();
592  SoapySDRInputThread *soapySDRInputThread = findThread();
593 
594  if (soapySDRInputThread == 0) { // no thread allocated
595  return;
596  }
597 
598  int nbOriginalChannels = soapySDRInputThread->getNbChannels();
599 
600  if (nbOriginalChannels == 1) // SI mode => just stop and delete the thread
601  {
602  qDebug("SoapySDRInput::stop: SI mode. Just stop and delete the thread");
603  soapySDRInputThread->stopWork();
604  delete soapySDRInputThread;
605  m_thread = 0;
606 
607  // remove old thread address from buddies (reset in all buddies)
608  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
609  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
610 
611  for (; it != sourceBuddies.end(); ++it) {
612  ((DeviceSoapySDRShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0);
613  }
614  }
615  else if (requestedChannel == nbOriginalChannels - 1) // remove last MI channel => reduce by deleting and re-creating the thread
616  {
617  qDebug("SoapySDRInput::stop: MI mode. Reduce by deleting and re-creating the thread");
618  soapySDRInputThread->stopWork();
619  SampleSinkFifo **fifos = new SampleSinkFifo*[nbOriginalChannels-1];
620  unsigned int *log2Decims = new unsigned int[nbOriginalChannels-1];
621  int *fcPoss = new int[nbOriginalChannels-1];
622  int highestActiveChannelIndex = -1;
623 
624  for (int i = 0; i < nbOriginalChannels-1; i++) // save original FIFO references and get the channel with highest index
625  {
626  fifos[i] = soapySDRInputThread->getFifo(i);
627 
628  if ((soapySDRInputThread->getFifo(i) != 0) && (i > highestActiveChannelIndex)) {
629  highestActiveChannelIndex = i;
630  }
631 
632  log2Decims[i] = soapySDRInputThread->getLog2Decimation(i);
633  fcPoss[i] = soapySDRInputThread->getFcPos(i);
634  }
635 
636  delete soapySDRInputThread;
637  m_thread = 0;
638 
639  if (highestActiveChannelIndex >= 0) // there is at least one channel still active
640  {
641  soapySDRInputThread = new SoapySDRInputThread(m_deviceShared.m_device, highestActiveChannelIndex+1);
642  m_thread = soapySDRInputThread; // take ownership
643 
644  for (int i = 0; i < highestActiveChannelIndex; i++) // restore original FIFO references
645  {
646  soapySDRInputThread->setFifo(i, fifos[i]);
647  soapySDRInputThread->setLog2Decimation(i, log2Decims[i]);
648  soapySDRInputThread->setFcPos(i, fcPoss[i]);
649  }
650  }
651  else
652  {
653  qDebug("SoapySDRInput::stop: do not re-create thread as there are no more FIFOs active");
654  }
655 
656  // remove old thread address from buddies (reset in all buddies). The address being held only in the owning source.
657  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
658  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
659 
660  for (; it != sourceBuddies.end(); ++it) {
661  ((DeviceSoapySDRShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0);
662  }
663 
664  if (highestActiveChannelIndex >= 0)
665  {
666  qDebug("SoapySDRInput::stop: restarting the thread");
667  soapySDRInputThread->startWork();
668  }
669 
670  delete[] fcPoss;
671  delete[] log2Decims;
672  delete[] fifos;
673  }
674  else // remove channel from existing thread
675  {
676  qDebug("SoapySDRInput::stop: MI mode. Not changing MI configuration. Just remove FIFO reference");
677  soapySDRInputThread->setFifo(requestedChannel, 0); // remove FIFO
678  }
679 
680  m_running = false;
681 }
682 
683 QByteArray SoapySDRInput::serialize() const
684 {
685  SimpleSerializer s(1);
686  return s.final();
687 }
688 
689 bool SoapySDRInput::deserialize(const QByteArray& data)
690 {
691  (void) data;
692  return false;
693 }
694 
696 {
697  return m_deviceDescription;
698 }
699 
701 {
702  int rate = m_settings.m_devSampleRate;
703  return (rate / (1<<m_settings.m_log2Decim));
704 }
705 
707 {
709 }
710 
711 void SoapySDRInput::setCenterFrequency(qint64 centerFrequency)
712 {
714  settings.m_centerFrequency = centerFrequency;
715 
717  m_inputMessageQueue.push(message);
718 
719  if (m_guiMessageQueue)
720  {
721  MsgConfigureSoapySDRInput* messageToGUI = MsgConfigureSoapySDRInput::create(settings, false);
722  m_guiMessageQueue->push(messageToGUI);
723  }
724 }
725 
726 bool SoapySDRInput::setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths)
727 {
728  qint64 df = ((qint64)freq_hz * loPpmTenths) / 10000000LL;
729  freq_hz += df;
730 
731  try
732  {
733  dev->setFrequency(SOAPY_SDR_RX,
734  requestedChannel,
736  freq_hz);
737  qDebug("SoapySDRInput::setDeviceCenterFrequency: setFrequency(%llu)", freq_hz);
738  return true;
739  }
740  catch (const std::exception &ex)
741  {
742  qCritical("SoapySDRInput::applySettings: could not set frequency: %llu: %s", freq_hz, ex.what());
743  return false;
744  }
745 }
746 
747 void SoapySDRInput::updateGains(SoapySDR::Device *dev, int requestedChannel, SoapySDRInputSettings& settings)
748 {
749  if (dev == 0) {
750  return;
751  }
752 
753  try
754  {
755  settings.m_globalGain = round(dev->getGain(SOAPY_SDR_RX, requestedChannel));
756 
757  for (const auto &name : settings.m_individualGains.keys()) {
758  settings.m_individualGains[name] = dev->getGain(SOAPY_SDR_RX, requestedChannel, name.toStdString());
759  }
760  }
761  catch (const std::exception &ex)
762  {
763  qCritical("SoapySDRInput::updateGains: caught exception: %s", ex.what());
764  }
765 }
766 
767 void SoapySDRInput::updateTunableElements(SoapySDR::Device *dev, int requestedChannel, SoapySDRInputSettings& settings)
768 {
769  if (dev == 0) {
770  return;
771  }
772 
773  try
774  {
775  for (const auto &name : settings.m_tunableElements.keys()) {
776  settings.m_tunableElements[name] = dev->getFrequency(SOAPY_SDR_RX, requestedChannel, name.toStdString());
777  }
778  }
779  catch (const std::exception &ex)
780  {
781  qCritical("SoapySDRInput::updateTunableElements: caught exception: %s", ex.what());
782  }
783 }
784 
786 {
788  {
790  qDebug() << "SoapySDRInput::handleMessage: MsgConfigureSoapySDRInput";
791 
792  if (!applySettings(conf.getSettings(), conf.getForce())) {
793  qDebug("SoapySDRInput::handleMessage: MsgConfigureSoapySDRInput config error");
794  }
795 
796  return true;
797  }
798  else if (MsgFileRecord::match(message))
799  {
800  MsgFileRecord& conf = (MsgFileRecord&) message;
801  qDebug() << "SoapySDRInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
802 
803  if (conf.getStartStop())
804  {
805  if (m_settings.m_fileRecordName.size() != 0) {
807  } else {
809  }
810 
812  }
813  else
814  {
816  }
817 
818  return true;
819  }
820  else if (MsgStartStop::match(message))
821  {
822  MsgStartStop& cmd = (MsgStartStop&) message;
823  qDebug() << "SoapySDRInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
824 
825  if (cmd.getStartStop())
826  {
828  {
830  }
831  }
832  else
833  {
835  }
836 
839  }
840 
841  return true;
842  }
844  {
845  int requestedChannel = m_deviceAPI->getDeviceItemIndex();
848  settings.m_fcPos = (SoapySDRInputSettings::fcPos_t) report.getFcPos();
849  //bool fromRxBuddy = report.getRxElseTx();
850 
851  double centerFrequency = m_deviceShared.m_device->getFrequency(
852  SOAPY_SDR_RX,
853  requestedChannel,
855 
856  settings.m_centerFrequency = round(centerFrequency/1000.0) * 1000;
857  settings.m_devSampleRate = round(m_deviceShared.m_device->getSampleRate(SOAPY_SDR_RX, requestedChannel));
858  settings.m_bandwidth = round(m_deviceShared.m_device->getBandwidth(SOAPY_SDR_RX, requestedChannel));
859 
860  SoapySDRInputThread *inputThread = findThread();
861 
862  if (inputThread)
863  {
864  inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos);
865  }
866 
867  m_settings = settings;
868 
869  // propagate settings to GUI if any
870  if (getMessageQueueToGUI())
871  {
873  getMessageQueueToGUI()->push(reportToGUI);
874  }
875 
876  return true;
877  }
879  {
881  QMap<QString, QVariant> deviceArgSettings = report.getDeviceArgSettings();
882 
883  for (const auto &oname : m_settings.m_deviceArgSettings.keys())
884  {
885  auto nvalue = deviceArgSettings.find(oname);
886 
887  if (nvalue != deviceArgSettings.end() && (m_settings.m_deviceArgSettings[oname] != *nvalue))
888  {
889  m_settings.m_deviceArgSettings[oname] = *nvalue;
890  qDebug("SoapySDRInput::handleMessage: MsgReportDeviceArgsChange: device argument %s set to %s",
891  oname.toStdString().c_str(), nvalue->toString().toStdString().c_str());
892  }
893  }
894 
895  // propagate settings to GUI if any
896  if (getMessageQueueToGUI())
897  {
900  getMessageQueueToGUI()->push(reportToGUI);
901  }
902 
903  return true;
904  }
905  else
906  {
907  return false;
908  }
909 }
910 
911 bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool force)
912 {
913  bool forwardChangeOwnDSP = false;
914  bool forwardChangeToBuddies = false;
915  bool globalGainChanged = false;
916  bool individualGainsChanged = false;
917  bool deviceArgsChanged = false;
918  QList<QString> reverseAPIKeys;
919 
920  SoapySDR::Device *dev = m_deviceShared.m_device;
921  SoapySDRInputThread *inputThread = findThread();
922  int requestedChannel = m_deviceAPI->getDeviceItemIndex();
923  qint64 xlatedDeviceCenterFrequency = settings.m_centerFrequency;
924  xlatedDeviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0;
925  xlatedDeviceCenterFrequency = xlatedDeviceCenterFrequency < 0 ? 0 : xlatedDeviceCenterFrequency;
926 
927  if ((m_settings.m_softDCCorrection != settings.m_softDCCorrection) || force) {
928  reverseAPIKeys.append("softDCCorrection");
929  }
930  if ((m_settings.m_softIQCorrection != settings.m_softIQCorrection) || force) {
931  reverseAPIKeys.append("softIQCorrection");
932  }
933 
935  (m_settings.m_softIQCorrection != settings.m_softIQCorrection) || force)
936  {
938  }
939 
940  if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
941  {
942  reverseAPIKeys.append("devSampleRate");
943  forwardChangeOwnDSP = true;
944  forwardChangeToBuddies = true;
945 
946  if (dev != 0)
947  {
948  try
949  {
950  dev->setSampleRate(SOAPY_SDR_RX, requestedChannel, settings.m_devSampleRate);
951  qDebug() << "SoapySDRInput::applySettings: setSampleRate OK: " << settings.m_devSampleRate;
952 
953  if (inputThread)
954  {
955  bool wasRunning = inputThread->isRunning();
956  inputThread->stopWork();
957  inputThread->setSampleRate(settings.m_devSampleRate);
958 
959  if (wasRunning) {
960  inputThread->startWork();
961  }
962  }
963  }
964  catch (const std::exception &ex)
965  {
966  qCritical("SoapySDRInput::applySettings: could not set sample rate: %d: %s",
967  settings.m_devSampleRate, ex.what());
968  }
969  }
970  }
971 
972  if ((m_settings.m_fcPos != settings.m_fcPos) || force)
973  {
974  reverseAPIKeys.append("fcPos");
975 
976  if (inputThread != 0)
977  {
978  inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos);
979  qDebug() << "SoapySDRInput::applySettings: set fc pos (enum) to " << (int) settings.m_fcPos;
980  }
981  }
982 
983  if ((m_settings.m_log2Decim != settings.m_log2Decim) || force)
984  {
985  reverseAPIKeys.append("log2Decim");
986  forwardChangeOwnDSP = true;
987  SoapySDRInputThread *inputThread = findThread();
988 
989  if (inputThread != 0)
990  {
991  inputThread->setLog2Decimation(requestedChannel, settings.m_log2Decim);
992  qDebug() << "SoapySDRInput::applySettings: set decimation to " << (1<<settings.m_log2Decim);
993  }
994  }
995 
996  if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) {
997  reverseAPIKeys.append("centerFrequency");
998  }
999  if ((m_settings.m_transverterMode != settings.m_transverterMode) || force) {
1000  reverseAPIKeys.append("transverterMode");
1001  }
1003  reverseAPIKeys.append("transverterDeltaFrequency");
1004  }
1005  if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force) {
1006  reverseAPIKeys.append("LOppmTenths");
1007  }
1008 
1012  || (m_settings.m_LOppmTenths != settings.m_LOppmTenths)
1013  || (m_settings.m_devSampleRate != settings.m_devSampleRate)
1014  || (m_settings.m_fcPos != settings.m_fcPos)
1015  || (m_settings.m_log2Decim != settings.m_log2Decim) || force)
1016  {
1017  qint64 deviceCenterFrequency = DeviceSampleSource::calculateDeviceCenterFrequency(
1018  xlatedDeviceCenterFrequency,
1019  0,
1020  settings.m_log2Decim,
1022  settings.m_devSampleRate,
1023  DeviceSampleSource::FrequencyShiftScheme::FSHIFT_STD,
1024  false);
1025 
1026  forwardChangeOwnDSP = true;
1027  forwardChangeToBuddies = true;
1028 
1029  if (dev != 0) {
1030  setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency, settings.m_LOppmTenths);
1031  }
1032  }
1033 
1034  if ((m_settings.m_antenna != settings.m_antenna) || force)
1035  {
1036  reverseAPIKeys.append("antenna");
1037 
1038  if (dev != 0)
1039  {
1040  try
1041  {
1042  dev->setAntenna(SOAPY_SDR_RX, requestedChannel, settings.m_antenna.toStdString());
1043  qDebug("SoapySDRInput::applySettings: set antenna to %s", settings.m_antenna.toStdString().c_str());
1044  }
1045  catch (const std::exception &ex)
1046  {
1047  qCritical("SoapySDRInput::applySettings: cannot set antenna to %s: %s",
1048  settings.m_antenna.toStdString().c_str(), ex.what());
1049  }
1050  }
1051  }
1052 
1053  if ((m_settings.m_bandwidth != settings.m_bandwidth) || force)
1054  {
1055  reverseAPIKeys.append("bandwidth");
1056  forwardChangeToBuddies = true;
1057 
1058  if (dev != 0)
1059  {
1060  try
1061  {
1062  dev->setBandwidth(SOAPY_SDR_RX, requestedChannel, settings.m_bandwidth);
1063  qDebug("SoapySDRInput::applySettings: bandwidth set to %u", settings.m_bandwidth);
1064  }
1065  catch (const std::exception &ex)
1066  {
1067  qCritical("SoapySDRInput::applySettings: cannot set bandwidth to %u: %s",
1068  settings.m_bandwidth, ex.what());
1069  }
1070  }
1071  }
1072 
1073  for (const auto &oname : m_settings.m_tunableElements.keys())
1074  {
1075  auto nvalue = settings.m_tunableElements.find(oname);
1076 
1077  if (nvalue != settings.m_tunableElements.end() && ((m_settings.m_tunableElements[oname] != *nvalue) ||force))
1078  {
1079  if (dev != 0)
1080  {
1081  try
1082  {
1083  dev->setFrequency(SOAPY_SDR_RX, requestedChannel, oname.toStdString(), *nvalue);
1084  qDebug("SoapySDRInput::applySettings: tunable element %s frequency set to %lf",
1085  oname.toStdString().c_str(), *nvalue);
1086  }
1087  catch (const std::exception &ex)
1088  {
1089  qCritical("SoapySDRInput::applySettings: cannot set tunable element %s to %lf: %s",
1090  oname.toStdString().c_str(), *nvalue, ex.what());
1091  }
1092  }
1093 
1094  m_settings.m_tunableElements[oname] = *nvalue;
1095  }
1096  }
1097 
1098  if ((m_settings.m_globalGain != settings.m_globalGain) || force)
1099  {
1100  reverseAPIKeys.append("globalGain");
1101 
1102  if (dev != 0)
1103  {
1104  try
1105  {
1106  dev->setGain(SOAPY_SDR_RX, requestedChannel, settings.m_globalGain);
1107  qDebug("SoapySDRInput::applySettings: set global gain to %d", settings.m_globalGain);
1108  globalGainChanged = true;
1109  }
1110  catch (const std::exception &ex)
1111  {
1112  qCritical("SoapySDRInput::applySettings: cannot set global gain to %d: %s",
1113  settings.m_globalGain, ex.what());
1114  }
1115  }
1116  }
1117 
1118  for (const auto &oname : m_settings.m_individualGains.keys())
1119  {
1120  auto nvalue = settings.m_individualGains.find(oname);
1121 
1122  if (nvalue != settings.m_individualGains.end() && ((m_settings.m_individualGains[oname] != *nvalue) || force))
1123  {
1124  if (dev != 0)
1125  {
1126  try
1127  {
1128  dev->setGain(SOAPY_SDR_RX, requestedChannel, oname.toStdString(), *nvalue);
1129  qDebug("SoapySDRInput::applySettings: individual gain %s set to %lf",
1130  oname.toStdString().c_str(), *nvalue);
1131  individualGainsChanged = true;
1132  }
1133  catch (const std::exception &ex)
1134  {
1135  qCritical("SoapySDRInput::applySettings: cannot set individual gain %s to %lf: %s",
1136  oname.toStdString().c_str(), *nvalue, ex.what());
1137  }
1138  }
1139 
1140  m_settings.m_individualGains[oname] = *nvalue;
1141  }
1142  }
1143 
1144  if ((m_settings.m_autoGain != settings.m_autoGain) || force)
1145  {
1146  reverseAPIKeys.append("autoGain");
1147 
1148  if (dev != 0)
1149  {
1150  try
1151  {
1152  dev->setGainMode(SOAPY_SDR_RX, requestedChannel, settings.m_autoGain);
1153  qDebug("SoapySDRInput::applySettings: %s AGC", settings.m_autoGain ? "set" : "unset");
1154  }
1155  catch (const std::exception &ex)
1156  {
1157  qCritical("SoapySDRInput::applySettings: cannot %s AGC", settings.m_autoGain ? "set" : "unset");
1158  }
1159  }
1160  }
1161 
1162  if ((m_settings.m_autoDCCorrection != settings.m_autoDCCorrection) || force)
1163  {
1164  reverseAPIKeys.append("autoDCCorrection");
1165 
1166  if ((dev != 0) && hasDCAutoCorrection())
1167  {
1168  try
1169  {
1170  dev->setDCOffsetMode(SOAPY_SDR_RX, requestedChannel, settings.m_autoDCCorrection);
1171  qDebug("SoapySDRInput::applySettings: %s DC auto correction", settings.m_autoDCCorrection ? "set" : "unset");
1172  }
1173  catch (const std::exception &ex)
1174  {
1175  qCritical("SoapySDRInput::applySettings: cannot %s DC auto correction", settings.m_autoDCCorrection ? "set" : "unset");
1176  }
1177  }
1178  }
1179 
1180  if ((m_settings.m_dcCorrection != settings.m_dcCorrection) || force)
1181  {
1182  reverseAPIKeys.append("dcCorrection");
1183 
1184  if ((dev != 0) && hasDCCorrectionValue())
1185  {
1186  try
1187  {
1188  dev->setDCOffset(SOAPY_SDR_RX, requestedChannel, settings.m_dcCorrection);
1189  qDebug("SoapySDRInput::applySettings: DC offset correction set to (%lf, %lf)", settings.m_dcCorrection.real(), settings.m_dcCorrection.imag());
1190  }
1191  catch (const std::exception &ex)
1192  {
1193  qCritical("SoapySDRInput::applySettings: cannot set DC offset correction to (%lf, %lf)", settings.m_dcCorrection.real(), settings.m_dcCorrection.imag());
1194  }
1195  }
1196  }
1197 
1198  if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force)
1199  {
1200  reverseAPIKeys.append("iqCorrection");
1201 
1202  if ((dev != 0) && hasIQCorrectionValue())
1203  {
1204  try
1205  {
1206  dev->setIQBalance(SOAPY_SDR_RX, requestedChannel, settings.m_iqCorrection);
1207  qDebug("SoapySDRInput::applySettings: IQ balance correction set to (%lf, %lf)", settings.m_iqCorrection.real(), settings.m_iqCorrection.imag());
1208  }
1209  catch (const std::exception &ex)
1210  {
1211  qCritical("SoapySDRInput::applySettings: cannot set IQ balance correction to (%lf, %lf)", settings.m_iqCorrection.real(), settings.m_iqCorrection.imag());
1212  }
1213  }
1214  }
1215 
1216  for (const auto &oname : m_settings.m_streamArgSettings.keys())
1217  {
1218  auto nvalue = settings.m_streamArgSettings.find(oname);
1219 
1220  if (nvalue != settings.m_streamArgSettings.end() && ((m_settings.m_streamArgSettings[oname] != *nvalue) || force))
1221  {
1222  if (dev != 0)
1223  {
1224  try
1225  {
1226  dev->writeSetting(SOAPY_SDR_RX, requestedChannel, oname.toStdString(), nvalue->toString().toStdString());
1227  qDebug("SoapySDRInput::applySettings: stream argument %s set to %s",
1228  oname.toStdString().c_str(), nvalue->toString().toStdString().c_str());
1229  }
1230  catch (const std::exception &ex)
1231  {
1232  qCritical("SoapySDRInput::applySettings: cannot set stream argument %s to %s: %s",
1233  oname.toStdString().c_str(), nvalue->toString().toStdString().c_str(), ex.what());
1234  }
1235  }
1236 
1237  m_settings.m_streamArgSettings[oname] = *nvalue;
1238  }
1239  }
1240 
1241  for (const auto &oname : m_settings.m_deviceArgSettings.keys())
1242  {
1243  auto nvalue = settings.m_deviceArgSettings.find(oname);
1244 
1245  if (nvalue != settings.m_deviceArgSettings.end() && ((m_settings.m_deviceArgSettings[oname] != *nvalue) || force))
1246  {
1247  if (dev != 0)
1248  {
1249  try
1250  {
1251  dev->writeSetting(oname.toStdString(), nvalue->toString().toStdString());
1252  qDebug("SoapySDRInput::applySettings: device argument %s set to %s",
1253  oname.toStdString().c_str(), nvalue->toString().toStdString().c_str());
1254  }
1255  catch (const std::exception &ex)
1256  {
1257  qCritical("SoapySDRInput::applySettings: cannot set device argument %s to %s: %s",
1258  oname.toStdString().c_str(), nvalue->toString().toStdString().c_str(), ex.what());
1259  }
1260  }
1261 
1262  m_settings.m_deviceArgSettings[oname] = *nvalue;
1263  deviceArgsChanged = true;
1264  }
1265  }
1266 
1267  if (forwardChangeOwnDSP)
1268  {
1269  int sampleRate = settings.m_devSampleRate/(1<<settings.m_log2Decim);
1270  DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, settings.m_centerFrequency);
1271  m_fileSink->handleMessage(*notif); // forward to file sink
1273  }
1274 
1275  if (forwardChangeToBuddies)
1276  {
1277  // send to buddies
1278  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
1279  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
1280 
1281  for (const auto &itSource : sourceBuddies)
1282  {
1284  settings.m_centerFrequency,
1285  settings.m_LOppmTenths,
1286  (int) settings.m_fcPos,
1287  settings.m_devSampleRate,
1288  true);
1289  itSource->getSamplingDeviceInputMessageQueue()->push(report);
1290  }
1291 
1292  for (const auto &itSink : sinkBuddies)
1293  {
1295  settings.m_centerFrequency,
1296  settings.m_LOppmTenths,
1297  (int) settings.m_fcPos,
1298  settings.m_devSampleRate,
1299  true);
1300  itSink->getSamplingDeviceInputMessageQueue()->push(report);
1301  }
1302  }
1303 
1304  if (deviceArgsChanged)
1305  {
1306  // send to buddies
1307  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
1308  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
1309 
1310  for (const auto &itSource : sourceBuddies)
1311  {
1313  settings.m_deviceArgSettings);
1314  itSource->getSamplingDeviceInputMessageQueue()->push(report);
1315  }
1316 
1317  for (const auto &itSink : sinkBuddies)
1318  {
1320  settings.m_deviceArgSettings);
1321  itSink->getSamplingDeviceInputMessageQueue()->push(report);
1322  }
1323  }
1324 
1325  if (settings.m_useReverseAPI)
1326  {
1327  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
1331 
1332  if (fullUpdate || force) {
1333  webapiReverseSendSettings(reverseAPIKeys, settings, true);
1334  } else if (reverseAPIKeys.size() != 0) {
1335  webapiReverseSendSettings(reverseAPIKeys, settings, false);
1336  }
1337  }
1338 
1339  m_settings = settings;
1340 
1341  if (globalGainChanged || individualGainsChanged)
1342  {
1343  if (dev) {
1344  updateGains(dev, requestedChannel, m_settings);
1345  }
1346 
1347  if (getMessageQueueToGUI())
1348  {
1349  MsgReportGainChange *report = MsgReportGainChange::create(m_settings, globalGainChanged, individualGainsChanged);
1350  getMessageQueueToGUI()->push(report);
1351  }
1352  }
1353 
1354  qDebug() << "SoapySDRInput::applySettings: "
1355  << " m_transverterMode: " << m_settings.m_transverterMode
1356  << " m_transverterDeltaFrequency: " << m_settings.m_transverterDeltaFrequency
1357  << " m_centerFrequency: " << m_settings.m_centerFrequency << " Hz"
1358  << " m_LOppmTenths: " << m_settings.m_LOppmTenths
1359  << " m_log2Decim: " << m_settings.m_log2Decim
1360  << " m_fcPos: " << m_settings.m_fcPos
1361  << " m_devSampleRate: " << m_settings.m_devSampleRate
1362  << " m_softDCCorrection: " << m_settings.m_softDCCorrection
1363  << " m_softIQCorrection: " << m_settings.m_softIQCorrection
1364  << " m_antenna: " << m_settings.m_antenna
1365  << " m_bandwidth: " << m_settings.m_bandwidth
1366  << " m_globalGain: " << m_settings.m_globalGain
1367  << " force: " << force;
1368 
1369  QMap<QString, double>::const_iterator doubleIt = m_settings.m_individualGains.begin();
1370 
1371  for(; doubleIt != m_settings.m_individualGains.end(); ++doubleIt) {
1372  qDebug("SoapySDRInput::applySettings: m_individualGains[%s]: %lf", doubleIt.key().toStdString().c_str(), doubleIt.value());
1373  }
1374 
1375  doubleIt = m_settings.m_tunableElements.begin();
1376 
1377  for(; doubleIt != m_settings.m_tunableElements.end(); ++doubleIt) {
1378  qDebug("SoapySDRInput::applySettings: m_tunableElements[%s]: %lf", doubleIt.key().toStdString().c_str(), doubleIt.value());
1379  }
1380 
1381  QMap<QString, QVariant>::const_iterator varIt = m_settings.m_deviceArgSettings.begin();
1382 
1383  for(; varIt != m_settings.m_deviceArgSettings.end(); ++varIt)
1384  {
1385  qDebug("SoapySDRInput::applySettings: m_deviceArgSettings[%s] (type %d): %s",
1386  varIt.key().toStdString().c_str(),
1387  (int) varIt.value().type(), // bool: 1, int: 2, double: 6, string: 10 (http://doc.qt.io/archives/qt-4.8/qvariant.html)
1388  varIt.value().toString().toStdString().c_str());
1389  }
1390 
1391  varIt = m_settings.m_streamArgSettings.begin();
1392 
1393  for(; varIt != m_settings.m_streamArgSettings.end(); ++varIt)
1394  {
1395  qDebug("SoapySDRInput::applySettings: m_streamArgSettings[%s] (type %d): %s",
1396  varIt.key().toStdString().c_str(),
1397  (int) varIt.value().type(),
1398  varIt.value().toString().toStdString().c_str());
1399  }
1400 
1401  return true;
1402 }
1403 
1406  QString& errorMessage)
1407 {
1408  (void) errorMessage;
1410  response.getSoapySdrInputSettings()->init();
1412  return 200;
1413 }
1414 
1416  bool force,
1417  const QStringList& deviceSettingsKeys,
1418  SWGSDRangel::SWGDeviceSettings& response, // query + response
1419  QString& errorMessage)
1420 {
1421  (void) errorMessage;
1422  SoapySDRInputSettings settings = m_settings;
1423 
1424  if (deviceSettingsKeys.contains("centerFrequency")) {
1426  }
1427  if (deviceSettingsKeys.contains("LOppmTenths")) {
1428  settings.m_LOppmTenths = response.getSoapySdrInputSettings()->getLOppmTenths();
1429  }
1430  if (deviceSettingsKeys.contains("devSampleRate")) {
1432  }
1433  if (deviceSettingsKeys.contains("bandwidth")) {
1434  settings.m_bandwidth = response.getSoapySdrInputSettings()->getBandwidth();
1435  }
1436  if (deviceSettingsKeys.contains("log2Decim")) {
1437  settings.m_log2Decim = response.getSoapySdrInputSettings()->getLog2Decim();
1438  }
1439  if (deviceSettingsKeys.contains("fcPos")) {
1440  settings.m_fcPos = static_cast<SoapySDRInputSettings::fcPos_t>(response.getSoapySdrInputSettings()->getFcPos());
1441  }
1442  if (deviceSettingsKeys.contains("softDCCorrection")) {
1443  settings.m_softDCCorrection = response.getSoapySdrInputSettings()->getSoftDcCorrection() != 0;
1444  }
1445  if (deviceSettingsKeys.contains("softIQCorrection")) {
1446  settings.m_softIQCorrection = response.getSoapySdrInputSettings()->getSoftIqCorrection() != 0;
1447  }
1448  if (deviceSettingsKeys.contains("transverterDeltaFrequency")) {
1450  }
1451  if (deviceSettingsKeys.contains("transverterMode")) {
1452  settings.m_transverterMode = response.getSoapySdrInputSettings()->getTransverterMode() != 0;
1453  }
1454  if (deviceSettingsKeys.contains("fileRecordName")) {
1456  }
1457  if (deviceSettingsKeys.contains("antenna")) {
1458  settings.m_antenna = *response.getSoapySdrInputSettings()->getAntenna();
1459  }
1460 
1461  if (deviceSettingsKeys.contains("tunableElements"))
1462  {
1463  QList<SWGSDRangel::SWGArgValue*> *tunableElements = response.getSoapySdrInputSettings()->getTunableElements();
1464 
1465  for (const auto &itArg : *tunableElements)
1466  {
1467  QMap<QString, double>::iterator itSettings = settings.m_tunableElements.find(*(itArg->getKey()));
1468 
1469  if (itSettings != settings.m_tunableElements.end())
1470  {
1471  QVariant v = webapiVariantFromArgValue(itArg);
1472  itSettings.value() = v.toDouble();
1473  }
1474  }
1475  }
1476 
1477  if (deviceSettingsKeys.contains("globalGain")) {
1478  settings.m_globalGain = response.getSoapySdrInputSettings()->getGlobalGain();
1479  }
1480 
1481  if (deviceSettingsKeys.contains("individualGains"))
1482  {
1483  QList<SWGSDRangel::SWGArgValue*> *individualGains = response.getSoapySdrInputSettings()->getIndividualGains();
1484 
1485  for (const auto &itArg : *individualGains)
1486  {
1487  QMap<QString, double>::iterator itSettings = settings.m_individualGains.find(*(itArg->getKey()));
1488 
1489  if (itSettings != settings.m_individualGains.end())
1490  {
1491  QVariant v = webapiVariantFromArgValue(itArg);
1492  itSettings.value() = v.toDouble();
1493  }
1494  }
1495  }
1496 
1497  if (deviceSettingsKeys.contains("autoGain")) {
1498  settings.m_autoGain = response.getSoapySdrInputSettings()->getAutoGain() != 0;
1499  }
1500  if (deviceSettingsKeys.contains("autoDCCorrection")) {
1501  settings.m_autoDCCorrection = response.getSoapySdrInputSettings()->getAutoDcCorrection() != 0;
1502  }
1503  if (deviceSettingsKeys.contains("autoIQCorrection")) {
1504  settings.m_autoIQCorrection = response.getSoapySdrInputSettings()->getAutoIqCorrection() != 0;
1505  }
1506  if (deviceSettingsKeys.contains("dcCorrection"))
1507  {
1508  settings.m_dcCorrection.real(response.getSoapySdrInputSettings()->getDcCorrection()->getReal());
1509  settings.m_dcCorrection.imag(response.getSoapySdrInputSettings()->getDcCorrection()->getImag());
1510  }
1511  if (deviceSettingsKeys.contains("iqCorrection"))
1512  {
1513  settings.m_iqCorrection.real(response.getSoapySdrInputSettings()->getIqCorrection()->getReal());
1514  settings.m_iqCorrection.imag(response.getSoapySdrInputSettings()->getIqCorrection()->getImag());
1515  }
1516 
1517  if (deviceSettingsKeys.contains("streamArgSettings"))
1518  {
1519  QList<SWGSDRangel::SWGArgValue*> *streamArgSettings = response.getSoapySdrInputSettings()->getStreamArgSettings();
1520 
1521  for (const auto itArg : *streamArgSettings)
1522  {
1523  QMap<QString, QVariant>::iterator itSettings = settings.m_streamArgSettings.find(*itArg->getKey());
1524 
1525  if (itSettings != settings.m_streamArgSettings.end()) {
1526  itSettings.value() = webapiVariantFromArgValue(itArg);
1527  }
1528  }
1529  }
1530 
1531  if (deviceSettingsKeys.contains("deviceArgSettings"))
1532  {
1533  QList<SWGSDRangel::SWGArgValue*> *deviceArgSettings = response.getSoapySdrInputSettings()->getDeviceArgSettings();
1534 
1535  for (const auto itArg : *deviceArgSettings)
1536  {
1537  QMap<QString, QVariant>::iterator itSettings = settings.m_deviceArgSettings.find(*itArg->getKey());
1538 
1539  if (itSettings != settings.m_deviceArgSettings.end()) {
1540  itSettings.value() = webapiVariantFromArgValue(itArg);
1541  }
1542  }
1543  }
1544 
1545  if (deviceSettingsKeys.contains("useReverseAPI")) {
1546  settings.m_useReverseAPI = response.getSoapySdrInputSettings()->getUseReverseApi() != 0;
1547  }
1548  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
1550  }
1551  if (deviceSettingsKeys.contains("reverseAPIPort")) {
1553  }
1554  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
1556  }
1557 
1560 
1561  if (m_guiMessageQueue) // forward to GUI if any
1562  {
1563  MsgConfigureSoapySDRInput *msgToGUI = MsgConfigureSoapySDRInput::create(settings, force);
1564  m_guiMessageQueue->push(msgToGUI);
1565  }
1566 
1567  webapiFormatDeviceSettings(response, settings);
1568  return 200;
1569 }
1570 
1572 {
1573  (void) errorMessage;
1575  response.getSoapySdrInputReport()->init();
1576  webapiFormatDeviceReport(response);
1577  return 200;
1578 }
1579 
1581  SWGSDRangel::SWGDeviceState& response,
1582  QString& errorMessage)
1583 {
1584  (void) errorMessage;
1586  return 200;
1587 }
1588 
1590  bool run,
1591  SWGSDRangel::SWGDeviceState& response,
1592  QString& errorMessage)
1593 {
1594  (void) errorMessage;
1596  MsgStartStop *message = MsgStartStop::create(run);
1597  m_inputMessageQueue.push(message);
1598 
1599  if (m_guiMessageQueue) // forward to GUI if any
1600  {
1601  MsgStartStop *msgToGUI = MsgStartStop::create(run);
1602  m_guiMessageQueue->push(msgToGUI);
1603  }
1604 
1605  return 200;
1606 }
1607 
1609 {
1613  response.getSoapySdrInputSettings()->setLog2Decim(settings.m_log2Decim);
1614  response.getSoapySdrInputSettings()->setFcPos((int) settings.m_fcPos);
1615  response.getSoapySdrInputSettings()->setSoftDcCorrection(settings.m_softDCCorrection ? 1 : 0);
1616  response.getSoapySdrInputSettings()->setSoftIqCorrection(settings.m_softIQCorrection ? 1 : 0);
1618  response.getSoapySdrInputSettings()->setTransverterMode(settings.m_transverterMode ? 1 : 0);
1619 
1620  if (response.getSoapySdrInputSettings()->getFileRecordName()) {
1622  } else {
1623  response.getSoapySdrInputSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
1624  }
1625 
1626  if (response.getSoapySdrInputSettings()->getAntenna()) {
1627  *response.getSoapySdrInputSettings()->getAntenna() = settings.m_antenna;
1628  } else {
1629  response.getSoapySdrInputSettings()->setAntenna(new QString(settings.m_antenna));
1630  }
1631 
1632  if (response.getSoapySdrInputSettings()->getTunableElements()) {
1633  response.getSoapySdrInputSettings()->getTunableElements()->clear();
1634  } else {
1635  response.getSoapySdrInputSettings()->setTunableElements(new QList<SWGSDRangel::SWGArgValue*>);
1636  }
1637 
1638  for (const auto itName : settings.m_tunableElements.keys())
1639  {
1641  response.getSoapySdrInputSettings()->getTunableElements()->back()->setKey(new QString(itName));
1642  double value = settings.m_tunableElements.value(itName);
1643  response.getSoapySdrInputSettings()->getTunableElements()->back()->setValueString(new QString(tr("%1").arg(value)));
1644  response.getSoapySdrInputSettings()->getTunableElements()->back()->setValueType(new QString("float"));
1645  }
1646 
1647  response.getSoapySdrInputSettings()->setBandwidth(settings.m_bandwidth);
1648  response.getSoapySdrInputSettings()->setGlobalGain(settings.m_globalGain);
1649 
1650  if (response.getSoapySdrInputSettings()->getIndividualGains()) {
1651  response.getSoapySdrInputSettings()->getIndividualGains()->clear();
1652  } else {
1653  response.getSoapySdrInputSettings()->setIndividualGains(new QList<SWGSDRangel::SWGArgValue*>);
1654  }
1655 
1656  for (const auto itName : settings.m_individualGains.keys())
1657  {
1659  response.getSoapySdrInputSettings()->getIndividualGains()->back()->setKey(new QString(itName));
1660  double value = settings.m_individualGains.value(itName);
1661  response.getSoapySdrInputSettings()->getIndividualGains()->back()->setValueString(new QString(tr("%1").arg(value)));
1662  response.getSoapySdrInputSettings()->getIndividualGains()->back()->setValueType(new QString("float"));
1663  }
1664 
1665  response.getSoapySdrInputSettings()->setAutoGain(settings.m_autoGain ? 1 : 0);
1666  response.getSoapySdrInputSettings()->setAutoDcCorrection(settings.m_autoDCCorrection ? 1 : 0);
1667  response.getSoapySdrInputSettings()->setAutoIqCorrection(settings.m_autoIQCorrection ? 1 : 0);
1668 
1669  if (!response.getSoapySdrInputSettings()->getDcCorrection()) {
1671  }
1672 
1673  response.getSoapySdrInputSettings()->getDcCorrection()->setReal(settings.m_dcCorrection.real());
1674  response.getSoapySdrInputSettings()->getDcCorrection()->setImag(settings.m_dcCorrection.imag());
1675 
1676  if (!response.getSoapySdrInputSettings()->getIqCorrection()) {
1678  }
1679 
1680  response.getSoapySdrInputSettings()->getIqCorrection()->setReal(settings.m_iqCorrection.real());
1681  response.getSoapySdrInputSettings()->getIqCorrection()->setImag(settings.m_iqCorrection.imag());
1682 
1683  if (response.getSoapySdrInputSettings()->getStreamArgSettings()) {
1684  response.getSoapySdrInputSettings()->getStreamArgSettings()->clear();
1685  } else {
1686  response.getSoapySdrInputSettings()->setStreamArgSettings(new QList<SWGSDRangel::SWGArgValue*>);
1687  }
1688 
1689  for (const auto itName : settings.m_streamArgSettings.keys())
1690  {
1692  response.getSoapySdrInputSettings()->getStreamArgSettings()->back()->setKey(new QString(itName));
1693  const QVariant& v = settings.m_streamArgSettings.value(itName);
1695  }
1696 
1697  if (response.getSoapySdrInputSettings()->getDeviceArgSettings()) {
1698  response.getSoapySdrInputSettings()->getDeviceArgSettings()->clear();
1699  } else {
1700  response.getSoapySdrInputSettings()->setDeviceArgSettings(new QList<SWGSDRangel::SWGArgValue*>);
1701  }
1702 
1703  for (const auto itName : settings.m_deviceArgSettings.keys())
1704  {
1706  response.getSoapySdrInputSettings()->getDeviceArgSettings()->back()->setKey(new QString(itName));
1707  const QVariant& v = settings.m_deviceArgSettings.value(itName);
1709  }
1710 
1711  response.getSoapySdrInputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
1712 
1713  if (response.getSoapySdrInputSettings()->getReverseApiAddress()) {
1715  } else {
1716  response.getSoapySdrInputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
1717  }
1718 
1721 }
1722 
1724 {
1726 
1727  response.getSoapySdrInputReport()->setDeviceSettingsArgs(new QList<SWGSDRangel::SWGArgInfo*>);
1728 
1729  for (const auto itArg : m_deviceShared.m_deviceParams->getDeviceArgs())
1730  {
1733  }
1734 
1735  response.getSoapySdrInputReport()->setStreamSettingsArgs(new QList<SWGSDRangel::SWGArgInfo*>);
1736 
1737  for (const auto itArg : channelSettings->m_streamSettingsArgs)
1738  {
1741  }
1742 
1743  response.getSoapySdrInputReport()->setFrequencySettingsArgs(new QList<SWGSDRangel::SWGArgInfo*>);
1744 
1745  for (const auto itArg : channelSettings->m_frequencySettingsArgs)
1746  {
1749  }
1750 
1751  response.getSoapySdrInputReport()->setHasAgc(channelSettings->m_hasAGC ? 1 : 0);
1752  response.getSoapySdrInputReport()->setHasDcAutoCorrection(channelSettings->m_hasDCAutoCorrection ? 1 : 0);
1753  response.getSoapySdrInputReport()->setHasDcOffsetValue(channelSettings->m_hasDCOffsetValue ? 1 : 0);
1755  response.getSoapySdrInputReport()->setHasIqBalanceValue(channelSettings->m_hasIQBalanceValue ? 1 : 0);
1756 
1757  if (channelSettings->m_antennas.size() != 0)
1758  {
1759  response.getSoapySdrInputReport()->setAntennas(new QList<QString *>);
1760 
1761  for (const auto itAntenna : channelSettings->m_antennas) {
1762  response.getSoapySdrInputReport()->getAntennas()->append(new QString(itAntenna.c_str()));
1763  }
1764  }
1765 
1766  if ((channelSettings->m_gainRange.maximum() != 0.0) || (channelSettings->m_gainRange.minimum() != 0.0))
1767  {
1769  response.getSoapySdrInputReport()->getGainRange()->setMin(channelSettings->m_gainRange.minimum());
1770  response.getSoapySdrInputReport()->getGainRange()->setMax(channelSettings->m_gainRange.maximum());
1771  }
1772 
1773  if (channelSettings->m_gainSettings.size() != 0)
1774  {
1775  response.getSoapySdrInputReport()->setGainSettings(new QList<SWGSDRangel::SWGSoapySDRGainSetting*>);
1776 
1777  for (const auto itGain : channelSettings->m_gainSettings)
1778  {
1780  response.getSoapySdrInputReport()->getGainSettings()->back()->setRange(new SWGSDRangel::SWGRangeFloat());
1781  response.getSoapySdrInputReport()->getGainSettings()->back()->getRange()->setMin(itGain.m_range.minimum());
1782  response.getSoapySdrInputReport()->getGainSettings()->back()->getRange()->setMax(itGain.m_range.maximum());
1783  response.getSoapySdrInputReport()->getGainSettings()->back()->setName(new QString(itGain.m_name.c_str()));
1784  }
1785  }
1786 
1787  if (channelSettings->m_frequencySettings.size() != 0)
1788  {
1789  response.getSoapySdrInputReport()->setFrequencySettings(new QList<SWGSDRangel::SWGSoapySDRFrequencySetting*>);
1790 
1791  for (const auto itFreq : channelSettings->m_frequencySettings)
1792  {
1794  response.getSoapySdrInputReport()->getFrequencySettings()->back()->setRanges(new QList<SWGSDRangel::SWGRangeFloat*>);
1795 
1796  for (const auto itRange : itFreq.m_ranges)
1797  {
1798  response.getSoapySdrInputReport()->getFrequencySettings()->back()->getRanges()->append(new SWGSDRangel::SWGRangeFloat());
1799  response.getSoapySdrInputReport()->getFrequencySettings()->back()->getRanges()->back()->setMin(itRange.minimum());
1800  response.getSoapySdrInputReport()->getFrequencySettings()->back()->getRanges()->back()->setMax(itRange.maximum());
1801  }
1802 
1803  response.getSoapySdrInputReport()->getFrequencySettings()->back()->setName(new QString(itFreq.m_name.c_str()));
1804  }
1805  }
1806 
1807  if (channelSettings->m_ratesRanges.size() != 0)
1808  {
1809  response.getSoapySdrInputReport()->setRatesRanges(new QList<SWGSDRangel::SWGRangeFloat*>);
1810 
1811  for (const auto itRange : channelSettings->m_ratesRanges)
1812  {
1814  response.getSoapySdrInputReport()->getRatesRanges()->back()->setMin(itRange.minimum());
1815  response.getSoapySdrInputReport()->getRatesRanges()->back()->setMax(itRange.maximum());
1816  }
1817  }
1818 
1819  if (channelSettings->m_bandwidthsRanges.size() != 0)
1820  {
1821  response.getSoapySdrInputReport()->setBandwidthsRanges(new QList<SWGSDRangel::SWGRangeFloat*>);
1822 
1823  for (const auto itBandwidth : channelSettings->m_bandwidthsRanges)
1824  {
1826  response.getSoapySdrInputReport()->getBandwidthsRanges()->back()->setMin(itBandwidth.minimum());
1827  response.getSoapySdrInputReport()->getBandwidthsRanges()->back()->setMax(itBandwidth.maximum());
1828  }
1829  }
1830 }
1831 
1833 {
1834  if (*argValue->getValueType() == "bool") {
1835  return QVariant((bool) (*argValue->getValueString() == "1"));
1836  } else if (*argValue->getValueType() == "int") {
1837  return QVariant((int) (atoi(argValue->getValueString()->toStdString().c_str())));
1838  } else if (*argValue->getValueType() == "float") {
1839  return QVariant((double) (atof(argValue->getValueString()->toStdString().c_str())));
1840  } else {
1841  return QVariant(QString(*argValue->getValueString()));
1842  }
1843 }
1844 
1846 {
1847  if (v.type() == QVariant::Bool)
1848  {
1849  argValue->setValueType(new QString("bool"));
1850  argValue->setValueString(new QString(v.toBool() ? "1" : "0"));
1851  }
1852  else if (v.type() == QVariant::Int)
1853  {
1854  argValue->setValueType(new QString("int"));
1855  argValue->setValueString(new QString(tr("%1").arg(v.toInt())));
1856  }
1857  else if (v.type() == QVariant::Double)
1858  {
1859  argValue->setValueType(new QString("float"));
1860  argValue->setValueString(new QString(tr("%1").arg(v.toDouble())));
1861  }
1862  else
1863  {
1864  argValue->setValueType(new QString("string"));
1865  argValue->setValueString(new QString(v.toString()));
1866  }
1867 }
1868 
1869 void SoapySDRInput::webapiFormatArgInfo(const SoapySDR::ArgInfo& arg, SWGSDRangel::SWGArgInfo *argInfo)
1870 {
1871  argInfo->setKey(new QString(arg.key.c_str()));
1872 
1873  if (arg.type == SoapySDR::ArgInfo::BOOL) {
1874  argInfo->setValueType(new QString("bool"));
1875  } else if (arg.type == SoapySDR::ArgInfo::INT) {
1876  argInfo->setValueType(new QString("int"));
1877  } else if (arg.type == SoapySDR::ArgInfo::FLOAT) {
1878  argInfo->setValueType(new QString("float"));
1879  } else {
1880  argInfo->setValueType(new QString("string"));
1881  }
1882 
1883  argInfo->setValueString(new QString(arg.value.c_str()));
1884  argInfo->setName(new QString(arg.name.c_str()));
1885  argInfo->setDescription(new QString(arg.description.c_str()));
1886  argInfo->setUnits(new QString(arg.units.c_str()));
1887 
1888  if ((arg.range.minimum() != 0.0) || (arg.range.maximum() != 0.0))
1889  {
1890  argInfo->setRange(new SWGSDRangel::SWGRangeFloat());
1891  argInfo->getRange()->setMin(arg.range.minimum());
1892  argInfo->getRange()->setMax(arg.range.maximum());
1893  }
1894 
1895  argInfo->setValueOptions(new QList<QString*>);
1896 
1897  for (const auto itOpt : arg.options) {
1898  argInfo->getValueOptions()->append(new QString(itOpt.c_str()));
1899  }
1900 
1901  argInfo->setOptionNames(new QList<QString*>);
1902 
1903  for (const auto itOpt : arg.optionNames) {
1904  argInfo->getOptionNames()->append(new QString(itOpt.c_str()));
1905  }
1906 }
1907 
1908 void SoapySDRInput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const SoapySDRInputSettings& settings, bool force)
1909 {
1911  swgDeviceSettings->setDirection(0); // Single Tx
1912  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
1913  swgDeviceSettings->setDeviceHwType(new QString("SoapySDR"));
1915  swgDeviceSettings->getSoapySdrInputSettings()->init();
1916  SWGSDRangel::SWGSoapySDRInputSettings *swgSoapySDRInputSettings = swgDeviceSettings->getSoapySdrInputSettings();
1917 
1918  // transfer data that has been modified. When force is on transfer all data except reverse API data
1919 
1920  if (deviceSettingsKeys.contains("centerFrequency") || force) {
1921  swgSoapySDRInputSettings->setCenterFrequency(settings.m_centerFrequency);
1922  }
1923  if (deviceSettingsKeys.contains("LOppmTenths") || force) {
1924  swgSoapySDRInputSettings->setLOppmTenths(settings.m_LOppmTenths);
1925  }
1926  if (deviceSettingsKeys.contains("devSampleRate") || force) {
1927  swgSoapySDRInputSettings->setDevSampleRate(settings.m_devSampleRate);
1928  }
1929  if (deviceSettingsKeys.contains("bandwidth") || force) {
1930  swgSoapySDRInputSettings->setBandwidth(settings.m_bandwidth);
1931  }
1932  if (deviceSettingsKeys.contains("log2Decim") || force) {
1933  swgSoapySDRInputSettings->setLog2Decim(settings.m_log2Decim);
1934  }
1935  if (deviceSettingsKeys.contains("fcPos") || force) {
1936  swgSoapySDRInputSettings->setFcPos((int) settings.m_fcPos);
1937  }
1938  if (deviceSettingsKeys.contains("softDCCorrection") || force) {
1939  swgSoapySDRInputSettings->setSoftDcCorrection(settings.m_softDCCorrection ? 1 : 0);
1940  }
1941  if (deviceSettingsKeys.contains("softIQCorrection") || force) {
1942  swgSoapySDRInputSettings->setSoftIqCorrection(settings.m_softIQCorrection ? 1 : 0);
1943  }
1944  if (deviceSettingsKeys.contains("transverterDeltaFrequency") || force) {
1945  swgSoapySDRInputSettings->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency);
1946  }
1947  if (deviceSettingsKeys.contains("transverterMode") || force) {
1948  swgSoapySDRInputSettings->setTransverterMode(settings.m_transverterMode ? 1 : 0);
1949  }
1950  if (deviceSettingsKeys.contains("fileRecordName") || force) {
1951  swgSoapySDRInputSettings->setFileRecordName(new QString(settings.m_fileRecordName));
1952  }
1953  if (deviceSettingsKeys.contains("antenna") || force) {
1954  swgSoapySDRInputSettings->setAntenna(new QString(settings.m_antenna));
1955  }
1956  if (deviceSettingsKeys.contains("globalGain") || force) {
1957  swgSoapySDRInputSettings->setGlobalGain(settings.m_globalGain);
1958  }
1959  if (deviceSettingsKeys.contains("autoGain") || force) {
1960  swgSoapySDRInputSettings->setAutoGain(settings.m_autoGain ? 1 : 0);
1961  }
1962  if (deviceSettingsKeys.contains("autoDCCorrection") || force) {
1963  swgSoapySDRInputSettings->setAutoDcCorrection(settings.m_autoDCCorrection ? 1 : 0);
1964  }
1965  if (deviceSettingsKeys.contains("autoIQCorrection") || force) {
1966  swgSoapySDRInputSettings->setAutoIqCorrection(settings.m_autoIQCorrection ? 1 : 0);
1967  }
1968  if (deviceSettingsKeys.contains("dcCorrection") || force)
1969  {
1970  swgSoapySDRInputSettings->setDcCorrection(new SWGSDRangel::SWGComplex());
1971  swgSoapySDRInputSettings->getDcCorrection()->setReal(settings.m_dcCorrection.real());
1972  swgSoapySDRInputSettings->getDcCorrection()->setImag(settings.m_dcCorrection.imag());
1973  }
1974  if (deviceSettingsKeys.contains("iqCorrection") || force)
1975  {
1976  swgSoapySDRInputSettings->setIqCorrection(new SWGSDRangel::SWGComplex());
1977  swgSoapySDRInputSettings->getIqCorrection()->setReal(settings.m_iqCorrection.real());
1978  swgSoapySDRInputSettings->getIqCorrection()->setImag(settings.m_iqCorrection.imag());
1979  }
1980 
1981  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
1982  .arg(settings.m_reverseAPIAddress)
1983  .arg(settings.m_reverseAPIPort)
1984  .arg(settings.m_reverseAPIDeviceIndex);
1985  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
1986  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
1987 
1988  QBuffer *buffer=new QBuffer();
1989  buffer->open((QBuffer::ReadWrite));
1990  buffer->write(swgDeviceSettings->asJson().toUtf8());
1991  buffer->seek(0);
1992 
1993  // Always use PATCH to avoid passing reverse API settings
1994  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
1995 
1996  delete swgDeviceSettings;
1997 }
1998 
2000 {
2002  swgDeviceSettings->setDirection(0); // Single Tx
2003  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
2004  swgDeviceSettings->setDeviceHwType(new QString("SoapySDR"));
2005 
2006  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
2010  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
2011  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
2012 
2013  QBuffer *buffer=new QBuffer();
2014  buffer->open((QBuffer::ReadWrite));
2015  buffer->write(swgDeviceSettings->asJson().toUtf8());
2016  buffer->seek(0);
2017 
2018  if (start) {
2019  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
2020  } else {
2021  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
2022  }
2023 
2024  delete swgDeviceSettings;
2025 }
2026 
2027 void SoapySDRInput::networkManagerFinished(QNetworkReply *reply)
2028 {
2029  QNetworkReply::NetworkError replyError = reply->error();
2030 
2031  if (replyError)
2032  {
2033  qWarning() << "SoapySDRInput::networkManagerFinished:"
2034  << " error(" << (int) replyError
2035  << "): " << replyError
2036  << ": " << reply->errorString();
2037  return;
2038  }
2039 
2040  QString answer = reply->readAll();
2041  answer.chop(1); // remove last \n
2042  qDebug("SoapySDRInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
2043 }
void setAutoDcCorrection(qint32 auto_dc_correction)
void networkManagerFinished(QNetworkReply *reply)
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
const SoapySDR::RangeList & getBandwidthRanges()
void setHasFrequencyCorrectionValue(qint32 has_frequency_correction_value)
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
const SoapySDR::RangeList & getRateRanges()
int m_channel
allocated channel (-1 if none)
void setSoapySdrInputReport(SWGSoapySDRReport *soapy_sdr_input_report)
QMap< QString, QVariant > m_streamArgSettings
virtual void stop()
static qint64 calculateDeviceCenterFrequency(quint64 centerFrequency, qint64 transverterDeltaFrequency, int log2Decim, fcPos_t fcPos, quint32 devSampleRate, FrequencyShiftScheme frequencyShiftScheme, bool transverterMode=false)
virtual void setCenterFrequency(qint64 centerFrequency)
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
QList< QString * > * getValueOptions()
Definition: SWGArgInfo.cpp:263
void setTransverterMode(qint32 transverter_mode)
QList< QString * > * getOptionNames()
Definition: SWGArgInfo.cpp:273
void setName(QString *name)
Definition: SWGArgInfo.cpp:227
void setFileName(const QString &filename)
Definition: filerecord.cpp:59
const std::vector< DeviceSoapySDRParams::FrequencySetting > & getTunableElements()
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
uint getDeviceUID() const
Return the current device engine unique ID.
Definition: deviceapi.cpp:303
void setReal(float real)
Definition: SWGComplex.cpp:101
void setThread(SoapySDRInputThread *thread)
const std::vector< DeviceAPI * > & getSinkBuddies() const
Definition: deviceapi.h:166
void startRecording()
Definition: filerecord.cpp:105
bool hasDCAutoCorrection()
static MsgReportDeviceArgsChange * create(const QMap< QString, QVariant > &deviceArgSettings)
void setCenterFrequency(qint64 center_frequency)
MessageQueue m_inputMessageQueue
Input queue to the source.
void setValueOptions(QList< QString *> *value_options)
Definition: SWGArgInfo.cpp:267
virtual bool handleMessage(const Message &message)
virtual QString asJson() override
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
static DeviceSoapySDR & instance()
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
virtual ~SoapySDRInput()
DeviceAPI * m_deviceAPI
SoapySDRInputThread * m_thread
void setFrequencySettingsArgs(QList< SWGArgInfo *> *frequency_settings_args)
SoapySDR::ArgInfoList m_frequencySettingsArgs
common tuning parameters
const QMap< QString, QVariant > & getDeviceArgSettings() const
std::string getRxChannelMainTunableElementName(uint32_t index)
uint32_t getDeviceItemIndex() const
Definition: deviceapi.h:129
void setFcPos(unsigned int channel, int fcPos)
void closeSoapySdr(SoapySDR::Device *device)
static MsgReportBuddyChange * create(uint64_t centerFrequency, int LOppmTenths, int fcPos, int devSampleRate, bool rxElseTx)
void setIndividualGains(QList< SWGArgValue *> *individual_gains)
void initGainSettings(SoapySDRInputSettings &settings)
virtual int getSampleRate() const
Sample rate exposed by the source.
bool m_hasFrequencyCorrectionValue
Frequency correction value flag.
void setRange(SWGRangeFloat *range)
Definition: SWGArgInfo.cpp:257
QList< SWGSoapySDRGainSetting * > * getGainSettings()
bool hasDCCorrectionValue()
bool m_hasDCOffsetValue
DC offset value flag.
DeviceSoapySDRShared m_deviceShared
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
void setSoftIqCorrection(qint32 soft_iq_correction)
void setDeviceSettingsArgs(QList< SWGArgInfo *> *device_settings_args)
std::complex< double > m_iqCorrection
const QString & getHardwareUserArguments() const
Definition: deviceapi.h:124
bool m_hasDCAutoCorrection
DC offset auto correction flag.
QList< SWGArgInfo * > * getStreamSettingsArgs()
void setSampleRate(unsigned int sampleRate)
bool applySettings(const SoapySDRInputSettings &settings, bool force=false)
void setStreamSettingsArgs(QList< SWGArgInfo *> *stream_settings_args)
std::vector< FrequencySetting > m_frequencySettings
tunable elements settings
void setOriginatorIndex(qint32 originator_index)
void setAutoIqCorrection(qint32 auto_iq_correction)
QString m_deviceDescription
void setImag(float imag)
Definition: SWGComplex.cpp:111
SampleSinkFifo m_sampleFifo
bool setSize(int size)
void initDeviceArgSettings(SoapySDRInputSettings &settings)
void setSoftDcCorrection(qint32 soft_dc_correction)
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
SoapySDRInputThread * findThread()
QMap< QString, QVariant > m_deviceArgSettings
int getFcPos(unsigned int channel) const
virtual bool start()
const ChannelSettings * getRxChannelSettings(uint32_t index)
void setStreamArgSettings(QList< SWGArgValue *> *stream_arg_settings)
void getFrequencyRange(uint64_t &min, uint64_t &max)
void setValueString(QString *value_string)
static MsgConfigureSoapySDRInput * create(const SoapySDRInputSettings &settings, bool force)
Definition: soapysdrinput.h:61
const SoapySDR::ArgInfoList & getStreamArgInfoList()
void setValueString(QString *value_string)
Definition: SWGArgInfo.cpp:217
void setValueType(QString *value_type)
Definition: SWGArgInfo.cpp:207
void setGainRange(SWGRangeFloat *gain_range)
int getDeviceSetIndex() const
Definition: deviceapi.h:131
SoapySDR::RangeList m_ranges
List of ranges of the tunable element.
void setHasDcAutoCorrection(qint32 has_dc_auto_correction)
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const SoapySDRInputSettings &settings, bool force)
QNetworkRequest m_networkRequest
QList< SWGArgInfo * > * getDeviceSettingsArgs()
void * getBuddySharedPtr() const
Definition: deviceapi.h:161
void setIqCorrection(SWGComplex *iq_correction)
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
void genUniqueFileName(uint deviceUID, int istream=-1)
Definition: filerecord.cpp:67
QMap< QString, double > m_tunableElements
void setTransverterDeltaFrequency(qint64 transverter_delta_frequency)
void setRatesRanges(QList< SWGRangeFloat *> *rates_ranges)
void setGainSettings(QList< SWGSoapySDRGainSetting *> *gain_settings)
void setReverseApiAddress(QString *reverse_api_address)
void setDeviceArgSettings(QList< SWGArgValue *> *device_arg_settings)
std::vector< std::string > m_antennas
Antenna ports names.
DeviceSoapySDRParams * m_deviceParams
SoapySDR::RangeList m_ratesRanges
list of ranges of sample rates
virtual const QString & getDeviceDescription() const
void setBuddySharedPtr(void *ptr)
Definition: deviceapi.h:162
void stopRecording()
Definition: filerecord.cpp:117
const std::vector< DeviceSoapySDRParams::GainSetting > & getIndividualGainsRanges()
void setLog2Decimation(unsigned int channel, unsigned int log2_decim)
int32_t i
Definition: decimators.h:244
void setBandwidthsRanges(QList< SWGRangeFloat *> *bandwidths_ranges)
void setKey(QString *key)
Definition: SWGArgInfo.cpp:197
std::complex< double > m_dcCorrection
QMap< QString, double > m_individualGains
const SoapySDR::ArgInfoList & getDeviceArgs() const
QList< SWGArgInfo * > * getFrequencySettingsArgs()
static bool match(const Message *message)
Definition: message.cpp:45
static MsgReportGainChange * create(const SoapySDRInputSettings &settings, bool globalGain, bool individualGains)
QList< SWGRangeFloat * > * getBandwidthsRanges()
SampleSinkFifo * getFifo(unsigned int channel)
SoapySDR::Device * m_device
void removeAncillarySink(BasebandSampleSink *sink, unsigned int index=0)
Removes it.
Definition: deviceapi.cpp:100
void webapiFormatArgInfo(const SoapySDR::ArgInfo &arg, SWGSDRangel::SWGArgInfo *argInfo)
SWGRangeFloat * getRange()
Definition: SWGArgInfo.cpp:253
int BOOL
Definition: fcdhid.h:37
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
SoapySDR::RangeList m_bandwidthsRanges
list of ranges of bandwidths
void webapiReverseSendStartStop(bool start)
void setUnits(QString *units)
Definition: SWGArgInfo.cpp:247
void setValueType(QString *value_type)
QList< SWGSoapySDRFrequencySetting * > * getFrequencySettings()
const SoapySDRInputSettings & getSettings() const
Definition: soapysdrinput.h:58
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
virtual bool deserialize(const QByteArray &data)
void setDcCorrection(SWGComplex *dc_correction)
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
void setFrequencySettings(QList< SWGSoapySDRFrequencySetting *> *frequency_settings)
void webapiFormatArgValue(const QVariant &v, SWGSDRangel::SWGArgValue *argValue)
virtual QByteArray serialize() const
void updateGains(SoapySDR::Device *dev, int requestedChannel, SoapySDRInputSettings &settings)
const std::vector< std::string > & getAntennas()
SoapySDRInputSettings m_settings
void initStreamArgSettings(SoapySDRInputSettings &settings)
void getGlobalGainRange(int &min, int &max)
void setTunableElements(QList< SWGArgValue *> *tunable_elements)
void updateTunableElements(SoapySDR::Device *dev, int requestedChannel, SoapySDRInputSettings &settings)
bool hasIQCorrectionValue()
int getAntennaIndex(const std::string &antenna)
unsigned int getLog2Decimation(unsigned int channel) const
void setFileRecordName(QString *file_record_name)
SoapySDR::Device * openSoapySDR(uint32_t sequence, const QString &hardwareUserArguments)
void initTunableElementsSettings(SoapySDRInputSettings &settings)
void setDescription(QString *description)
Definition: SWGArgInfo.cpp:237
const SoapySDR::ArgInfoList & getDeviceArgInfoList()
void setHasIqBalanceValue(qint32 has_iq_balance_value)
virtual quint64 getCenterFrequency() const
Center frequency exposed by the source.
static MsgStartStop * create(bool startStop)
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
const std::vector< DeviceAPI * > & getSourceBuddies() const
Definition: deviceapi.h:165
void moveThreadToBuddy()
QVariant webapiVariantFromArgValue(SWGSDRangel::SWGArgValue *argValue)
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
std::vector< GainSetting > m_gainSettings
gain elements settings
void setOptionNames(QList< QString *> *option_names)
Definition: SWGArgInfo.cpp:277
SWGSoapySDRReport * getSoapySdrInputReport()
bool setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths)
QList< QString * > * getAntennas()
SoapySDRInputThread * getThread()
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
SoapySDR::ArgInfoList m_streamSettingsArgs
common stream parameters
void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection, int streamIndex=0)
Configure current device engine DSP corrections (Rx)
Definition: deviceapi.cpp:355
void setFifo(unsigned int channel, SampleSinkFifo *sampleFifo)
QList< SWGRangeFloat * > * getRatesRanges()
void setSoapySdrInputSettings(SWGSoapySDRInputSettings *soapy_sdr_input_settings)
uint32_t getSamplingDeviceSequence() const
Definition: deviceapi.h:123
void setDirection(qint32 direction)
const QByteArray & final()
bool m_hasIQBalanceValue
IQ correction value flag.
FileRecord * m_fileSink
File sink to record device I/Q output.
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const SoapySDRInputSettings &settings)
void setAntennas(QList< QString *> *antennas)
T max(const T &x, const T &y)
Definition: framework.h:446
void setHasDcOffsetValue(qint32 has_dc_offset_value)
void setDeviceHwType(QString *device_hw_type)
void setReverseApiPort(qint32 reverse_api_port)
unsigned int getNbChannels() const
SoapySDR::Range m_gainRange
Global gain range.
SWGSoapySDRInputSettings * getSoapySdrInputSettings()
T min(const T &x, const T &y)
Definition: framework.h:440
virtual void destroy()
QNetworkAccessManager * m_networkManager
unsigned __int64 uint64_t
Definition: rtptypes_win.h:48