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.
limesdroutput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2017 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 <cstddef>
19 #include <string.h>
20 
21 #include <QMutexLocker>
22 #include <QDebug>
23 #include <QNetworkReply>
24 #include <QBuffer>
25 
26 #include "lime/LimeSuite.h"
27 
28 #include "SWGDeviceSettings.h"
30 #include "SWGDeviceState.h"
31 #include "SWGDeviceReport.h"
32 #include "SWGLimeSdrOutputReport.h"
33 
34 #include "device/deviceapi.h"
35 #include "dsp/dspcommands.h"
36 #include "dsp/dspengine.h"
37 #include "limesdroutputthread.h"
39 #include "limesdr/devicelimesdr.h"
40 #include "limesdroutput.h"
41 
47 
48 
50  m_deviceAPI(deviceAPI),
51  m_settings(),
52  m_limeSDROutputThread(0),
53  m_deviceDescription("LimeSDROutput"),
54  m_running(false),
55  m_channelAcquired(false)
56 {
57  m_deviceAPI->setNbSinkStreams(1);
58  m_sampleSourceFifo.resize(16*LIMESDROUTPUT_BLOCKSIZE);
59  m_streamId.handle = 0;
60  suspendRxBuddies();
61  suspendTxBuddies();
62  openDevice();
63  resumeTxBuddies();
64  resumeRxBuddies();
65  m_networkManager = new QNetworkAccessManager();
66  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
67 }
68 
70 {
71  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
72  delete m_networkManager;
73 
74  if (m_running) {
75  stop();
76  }
77 
80  closeDevice();
83 }
84 
86 {
87  delete this;
88 }
89 
91 {
92  int requestedChannel = m_deviceAPI->getDeviceItemIndex();
93 
94  // look for Tx buddies and get reference to common parameters
95  // if there is a channel left take the first available
96  if (m_deviceAPI->getSinkBuddies().size() > 0) // look sink sibling first
97  {
98  qDebug("LimeSDROutput::openDevice: look in Ix buddies");
99 
100  DeviceAPI *sinkBuddy = m_deviceAPI->getSinkBuddies()[0];
101  //m_deviceShared = *((DeviceLimeSDRShared *) sinkBuddy->getBuddySharedPtr()); // copy shared data
102  DeviceLimeSDRShared *deviceLimeSDRShared = (DeviceLimeSDRShared*) sinkBuddy->getBuddySharedPtr();
103  m_deviceShared.m_deviceParams = deviceLimeSDRShared->m_deviceParams;
104 
105  DeviceLimeSDRParams *deviceParams = m_deviceShared.m_deviceParams; // get device parameters
106 
107  if (deviceParams == 0)
108  {
109  qCritical("LimeSDROutput::openDevice: cannot get device parameters from Tx buddy");
110  return false; // the device params should have been created by the buddy
111  }
112  else
113  {
114  qDebug("LimeSDROutput::openDevice: getting device parameters from Tx buddy");
115  }
116 
117  if (m_deviceAPI->getSinkBuddies().size() == deviceParams->m_nbTxChannels)
118  {
119  qCritical("LimeSDROutput::openDevice: no more Tx channels available in device");
120  return false; // no more Tx channels available in device
121  }
122  else
123  {
124  qDebug("LimeSDROutput::openDevice: at least one more Tx channel is available in device");
125  }
126 
127  // check if the requested channel is busy and abort if so (should not happen if device management is working correctly)
128 
129  for (unsigned int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++)
130  {
131  DeviceAPI *buddy = m_deviceAPI->getSinkBuddies()[i];
132  DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr();
133 
134  if (buddyShared->m_channel == requestedChannel)
135  {
136  qCritical("LimeSDROutput::openDevice: cannot open busy channel %u", requestedChannel);
137  return false;
138  }
139  }
140 
141  m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel
142  }
143  // look for Rx buddies and get reference to common parameters
144  // take the first Rx channel
145  else if (m_deviceAPI->getSourceBuddies().size() > 0) // then source
146  {
147  qDebug("LimeSDROutput::openDevice: look in Rx buddies");
148 
149  DeviceAPI *sourceBuddy = m_deviceAPI->getSourceBuddies()[0];
150  //m_deviceShared = *((DeviceLimeSDRShared *) sourceBuddy->getBuddySharedPtr()); // copy parameters
151  DeviceLimeSDRShared *deviceLimeSDRShared = (DeviceLimeSDRShared*) sourceBuddy->getBuddySharedPtr();
152  m_deviceShared.m_deviceParams = deviceLimeSDRShared->m_deviceParams;
153 
155  {
156  qCritical("LimeSDROutput::openDevice: cannot get device parameters from Rx buddy");
157  return false; // the device params should have been created by the buddy
158  }
159  else
160  {
161  qDebug("LimeSDROutput::openDevice: getting device parameters from Rx buddy");
162  }
163 
164  m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel
165  }
166  // There are no buddies then create the first LimeSDR common parameters
167  // open the device this will also populate common fields
168  // take the first Tx channel
169  else
170  {
171  qDebug("LimeSDROutput::openDevice: open device here");
172 
174  char serial[256];
175  strcpy(serial, qPrintable(m_deviceAPI->getSamplingDeviceSerial()));
177  m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel
178  }
179 
180  m_deviceAPI->setBuddySharedPtr(&m_deviceShared); // propagate common parameters to API
181 
182  return true;
183 }
184 
186 {
187  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
188  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
189 
190  qDebug("LimeSDROutput::suspendRxBuddies (%lu)", sourceBuddies.size());
191 
192  for (; itSource != sourceBuddies.end(); ++itSource)
193  {
194  DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr();
195 
196  if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning())
197  {
198  buddySharedPtr->m_thread->stopWork();
199  buddySharedPtr->m_threadWasRunning = true;
200  }
201  else
202  {
203  buddySharedPtr->m_threadWasRunning = false;
204  }
205  }
206 }
207 
209 {
210  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
211  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
212 
213  qDebug("LimeSDROutput::suspendTxBuddies (%lu)", sinkBuddies.size());
214 
215  for (; itSink != sinkBuddies.end(); ++itSink)
216  {
217  DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr();
218 
219  if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning())
220  {
221  buddySharedPtr->m_thread->stopWork();
222  buddySharedPtr->m_threadWasRunning = true;
223  }
224  else
225  {
226  buddySharedPtr->m_threadWasRunning = false;
227  }
228  }
229 }
230 
232 {
233  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
234  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
235 
236  qDebug("LimeSDROutput::resumeRxBuddies (%lu)", sourceBuddies.size());
237 
238  for (; itSource != sourceBuddies.end(); ++itSource)
239  {
240  DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr();
241 
242  if (buddySharedPtr->m_threadWasRunning) {
243  buddySharedPtr->m_thread->startWork();
244  }
245  }
246 }
247 
249 {
250  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
251  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
252 
253  qDebug("LimeSDROutput::resumeTxBuddies (%lu)", sinkBuddies.size());
254 
255  for (; itSink != sinkBuddies.end(); ++itSink)
256  {
257  DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr();
258 
259  if (buddySharedPtr->m_threadWasRunning) {
260  buddySharedPtr->m_thread->startWork();
261  }
262  }
263 }
264 
266 {
267  if (m_deviceShared.m_deviceParams->getDevice() == 0) { // was never open
268  return;
269  }
270 
271  if (m_running) stop();
272 
273  // No buddies so effectively close the device
274 
275  if ((m_deviceAPI->getSourceBuddies().size() == 0) && (m_deviceAPI->getSinkBuddies().size() == 0))
276  {
280  }
281 
282  m_deviceShared.m_channel = -1; // effectively release the channel for the possible buddies
283 }
284 
286 {
289 
290  // acquire the channel
291 
292  if (LMS_EnableChannel(m_deviceShared.m_deviceParams->getDevice(), LMS_CH_TX, m_deviceShared.m_channel, true) != 0)
293  {
294  qCritical("LimeSDROutput::acquireChannel: cannot enable Tx channel %d", m_deviceShared.m_channel);
295  return false;
296  }
297  else
298  {
299  qDebug("LimeSDROutput::acquireChannel: Tx channel %d enabled", m_deviceShared.m_channel);
300  }
301 
302  // set up the stream
303 
304  m_streamId.channel = m_deviceShared.m_channel; // channel number
305  m_streamId.fifoSize = 1024 * 1024; // fifo size in samples (SR / 10 take ~5MS/s)
306  m_streamId.throughputVsLatency = 0.5; // optimize for min latency
307  m_streamId.isTx = true; // TX channel
308  m_streamId.dataFmt = lms_stream_t::LMS_FMT_I12; // 12-bit integers
309 
310  if (LMS_SetupStream(m_deviceShared.m_deviceParams->getDevice(), &m_streamId) != 0)
311  {
312  qCritical("LimeSDROutput::acquireChannel: cannot setup the stream on Tx channel %d", m_deviceShared.m_channel);
313  resumeTxBuddies();
314  resumeRxBuddies();
315  return false;
316  }
317  else
318  {
319  qDebug("LimeSDROutput::acquireChannel: stream set up on Tx channel %d", m_deviceShared.m_channel);
320  }
321 
322  resumeTxBuddies();
323  resumeRxBuddies();
324 
325  m_channelAcquired = true;
326 
327  return true;
328 }
329 
331 {
334 
335  // destroy the stream
336 
337  if (LMS_DestroyStream(m_deviceShared.m_deviceParams->getDevice(), &m_streamId) != 0)
338  {
339  qWarning("LimeSDROutput::releaseChannel: cannot destroy the stream on Tx channel %d", m_deviceShared.m_channel);
340  }
341  else
342  {
343  qDebug("LimeSDROutput::releaseChannel: stream destroyed on Tx channel %d", m_deviceShared.m_channel);
344  }
345 
346  m_streamId.handle = 0;
347 
348  // release the channel
349 
350  if (LMS_EnableChannel(m_deviceShared.m_deviceParams->getDevice(), LMS_CH_TX, m_deviceShared.m_channel, false) != 0)
351  {
352  qWarning("LimeSDROutput::releaseChannel: cannot disable Tx channel %d", m_deviceShared.m_channel);
353  }
354  else
355  {
356  qDebug("LimeSDROutput::releaseChannel: Tx channel %d released", m_deviceShared.m_channel);
357  }
358 
359  resumeTxBuddies();
360  resumeRxBuddies();
361 
362  m_channelAcquired = false;
363 }
364 
366 {
367  applySettings(m_settings, true, false);
368 }
369 
371 {
373  return false;
374  }
375 
376  if (m_running) { stop(); }
377 
378  if (!acquireChannel())
379  {
380  return false;
381  }
382 
383  // start / stop streaming is done in the thread.
384 
386  qDebug("LimeSDROutput::start: thread created");
387 
388  applySettings(m_settings, true);
389 
391 
393 
395  m_running = true;
396 
397  return true;
398 }
399 
401 {
402  qDebug("LimeSDROutput::stop");
403 
404  if (m_limeSDROutputThread != 0)
405  {
407  delete m_limeSDROutputThread;
409  }
410 
412  m_running = false;
413 
414  releaseChannel();
415 }
416 
417 QByteArray LimeSDROutput::serialize() const
418 {
419  return m_settings.serialize();
420 }
421 
422 bool LimeSDROutput::deserialize(const QByteArray& data)
423 {
424  bool success = true;
425 
426  if (!m_settings.deserialize(data))
427  {
429  success = false;
430  }
431 
433  m_inputMessageQueue.push(message);
434 
435  if (m_guiMessageQueue)
436  {
438  m_guiMessageQueue->push(messageToGUI);
439  }
440 
441  return success;
442 }
443 
445 {
446  return m_deviceDescription;
447 }
448 
450 {
451  int rate = m_settings.m_devSampleRate;
452  return (rate / (1<<m_settings.m_log2SoftInterp));
453 }
454 
456 {
458 }
459 
460 void LimeSDROutput::setCenterFrequency(qint64 centerFrequency)
461 {
463  settings.m_centerFrequency = centerFrequency - (m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0);
464 
465  MsgConfigureLimeSDR* message = MsgConfigureLimeSDR::create(settings, false);
466  m_inputMessageQueue.push(message);
467 
468  if (m_guiMessageQueue)
469  {
470  MsgConfigureLimeSDR* messageToGUI = MsgConfigureLimeSDR::create(settings, false);
471  m_guiMessageQueue->push(messageToGUI);
472  }
473 }
474 
476 {
477  return m_deviceShared.m_channel;
478 }
479 
480 void LimeSDROutput::getLORange(float& minF, float& maxF) const
481 {
482  lms_range_t range = m_deviceShared.m_deviceParams->m_loRangeTx;
483  minF = range.min;
484  maxF = range.max;
485  qDebug("LimeSDROutput::getLORange: min: %f max: %f", range.min, range.max);
486 }
487 
488 void LimeSDROutput::getSRRange(float& minF, float& maxF) const
489 {
490  lms_range_t range = m_deviceShared.m_deviceParams->m_srRangeTx;
491  minF = range.min;
492  maxF = range.max;
493  qDebug("LimeSDROutput::getSRRange: min: %f max: %f", range.min, range.max);
494 }
495 
496 void LimeSDROutput::getLPRange(float& minF, float& maxF) const
497 {
498  lms_range_t range = m_deviceShared.m_deviceParams->m_lpfRangeTx;
499  minF = range.min;
500  maxF = range.max;
501  qDebug("LimeSDROutput::getLPRange: min: %f max: %f", range.min, range.max);
502 }
503 
505 {
507 }
508 
510 {
513  } else {
515  }
516 }
517 
519 {
520  if (MsgConfigureLimeSDR::match(message))
521  {
522  MsgConfigureLimeSDR& conf = (MsgConfigureLimeSDR&) message;
523  qDebug() << "LimeSDROutput::handleMessage: MsgConfigureLimeSDR";
524 
525  if (!applySettings(conf.getSettings(), conf.getForce()))
526  {
527  qDebug("LimeSDROutput::handleMessage config error");
528  }
529 
530  return true;
531  }
532  else if (MsgStartStop::match(message))
533  {
534  MsgStartStop& cmd = (MsgStartStop&) message;
535  qDebug() << "LimeSDROutput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
536 
537  if (cmd.getStartStop())
538  {
540  {
542  }
543  }
544  else
545  {
547  }
548 
551  }
552 
553  return true;
554  }
556  {
558 
559  if (report.getRxElseTx() && m_running)
560  {
561  double host_Hz;
562  double rf_Hz;
563 
564  if (LMS_GetSampleRate(m_deviceShared.m_deviceParams->getDevice(),
565  LMS_CH_TX,
567  &host_Hz,
568  &rf_Hz) < 0)
569  {
570  qDebug("LimeSDROutput::handleMessage: MsgReportBuddyChange: LMS_GetSampleRate() failed");
571  }
572  else
573  {
574  m_settings.m_devSampleRate = roundf(host_Hz);
575  int hard = roundf(rf_Hz) / m_settings.m_devSampleRate;
576  m_settings.m_log2HardInterp = log2(hard);
577 
578  qDebug() << "LimeSDROutput::handleMessage: MsgReportBuddyChange:"
579  << " host_Hz: " << host_Hz
580  << " rf_Hz: " << rf_Hz
581  << " m_devSampleRate: " << m_settings.m_devSampleRate
582  << " log2Hard: " << hard
583  << " m_log2HardInterp: " << m_settings.m_log2HardInterp;
584  }
585 
586  }
587  else
588  {
592  }
593 
594  if (m_settings.m_ncoEnable) // need to reset NCO after sample rate change
595  {
596  applySettings(m_settings, false, true);
597  }
598 
599  int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
600 
603  m_settings.m_centerFrequency + ncoShift);
605 
608  getMessageQueueToGUI()->push(reportToGUI);
609 
610  return true;
611  }
613  {
615 
616  m_settings.m_extClock = report.getExtClock();
618 
619  if (getMessageQueueToGUI())
620  {
623  getMessageQueueToGUI()->push(reportToGUI);
624  }
625 
626  return true;
627  }
629  {
631 
632  m_settings.m_gpioDir = report.getGPIODir();
633  m_settings.m_gpioPins = report.getGPIOPins();
634 
635  // no GUI for the moment only REST API
636 
637  return true;
638  }
639  else if (MsgGetStreamInfo::match(message))
640  {
641 // qDebug() << "LimeSDROutput::handleMessage: MsgGetStreamInfo";
642  lms_stream_status_t status;
643 
644  if (m_streamId.handle && (LMS_GetStreamStatus(&m_streamId, &status) == 0))
645  {
647  {
649  true, // Success
650  status.active,
651  status.fifoFilledCount,
652  status.fifoSize,
653  status.underrun,
654  status.overrun,
655  status.droppedPackets,
656  status.linkRate,
657  status.timestamp);
659  }
660  }
661  else
662  {
664  {
666  false, // Success
667  false, // status.active,
668  0, // status.fifoFilledCount,
669  16384, // status.fifoSize,
670  0, // status.underrun,
671  0, // status.overrun,
672  0, // status.droppedPackets,
673  0, // status.linkRate,
674  0); // status.timestamp);
676  }
677  }
678 
679  return true;
680  }
681  else if (MsgGetDeviceInfo::match(message))
682  {
683  double temp = 0.0;
684  uint8_t gpioPins = 0;
685 
686  if (m_deviceShared.m_deviceParams->getDevice() && (LMS_GetChipTemperature(m_deviceShared.m_deviceParams->getDevice(), 0, &temp) != 0)) {
687  qDebug("LimeSDROutput::handleMessage: MsgGetDeviceInfo: cannot get temperature");
688  }
689 
692  {
693  if (m_deviceShared.m_deviceParams->getDevice() && (LMS_GPIORead(m_deviceShared.m_deviceParams->getDevice(), &gpioPins, 1) != 0)) {
694  qDebug("LimeSDROutput::handleMessage: MsgGetDeviceInfo: cannot get GPIO pins values");
695  }
696  }
697 
698  // send to oneself
699  if (getMessageQueueToGUI())
700  {
702  getMessageQueueToGUI()->push(report);
703  }
704 
705  // send to source buddies
706  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
707  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
708 
709  for (; itSource != sourceBuddies.end(); ++itSource)
710  {
711  if ((*itSource)->getSamplingDeviceGUIMessageQueue())
712  {
714  (*itSource)->getSamplingDeviceGUIMessageQueue()->push(report);
715  }
716  }
717 
718  // send to sink buddies
719  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
720  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
721 
722  for (; itSink != sinkBuddies.end(); ++itSink)
723  {
724  if ((*itSink)->getSamplingDeviceGUIMessageQueue())
725  {
727  (*itSink)->getSamplingDeviceGUIMessageQueue()->push(report);
728  }
729  }
730 
731  return true;
732  }
733  else
734  {
735  return false;
736  }
737 }
738 
739 bool LimeSDROutput::applySettings(const LimeSDROutputSettings& settings, bool force, bool forceNCOFrequency)
740 {
741  bool forwardChangeOwnDSP = false;
742  bool forwardChangeTxDSP = false;
743  bool forwardChangeAllDSP = false;
744  bool forwardClockSource = false;
745  bool forwardGPIOChange = false;
746  bool ownThreadWasRunning = false;
747  bool doCalibration = false;
748  bool doLPCalibration = false;
749  double clockGenFreq = 0.0;
750  QList<QString> reverseAPIKeys;
751 // QMutexLocker mutexLocker(&m_mutex);
752 
753  qint64 deviceCenterFrequency = settings.m_centerFrequency;
754  deviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0;
755  deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency;
756 
757  if (LMS_GetClockFreq(m_deviceShared.m_deviceParams->getDevice(), LMS_CLOCK_CGEN, &clockGenFreq) != 0)
758  {
759  qCritical("LimeSDROutput::applySettings: could not get clock gen frequency");
760  }
761  else
762  {
763  qDebug() << "LimeSDROutput::applySettings: clock gen frequency: " << clockGenFreq;
764  }
765 
766  // apply settings
767 
768  if ((m_settings.m_gain != settings.m_gain) || force)
769  {
770  reverseAPIKeys.append("gain");
771 
773  {
774  if (LMS_SetGaindB(m_deviceShared.m_deviceParams->getDevice(),
775  LMS_CH_TX,
777  settings.m_gain) < 0)
778  {
779  qDebug("LimeSDROutput::applySettings: LMS_SetGaindB() failed");
780  }
781  else
782  {
783  doCalibration = true;
784  qDebug() << "LimeSDROutput::applySettings: Gain set to " << settings.m_gain;
785  }
786  }
787  }
788 
789  if ((m_settings.m_devSampleRate != settings.m_devSampleRate)
790  || (m_settings.m_log2HardInterp != settings.m_log2HardInterp) || force)
791  {
792  reverseAPIKeys.append("devSampleRate");
793  reverseAPIKeys.append("log2HardInterp");
794  forwardChangeAllDSP = true; //m_settings.m_devSampleRate != settings.m_devSampleRate;
795 
797  {
798  if (LMS_SetSampleRateDir(m_deviceShared.m_deviceParams->getDevice(),
799  LMS_CH_TX,
800  settings.m_devSampleRate,
801  1<<settings.m_log2HardInterp) < 0)
802  {
803  qCritical("LimeSDROutput::applySettings: could not set sample rate to %d with oversampling of %d",
804  settings.m_devSampleRate,
805  1<<settings.m_log2HardInterp);
806  }
807  else
808  {
811  //doCalibration = true;
812  forceNCOFrequency = true;
813  qDebug("LimeSDROutput::applySettings: set sample rate set to %d with oversampling of %d",
814  settings.m_devSampleRate,
815  1<<settings.m_log2HardInterp);
816  }
817  }
818  }
819 
820  if ((m_settings.m_devSampleRate != settings.m_devSampleRate)
821  || (m_settings.m_log2SoftInterp != settings.m_log2SoftInterp) || force)
822  {
823  reverseAPIKeys.append("devSampleRate");
824  reverseAPIKeys.append("log2SoftInterp");
825 
826  int fifoSize = (std::max)(
829  qDebug("LimeSDROutput::applySettings: resize FIFO: %d", fifoSize);
830  m_sampleSourceFifo.resize(fifoSize);
831  }
832 
833  if ((m_settings.m_lpfBW != settings.m_lpfBW) || force)
834  {
835  reverseAPIKeys.append("lpfBW");
836 
838  {
839  doLPCalibration = true;
840  }
841  }
842 
843  if ((m_settings.m_lpfFIRBW != settings.m_lpfFIRBW) ||
844  (m_settings.m_lpfFIREnable != settings.m_lpfFIREnable) || force)
845  {
846  reverseAPIKeys.append("lpfFIRBW");
847  reverseAPIKeys.append("lpfFIREnable");
848 
850  {
851  if (LMS_SetGFIRLPF(m_deviceShared.m_deviceParams->getDevice(),
852  LMS_CH_TX,
854  settings.m_lpfFIREnable,
855  settings.m_lpfFIRBW) < 0)
856  {
857  qCritical("LimeSDROutput::applySettings: could %s and set LPF FIR to %f Hz",
858  settings.m_lpfFIREnable ? "enable" : "disable",
859  settings.m_lpfFIRBW);
860  }
861  else
862  {
863  //doCalibration = true;
864  qDebug("LimeSDROutput::applySettings: %sd and set LPF FIR to %f Hz",
865  settings.m_lpfFIREnable ? "enable" : "disable",
866  settings.m_lpfFIRBW);
867  }
868  }
869  }
870 
871  if ((m_settings.m_ncoFrequency != settings.m_ncoFrequency) ||
872  (m_settings.m_ncoEnable != settings.m_ncoEnable) || force || forceNCOFrequency)
873  {
874  reverseAPIKeys.append("ncoFrequency");
875  reverseAPIKeys.append("ncoEnable");
876  forwardChangeOwnDSP = true;
877 
879  {
881  LMS_CH_TX,
883  settings.m_ncoEnable,
884  settings.m_ncoFrequency))
885  {
886  //doCalibration = true;
887  m_deviceShared.m_ncoFrequency = settings.m_ncoEnable ? settings.m_ncoFrequency : 0; // for buddies
888  qDebug("LimeSDROutput::applySettings: %sd and set NCO to %d Hz",
889  settings.m_ncoEnable ? "enable" : "disable",
890  settings.m_ncoFrequency);
891  }
892  else
893  {
894  qCritical("LimeSDROutput::applySettings: could not %s and set NCO to %d Hz",
895  settings.m_ncoEnable ? "enable" : "disable",
896  settings.m_ncoFrequency);
897  }
898  }
899  }
900 
901  if ((m_settings.m_log2SoftInterp != settings.m_log2SoftInterp) || force)
902  {
903  reverseAPIKeys.append("log2SoftInterp");
904  forwardChangeOwnDSP = true;
905  m_deviceShared.m_log2Soft = settings.m_log2SoftInterp; // for buddies
906 
907  if (m_limeSDROutputThread != 0)
908  {
910  qDebug() << "LimeSDROutput::applySettings: set soft decimation to " << (1<<settings.m_log2SoftInterp);
911  }
912  }
913 
914  if ((m_settings.m_antennaPath != settings.m_antennaPath) || force)
915  {
916  reverseAPIKeys.append("antennaPath");
917 
919  {
922  settings.m_antennaPath))
923  {
924  doCalibration = true;
925  qDebug("LimeSDROutput::applySettings: set antenna path to %d",
926  (int) settings.m_antennaPath);
927  }
928  else
929  {
930  qCritical("LimeSDROutput::applySettings: could not set antenna path to %d",
931  (int) settings.m_antennaPath);
932  }
933  }
934  }
935 
939  || force)
940  {
941  reverseAPIKeys.append("centerFrequency");
942  reverseAPIKeys.append("transverterMode");
943  reverseAPIKeys.append("transverterDeltaFrequency");
944  forwardChangeTxDSP = true;
945 
947  {
948  if (LMS_SetClockFreq(m_deviceShared.m_deviceParams->getDevice(), LMS_CLOCK_SXT, deviceCenterFrequency) < 0)
949  {
950  qCritical("LimeSDROutput::applySettings: could not set frequency to %lld", deviceCenterFrequency);
951  }
952  else
953  {
954  doCalibration = true;
955  m_deviceShared.m_centerFrequency = deviceCenterFrequency; // for buddies
956  qDebug("LimeSDROutput::applySettings: frequency set to %lld", deviceCenterFrequency);
957  }
958  }
959  }
960 
961  if ((m_settings.m_extClock != settings.m_extClock) ||
962  (settings.m_extClock && (m_settings.m_extClockFreq != settings.m_extClockFreq)) || force)
963  {
964  reverseAPIKeys.append("extClock");
965  reverseAPIKeys.append("extClockFreq");
966 
968  settings.m_extClock,
969  settings.m_extClockFreq))
970  {
971  forwardClockSource = true;
972  doCalibration = true;
973  qDebug("LimeSDROutput::applySettings: clock set to %s (Ext: %d Hz)",
974  settings.m_extClock ? "external" : "internal",
975  settings.m_extClockFreq);
976  }
977  else
978  {
979  qCritical("LimeSDROutput::applySettings: could not set clock to %s (Ext: %d Hz)",
980  settings.m_extClock ? "external" : "internal",
981  settings.m_extClockFreq);
982  }
983  }
984 
987  {
988  if ((m_settings.m_gpioDir != settings.m_gpioDir) || force)
989  {
990  reverseAPIKeys.append("gpioDir");
991 
992  if (LMS_GPIODirWrite(m_deviceShared.m_deviceParams->getDevice(), &settings.m_gpioDir, 1) != 0)
993  {
994  qCritical("LimeSDROutput::applySettings: could not set GPIO directions to %u", settings.m_gpioDir);
995  }
996  else
997  {
998  forwardGPIOChange = true;
999  qDebug("LimeSDROutput::applySettings: GPIO directions set to %u", settings.m_gpioDir);
1000  }
1001  }
1002 
1003  if ((m_settings.m_gpioPins != settings.m_gpioPins) || force)
1004  {
1005  reverseAPIKeys.append("gpioPins");
1006 
1007  if (LMS_GPIOWrite(m_deviceShared.m_deviceParams->getDevice(), &settings.m_gpioPins, 1) != 0)
1008  {
1009  qCritical("LimeSDROutput::applySettings: could not set GPIO pins to %u", settings.m_gpioPins);
1010  }
1011  else
1012  {
1013  forwardGPIOChange = true;
1014  qDebug("LimeSDROutput::applySettings: GPIO pins set to %u", settings.m_gpioPins);
1015  }
1016  }
1017  }
1018 
1019  if (settings.m_useReverseAPI)
1020  {
1021  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
1025  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
1026  }
1027 
1028  m_settings = settings;
1029  double clockGenFreqAfter;
1030 
1031  if (LMS_GetClockFreq(m_deviceShared.m_deviceParams->getDevice(), LMS_CLOCK_CGEN, &clockGenFreqAfter) != 0)
1032  {
1033  qCritical("LimeSDROutput::applySettings: could not get clock gen frequency");
1034  }
1035  else
1036  {
1037  qDebug() << "LimeSDROutput::applySettings: clock gen frequency after: " << clockGenFreqAfter;
1038  doCalibration = doCalibration || (clockGenFreqAfter != clockGenFreq);
1039  }
1040 
1041  if ((doCalibration || doLPCalibration) && m_channelAcquired)
1042  {
1044  {
1046  ownThreadWasRunning = true;
1047  }
1048 
1049  suspendRxBuddies();
1050  suspendTxBuddies();
1051 
1052  if (doCalibration)
1053  {
1054  if (LMS_Calibrate(m_deviceShared.m_deviceParams->getDevice(),
1055  LMS_CH_TX,
1058  0) < 0)
1059  {
1060  qCritical("LimeSDROutput::applySettings: calibration failed on Tx channel %d", m_deviceShared.m_channel);
1061  }
1062  else
1063  {
1064  qDebug("LimeSDROutput::applySettings: calibration successful on Tx channel %d", m_deviceShared.m_channel);
1065  }
1066  }
1067 
1068  if (doLPCalibration)
1069  {
1070  if (LMS_SetLPFBW(m_deviceShared.m_deviceParams->getDevice(),
1071  LMS_CH_TX,
1073  m_settings.m_lpfBW) < 0)
1074  {
1075  qCritical("LimeSDROutput::applySettings: could not set LPF to %f Hz", m_settings.m_lpfBW);
1076  }
1077  else
1078  {
1079  qDebug("LimeSDROutput::applySettings: LPF set to %f Hz", m_settings.m_lpfBW);
1080  }
1081  }
1082 
1083  resumeTxBuddies();
1084  resumeRxBuddies();
1085 
1086  if (ownThreadWasRunning) {
1088  }
1089  }
1090 
1091  // forward changes to buddies or oneself
1092 
1093  if (forwardChangeAllDSP)
1094  {
1095  qDebug("LimeSDROutput::applySettings: forward change to all buddies");
1096 
1097  int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
1098 
1099  // send to self first
1102  m_settings.m_centerFrequency + ncoShift);
1104 
1105  // send to sink buddies
1106  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
1107  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
1108 
1109  for (; itSink != sinkBuddies.end(); ++itSink)
1110  {
1113  (*itSink)->getSamplingDeviceInputMessageQueue()->push(report);
1114  }
1115 
1116  // send to source buddies
1117  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
1118  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
1119 
1120  for (; itSource != sourceBuddies.end(); ++itSource)
1121  {
1124  (*itSource)->getSamplingDeviceInputMessageQueue()->push(report);
1125  }
1126  }
1127  else if (forwardChangeTxDSP)
1128  {
1129  qDebug("LimeSDROutput::applySettings: forward change to Tx buddies");
1130 
1131  int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftInterp);
1132  int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
1133 
1134  // send to self first
1135  DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency + ncoShift);
1137 
1138  // send to sink buddies
1139  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
1140  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
1141 
1142  for (; itSink != sinkBuddies.end(); ++itSink)
1143  {
1146  (*itSink)->getSamplingDeviceInputMessageQueue()->push(report);
1147  }
1148  }
1149  else if (forwardChangeOwnDSP)
1150  {
1151  qDebug("LimeSDROutput::applySettings: forward change to self only");
1152 
1153  int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftInterp);
1154  int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
1155  DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency + ncoShift);
1157  }
1158 
1159  if (forwardClockSource)
1160  {
1161  // send to source buddies
1162  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
1163  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
1164 
1165  for (; itSource != sourceBuddies.end(); ++itSource)
1166  {
1169  (*itSource)->getSamplingDeviceInputMessageQueue()->push(report);
1170  }
1171 
1172  // send to sink buddies
1173  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
1174  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
1175 
1176  for (; itSink != sinkBuddies.end(); ++itSink)
1177  {
1180  (*itSink)->getSamplingDeviceInputMessageQueue()->push(report);
1181  }
1182  }
1183 
1184  if (forwardGPIOChange)
1185  {
1186  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
1187  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
1188 
1189  for (; itSource != sourceBuddies.end(); ++itSource)
1190  {
1193  (*itSource)->getSamplingDeviceInputMessageQueue()->push(report);
1194  }
1195 
1196  // send to sink buddies
1197  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
1198  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
1199 
1200  for (; itSink != sinkBuddies.end(); ++itSink)
1201  {
1204  (*itSink)->getSamplingDeviceInputMessageQueue()->push(report);
1205  }
1206  }
1207 
1208  QLocale loc;
1209 
1210  qDebug().noquote() << "LimeSDROutput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz"
1211  << " m_transverterMode: " << m_settings.m_transverterMode
1212  << " m_transverterDeltaFrequency: " << m_settings.m_transverterDeltaFrequency
1213  << " deviceCenterFrequency: " << deviceCenterFrequency
1214  << " device stream sample rate: " << loc.toString(m_settings.m_devSampleRate) << "S/s"
1215  << " sample rate with soft interpolation: " << loc.toString( m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftInterp)) << "S/s"
1216  << " DAC sample rate with hard interpolation: " << loc.toString(m_settings.m_devSampleRate*(1<<m_settings.m_log2HardInterp)) << "S/s"
1217  << " m_log2HardInterp: " << m_settings.m_log2HardInterp
1218  << " m_log2SoftInterp: " << m_settings.m_log2SoftInterp
1219  << " m_gain: " << m_settings.m_gain
1220  << " m_lpfBW: " << loc.toString(static_cast<int>(m_settings.m_lpfBW))
1221  << " m_lpfFIRBW: " << loc.toString(static_cast<int>(m_settings.m_lpfFIRBW))
1222  << " m_lpfFIREnable: " << m_settings.m_lpfFIREnable
1223  << " m_ncoEnable: " << m_settings.m_ncoEnable
1224  << " m_ncoFrequency: " << loc.toString(m_settings.m_ncoFrequency)
1225  << " m_antennaPath: " << m_settings.m_antennaPath
1226  << " m_extClock: " << m_settings.m_extClock
1227  << " m_extClockFreq: " << loc.toString(m_settings.m_extClockFreq)
1228  << " m_gpioDir: " << m_settings.m_gpioDir
1229  << " m_gpioPins: " << m_settings.m_gpioPins
1230  << " force: " << force
1231  << " forceNCOFrequency: " << forceNCOFrequency
1232  << " doCalibration: " << doCalibration
1233  << " doLPCalibration: " << doLPCalibration;
1234 
1235  return true;
1236 }
1237 
1240  QString& errorMessage)
1241 {
1242  (void) errorMessage;
1244  response.getLimeSdrOutputSettings()->init();
1246  return 200;
1247 }
1248 
1250  bool force,
1251  const QStringList& deviceSettingsKeys,
1252  SWGSDRangel::SWGDeviceSettings& response, // query + response
1253  QString& errorMessage)
1254 {
1255  (void) errorMessage;
1256  LimeSDROutputSettings settings = m_settings;
1257 
1258  if (deviceSettingsKeys.contains("antennaPath")) {
1260  }
1261  if (deviceSettingsKeys.contains("centerFrequency")) {
1263  }
1264  if (deviceSettingsKeys.contains("devSampleRate")) {
1266  }
1267  if (deviceSettingsKeys.contains("extClock")) {
1268  settings.m_extClock = response.getLimeSdrOutputSettings()->getExtClock() != 0;
1269  }
1270  if (deviceSettingsKeys.contains("extClockFreq")) {
1271  settings.m_extClockFreq = response.getLimeSdrOutputSettings()->getExtClockFreq();
1272  }
1273  if (deviceSettingsKeys.contains("gain")) {
1274  settings.m_gain = response.getLimeSdrOutputSettings()->getGain();
1275  }
1276  if (deviceSettingsKeys.contains("log2HardInterp")) {
1278  }
1279  if (deviceSettingsKeys.contains("log2SoftInterp")) {
1281  }
1282  if (deviceSettingsKeys.contains("lpfBW")) {
1283  settings.m_lpfBW = response.getLimeSdrOutputSettings()->getLpfBw();
1284  }
1285  if (deviceSettingsKeys.contains("lpfFIREnable")) {
1286  settings.m_lpfFIREnable = response.getLimeSdrOutputSettings()->getLpfFirEnable() != 0;
1287  }
1288  if (deviceSettingsKeys.contains("lpfFIRBW")) {
1289  settings.m_lpfFIRBW = response.getLimeSdrOutputSettings()->getLpfFirbw();
1290  }
1291  if (deviceSettingsKeys.contains("ncoEnable")) {
1292  settings.m_ncoEnable = response.getLimeSdrOutputSettings()->getNcoEnable() != 0;
1293  }
1294  if (deviceSettingsKeys.contains("ncoFrequency")) {
1295  settings.m_ncoFrequency = response.getLimeSdrOutputSettings()->getNcoFrequency();
1296  }
1297  if (deviceSettingsKeys.contains("transverterDeltaFrequency")) {
1299  }
1300  if (deviceSettingsKeys.contains("transverterMode")) {
1301  settings.m_transverterMode = response.getLimeSdrOutputSettings()->getTransverterMode() != 0;
1302  }
1303  if (deviceSettingsKeys.contains("gpioDir")) {
1304  settings.m_gpioDir = response.getLimeSdrOutputSettings()->getGpioDir() & 0xFF;
1305  }
1306  if (deviceSettingsKeys.contains("gpioPins")) {
1307  settings.m_gpioPins = response.getLimeSdrOutputSettings()->getGpioPins() & 0xFF;
1308  }
1309  if (deviceSettingsKeys.contains("useReverseAPI")) {
1310  settings.m_useReverseAPI = response.getLimeSdrOutputSettings()->getUseReverseApi() != 0;
1311  }
1312  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
1314  }
1315  if (deviceSettingsKeys.contains("reverseAPIPort")) {
1317  }
1318  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
1320  }
1321 
1322  MsgConfigureLimeSDR *msg = MsgConfigureLimeSDR::create(settings, force);
1324 
1325  if (m_guiMessageQueue) // forward to GUI if any
1326  {
1327  MsgConfigureLimeSDR *msgToGUI = MsgConfigureLimeSDR::create(settings, force);
1328  m_guiMessageQueue->push(msgToGUI);
1329  }
1330 
1331  webapiFormatDeviceSettings(response, settings);
1332  return 200;
1333 }
1334 
1336  SWGSDRangel::SWGDeviceReport& response,
1337  QString& errorMessage)
1338 {
1339  (void) errorMessage;
1341  response.getLimeSdrOutputReport()->init();
1342  webapiFormatDeviceReport(response);
1343  return 200;
1344 }
1346 {
1347  response.getLimeSdrOutputSettings()->setAntennaPath((int) settings.m_antennaPath);
1350  response.getLimeSdrOutputSettings()->setExtClock(settings.m_extClock ? 1 : 0);
1352  response.getLimeSdrOutputSettings()->setGain(settings.m_gain);
1355  response.getLimeSdrOutputSettings()->setLpfBw(settings.m_lpfBW);
1356  response.getLimeSdrOutputSettings()->setLpfFirEnable(settings.m_lpfFIREnable ? 1 : 0);
1357  response.getLimeSdrOutputSettings()->setLpfFirbw(settings.m_lpfFIRBW);
1358  response.getLimeSdrOutputSettings()->setNcoEnable(settings.m_ncoEnable ? 1 : 0);
1361  response.getLimeSdrOutputSettings()->setTransverterMode(settings.m_transverterMode ? 1 : 0);
1362  response.getLimeSdrOutputSettings()->setGpioDir(settings.m_gpioDir);
1363  response.getLimeSdrOutputSettings()->setGpioPins(settings.m_gpioPins);
1364  response.getLimeSdrOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
1365 
1366  if (response.getLimeSdrOutputSettings()->getReverseApiAddress()) {
1368  } else {
1369  response.getLimeSdrOutputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
1370  }
1371 
1374 }
1375 
1377  SWGSDRangel::SWGDeviceState& response,
1378  QString& errorMessage)
1379 {
1380  (void) errorMessage;
1382  return 200;
1383 }
1384 
1386  bool run,
1387  SWGSDRangel::SWGDeviceState& response,
1388  QString& errorMessage)
1389 {
1390  (void) errorMessage;
1392  MsgStartStop *message = MsgStartStop::create(run);
1393  m_inputMessageQueue.push(message);
1394 
1395  if (m_guiMessageQueue)
1396  {
1397  MsgStartStop *messagetoGui = MsgStartStop::create(run);
1398  m_guiMessageQueue->push(messagetoGui);
1399  }
1400 
1401  return 200;
1402 }
1403 
1405 {
1406  bool success = false;
1407  double temp = 0.0;
1408  uint8_t gpioDir = 0;
1409  uint8_t gpioPins = 0;
1410  lms_stream_status_t status;
1411  status.active = false;
1412  status.fifoFilledCount = 0;
1413  status.fifoSize = 1;
1414  status.underrun = 0;
1415  status.overrun = 0;
1416  status.droppedPackets = 0;
1417  status.linkRate = 0.0;
1418  status.timestamp = 0;
1419 
1420  success = (m_streamId.handle && (LMS_GetStreamStatus(&m_streamId, &status) == 0));
1421 
1422  response.getLimeSdrOutputReport()->setSuccess(success ? 1 : 0);
1423  response.getLimeSdrOutputReport()->setStreamActive(status.active ? 1 : 0);
1424  response.getLimeSdrOutputReport()->setFifoSize(status.fifoSize);
1425  response.getLimeSdrOutputReport()->setFifoFill(status.fifoFilledCount);
1426  response.getLimeSdrOutputReport()->setUnderrunCount(status.underrun);
1427  response.getLimeSdrOutputReport()->setOverrunCount(status.overrun);
1428  response.getLimeSdrOutputReport()->setDroppedPacketsCount(status.droppedPackets);
1429  response.getLimeSdrOutputReport()->setLinkRate(status.linkRate);
1430  response.getLimeSdrOutputReport()->setHwTimestamp(status.timestamp);
1431 
1433  {
1434  LMS_GetChipTemperature(m_deviceShared.m_deviceParams->getDevice(), 0, &temp);
1435  LMS_GPIODirRead(m_deviceShared.m_deviceParams->getDevice(), &gpioDir, 1);
1436  LMS_GPIORead(m_deviceShared.m_deviceParams->getDevice(), &gpioPins, 1);
1437  }
1438 
1439  response.getLimeSdrOutputReport()->setTemperature(temp);
1440  response.getLimeSdrOutputReport()->setGpioDir(gpioDir);
1441  response.getLimeSdrOutputReport()->setGpioPins(gpioPins);
1442 }
1443 
1444 void LimeSDROutput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const LimeSDROutputSettings& settings, bool force)
1445 {
1447  swgDeviceSettings->setDirection(1); // single Tx
1448  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
1449  swgDeviceSettings->setDeviceHwType(new QString("LimeSDR"));
1451  SWGSDRangel::SWGLimeSdrOutputSettings *swgLimeSdrOutputSettings = swgDeviceSettings->getLimeSdrOutputSettings();
1452 
1453  // transfer data that has been modified. When force is on transfer all data except reverse API data
1454 
1455  if (deviceSettingsKeys.contains("antennaPath") || force) {
1456  swgLimeSdrOutputSettings->setAntennaPath((int) settings.m_antennaPath);
1457  }
1458  if (deviceSettingsKeys.contains("centerFrequency") || force) {
1459  swgLimeSdrOutputSettings->setCenterFrequency(settings.m_centerFrequency);
1460  }
1461  if (deviceSettingsKeys.contains("devSampleRate") || force) {
1462  swgLimeSdrOutputSettings->setDevSampleRate(settings.m_devSampleRate);
1463  }
1464  if (deviceSettingsKeys.contains("extClock") || force) {
1465  swgLimeSdrOutputSettings->setExtClock(settings.m_extClock ? 1 : 0);
1466  }
1467  if (deviceSettingsKeys.contains("extClockFreq") || force) {
1468  swgLimeSdrOutputSettings->setExtClockFreq(settings.m_extClockFreq);
1469  }
1470  if (deviceSettingsKeys.contains("gain") || force) {
1471  swgLimeSdrOutputSettings->setGain(settings.m_gain);
1472  }
1473  if (deviceSettingsKeys.contains("log2HardInterp") || force) {
1474  swgLimeSdrOutputSettings->setLog2HardInterp(settings.m_log2HardInterp);
1475  }
1476  if (deviceSettingsKeys.contains("log2SoftInterp") || force) {
1477  swgLimeSdrOutputSettings->setLog2SoftInterp(settings.m_log2SoftInterp);
1478  }
1479  if (deviceSettingsKeys.contains("lpfBW") || force) {
1480  swgLimeSdrOutputSettings->setLpfBw(settings.m_lpfBW);
1481  }
1482  if (deviceSettingsKeys.contains("lpfFIREnable") || force) {
1483  swgLimeSdrOutputSettings->setLpfFirEnable(settings.m_lpfFIREnable ? 1 : 0);
1484  }
1485  if (deviceSettingsKeys.contains("lpfFIRBW") || force) {
1486  swgLimeSdrOutputSettings->setLpfFirbw(settings.m_lpfFIRBW);
1487  }
1488  if (deviceSettingsKeys.contains("ncoEnable") || force) {
1489  swgLimeSdrOutputSettings->setNcoEnable(settings.m_ncoEnable ? 1 : 0);
1490  }
1491  if (deviceSettingsKeys.contains("ncoFrequency") || force) {
1492  swgLimeSdrOutputSettings->setNcoFrequency(settings.m_ncoFrequency);
1493  }
1494  if (deviceSettingsKeys.contains("transverterDeltaFrequency") || force) {
1495  swgLimeSdrOutputSettings->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency);
1496  }
1497  if (deviceSettingsKeys.contains("transverterMode") || force) {
1498  swgLimeSdrOutputSettings->setTransverterMode(settings.m_transverterMode ? 1 : 0);
1499  }
1500  if (deviceSettingsKeys.contains("gpioDir") || force) {
1501  swgLimeSdrOutputSettings->setGpioDir(settings.m_gpioDir & 0xFF);
1502  }
1503  if (deviceSettingsKeys.contains("gpioPins") || force) {
1504  swgLimeSdrOutputSettings->setGpioPins(settings.m_gpioPins & 0xFF);
1505  }
1506 
1507  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
1508  .arg(settings.m_reverseAPIAddress)
1509  .arg(settings.m_reverseAPIPort)
1510  .arg(settings.m_reverseAPIDeviceIndex);
1511  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
1512  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
1513 
1514  QBuffer *buffer=new QBuffer();
1515  buffer->open((QBuffer::ReadWrite));
1516  buffer->write(swgDeviceSettings->asJson().toUtf8());
1517  buffer->seek(0);
1518 
1519  // Always use PATCH to avoid passing reverse API settings
1520  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
1521 
1522  delete swgDeviceSettings;
1523 }
1524 
1526 {
1528  swgDeviceSettings->setDirection(1); // single Tx
1529  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
1530  swgDeviceSettings->setDeviceHwType(new QString("LimeSDR"));
1531 
1532  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
1536  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
1537  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
1538 
1539  QBuffer *buffer=new QBuffer();
1540  buffer->open((QBuffer::ReadWrite));
1541  buffer->write(swgDeviceSettings->asJson().toUtf8());
1542  buffer->seek(0);
1543 
1544  if (start) {
1545  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
1546  } else {
1547  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
1548  }
1549 
1550  delete swgDeviceSettings;
1551 }
1552 
1553 void LimeSDROutput::networkManagerFinished(QNetworkReply *reply)
1554 {
1555  QNetworkReply::NetworkError replyError = reply->error();
1556 
1557  if (replyError)
1558  {
1559  qWarning() << "LimeSDROutput::networkManagerFinished:"
1560  << " error(" << (int) replyError
1561  << "): " << replyError
1562  << ": " << reply->errorString();
1563  return;
1564  }
1565 
1566  QString answer = reply->readAll();
1567  answer.chop(1); // remove last \n
1568  qDebug("LimeSDROutput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
1569 }
LimeSDROutputThread * m_limeSDROutputThread
virtual quint64 getCenterFrequency() const
Center frequency exposed by the sink.
#define LIMESDROUTPUT_BLOCKSIZE
virtual bool isRunning()
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
int m_ncoFrequency
Actual NCO frequency (the resulting frequency with mixing is displayed)
void setLimeSdrOutputReport(SWGLimeSdrOutputReport *lime_sdr_output_report)
int m_channel
logical device channel number (-1 if none)
virtual QByteArray serialize() const
void suspendTxBuddies()
bool m_channelAcquired
void push(Message *message, bool emitSignal=true)
Push message onto queue.
uint32_t getHWLog2Interp() const
void stopDeviceEngine()
Stop the device engine corresponding to the stream type.
Definition: deviceapi.cpp:266
DeviceLimeSDRShared m_deviceShared
void networkManagerFinished(QNetworkReply *reply)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
virtual void setCenterFrequency(qint64 centerFrequency)
static MsgReportBuddyChange * create(int devSampleRate, int log2HardDecimInterp, uint64_t centerFrequency, bool rxElseTx)
void resumeRxBuddies()
const std::vector< DeviceAPI * > & getSinkBuddies() const
Definition: deviceapi.h:166
void setReverseApiAddress(QString *reverse_api_address)
virtual QString asJson() override
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
static bool setTxAntennaPath(lms_device_t *device, std::size_t chan, int path)
SWGLimeSdrOutputSettings * getLimeSdrOutputSettings()
lms_device_t * getDevice()
void resumeTxBuddies()
uint32_t m_extClockFreq
Frequency (Hz) of external clock source.
lms_range_t m_srRangeTx
DAC sample rate range.
void setDroppedPacketsCount(qint32 dropped_packets_count)
uint32_t getDeviceItemIndex() const
Definition: deviceapi.h:129
uint32_t m_nbTxChannels
number of Tx channels (normally 2, we&#39;ll see if we really use it...)
virtual void destroy()
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
static MsgConfigureLimeSDR * create(const LimeSDROutputSettings &settings, bool force)
Definition: limesdroutput.h:47
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
void setLog2SoftInterp(qint32 log2_soft_interp)
void suspendRxBuddies()
void webapiReverseSendStartStop(bool start)
void setLog2Interpolation(unsigned int log2_ioterp)
QNetworkRequest m_networkRequest
void setOriginatorIndex(qint32 originator_index)
int m_log2OvSRTx
log2 of Tx oversampling (0..5)
void setUnderrunCount(qint32 underrun_count)
unsigned int uint32_t
Definition: rtptypes_win.h:46
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
MessageQueue m_inputMessageQueue
Input queue to the sink.
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
DeviceAPI * m_deviceAPI
void getSRRange(float &minF, float &maxF) const
bool applySettings(const LimeSDROutputSettings &settings, bool force=false, bool forceNCOFrequency=false)
std::size_t getChannelIndex()
int getDeviceSetIndex() const
Definition: deviceapi.h:131
void getLPRange(float &minF, float &maxF) const
virtual int getSampleRate() const
Sample rate exposed by the sink.
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
void * getBuddySharedPtr() const
Definition: deviceapi.h:161
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
bool m_threadWasRunning
flag to know if thread needs to be resumed after suspend
unsigned char uint8_t
Definition: rtptypes_win.h:42
void getLORange(float &minF, float &maxF) const
bool deserialize(const QByteArray &data)
static MsgStartStop * create(bool startStop)
Definition: limesdroutput.h:69
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const LimeSDROutputSettings &settings, bool force)
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
void setBuddySharedPtr(void *ptr)
Definition: deviceapi.h:162
bool m_ncoEnable
Enable TSP NCO and mixing.
int32_t i
Definition: decimators.h:244
virtual bool deserialize(const QByteArray &data)
static bool match(const Message *message)
Definition: message.cpp:45
void setTransverterDeltaFrequency(qint64 transverter_delta_frequency)
const LimeSDROutputSettings & getSettings() const
Definition: limesdroutput.h:44
QByteArray serialize() const
static bool setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, bool enable, float frequency)
uint8_t m_gpioPins
GPIO pins to write; LSB first.
void setLimeSdrOutputSettings(SWGLimeSdrOutputSettings *lime_sdr_output_settings)
float m_sampleRate
ADC/DAC sample rate.
static const float m_sampleFifoLengthInSeconds
static const int m_sampleFifoMinSize
lms_range_t m_lpfRangeTx
Low pass filter range information (Tx side)
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
void resize(uint32_t size)
void setLog2HardInterp(qint32 log2_hard_interp)
const QString & getSamplingDeviceSerial() const
Definition: deviceapi.h:121
SWGLimeSdrOutputReport * getLimeSdrOutputReport()
LimeType m_type
Hardware type.
static MsgReportStreamInfo * create(bool success, bool active, uint32_t fifoFilledCount, uint32_t fifoSize, uint32_t underrun, uint32_t overrun, uint32_t droppedPackets, float linkRate, uint64_t timestamp)
virtual bool handleMessage(const Message &message)
uint8_t m_gpioDir
GPIO pin direction LSB first; 0 input, 1 output.
virtual bool start()
bool m_extClock
True if external clock source.
QNetworkAccessManager * m_networkManager
SampleSourceFifo m_sampleSourceFifo
void setReverseApiPort(qint32 reverse_api_port)
bool m_lpfFIREnable
Enable LMS digital lowpass FIR filters.
const std::vector< DeviceAPI * > & getSourceBuddies() const
Definition: deviceapi.h:165
static bool setClockSource(lms_device_t *device, bool extClock, uint32_t extClockFrequency)
uint32_t m_gain
Optimally distributed gain (dB)
float m_lpfBW
LMS amalog lowpass filter bandwidth (Hz)
DeviceLimeSDRParams * m_deviceParams
unique hardware device parameters
float m_lpfFIRBW
LMS digital lowpass FIR filters bandwidth (Hz)
bool open(lms_info_str_t deviceStr)
lms_range_t m_loRangeTx
LO range for Tx.
DeviceLimeSDRParams::LimeType getLimeType() const
void setCenterFrequency(qint64 center_frequency)
MessageQueue * getMessageQueueToGUI()
LimeSDROutputSettings m_settings
ThreadInterface * m_thread
holds the thread address if started else 0
void setDirection(qint32 direction)
void setTransverterMode(qint32 transverter_mode)
virtual const QString & getDeviceDescription() const
static MsgReportGPIOChange * create(uint8_t gpioDir, uint8_t gpioPins)
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
virtual void stop()
lms_stream_t m_streamId
QString m_deviceDescription
virtual ~LimeSDROutput()
T max(const T &x, const T &y)
Definition: framework.h:446
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
void setDeviceHwType(QString *device_hw_type)
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const LimeSDROutputSettings &settings)
MessageQueue * getSamplingDeviceGUIMessageQueue()
Sampling device (ex: single Tx) GUI input message queue.
Definition: deviceapi.cpp:342
static MsgReportClockSourceChange * create(bool extClock, uint32_t m_extClockFreq)
static MsgReportDeviceInfo * create(float temperature, uint8_t gpioPins)