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