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.
xtrxinput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2017, 2018 Edouard Griffiths, F4EXB //
3 // Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
4 // //
5 // This program is free software; you can redistribute it and/or modify //
6 // it under the terms of the GNU General Public License as published by //
7 // the Free Software Foundation as version 3 of the License, or //
8 // (at your option) any later version. //
9 // //
10 // This program is distributed in the hope that it will be useful, //
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
13 // GNU General Public License V3 for more details. //
14 // //
15 // You should have received a copy of the GNU General Public License //
16 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
18 #include <cstddef>
19 #include <string.h>
20 #include "xtrx_api.h"
21 
22 #include <QMutexLocker>
23 #include <QDebug>
24 #include <QNetworkReply>
25 #include <QBuffer>
26 
27 #include "SWGDeviceSettings.h"
28 #include "SWGXtrxInputSettings.h"
29 #include "SWGDeviceState.h"
30 #include "SWGDeviceReport.h"
31 #include "SWGXtrxInputReport.h"
32 
33 #include "device/deviceapi.h"
34 #include "dsp/dspcommands.h"
35 #include "dsp/filerecord.h"
36 #include "xtrxinput.h"
37 #include "xtrxinputthread.h"
38 #include "xtrx/devicextrxparam.h"
39 #include "xtrx/devicextrxshared.h"
40 #include "xtrx/devicextrx.h"
41 
49 
51  m_deviceAPI(deviceAPI),
52  m_settings(),
53  m_XTRXInputThread(0),
54  m_deviceDescription("XTRXInput"),
55  m_running(false)
56 {
57  openDevice();
58 
59  m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
60  m_deviceAPI->setNbSourceStreams(1);
61  m_deviceAPI->addAncillarySink(m_fileSink);
62 
63  m_networkManager = new QNetworkAccessManager();
64  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
65 }
66 
68 {
69  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
70  delete m_networkManager;
71 
72  if (m_running) {
73  stop();
74  }
75 
77  delete m_fileSink;
78  closeDevice();
79 }
80 
82 {
83  delete this;
84 }
85 
87 {
88  if (!m_sampleFifo.setSize(96000 * 4))
89  {
90  qCritical("XTRXInput::openDevice: could not allocate SampleFifo");
91  return false;
92  }
93  else
94  {
95  qDebug("XTRXInput::openDevice: allocated SampleFifo");
96  }
97 
98  // look for Rx buddies and get reference to the device object
99  if (m_deviceAPI->getSourceBuddies().size() > 0) // look source sibling first
100  {
101  qDebug("XTRXInput::openDevice: look in Rx buddies");
102 
103  DeviceAPI *sourceBuddy = m_deviceAPI->getSourceBuddies()[0];
104  DeviceXTRXShared *deviceXTRXShared = (DeviceXTRXShared*) sourceBuddy->getBuddySharedPtr();
105 
106  if (deviceXTRXShared == 0)
107  {
108  qCritical("XTRXInput::openDevice: the source buddy shared pointer is null");
109  return false;
110  }
111 
112  DeviceXTRX *device = deviceXTRXShared->m_dev;
113 
114  if (device == 0)
115  {
116  qCritical("XTRXInput::openDevice: cannot get device pointer from Rx buddy");
117  return false;
118  }
119 
120  m_deviceShared.m_dev = device;
121  }
122  // look for Tx buddies and get reference to the device object
123  else if (m_deviceAPI->getSinkBuddies().size() > 0) // then sink
124  {
125  qDebug("XTRXInput::openDevice: look in Tx buddies");
126 
127  DeviceAPI *sinkBuddy = m_deviceAPI->getSinkBuddies()[0];
128  DeviceXTRXShared *deviceXTRXShared = (DeviceXTRXShared*) sinkBuddy->getBuddySharedPtr();
129 
130  if (deviceXTRXShared == 0)
131  {
132  qCritical("XTRXInput::openDevice: the sink buddy shared pointer is null");
133  return false;
134  }
135 
136  DeviceXTRX *device = deviceXTRXShared->m_dev;
137 
138  if (device == 0)
139  {
140  qCritical("XTRXInput::openDevice: cannot get device pointer from Tx buddy");
141  return false;
142  }
143 
144  m_deviceShared.m_dev = device;
145  }
146  // There are no buddies then create the first BladeRF2 device
147  else
148  {
149  qDebug("XTRXInput::openDevice: open device here");
150 
152  char serial[256];
153  strcpy(serial, qPrintable(m_deviceAPI->getSamplingDeviceSerial()));
154 
155  if (!m_deviceShared.m_dev->open(serial))
156  {
157  qCritical("XTRXInput::openDevice: cannot open BladeRF2 device");
158  return false;
159  }
160  }
161 
162  m_deviceShared.m_channel = m_deviceAPI->getDeviceItemIndex(); // publicly allocate channel
163  m_deviceShared.m_source = this;
164  m_deviceAPI->setBuddySharedPtr(&m_deviceShared); // propagate common parameters to API
165  return true;
166 }
167 
169 {
170  if (m_deviceShared.m_dev == 0) { // was never open
171  return;
172  }
173 
174  if (m_running) {
175  stop();
176  }
177 
178  if (m_XTRXInputThread) { // stills own the thread => transfer to a buddy
180  }
181 
182  m_deviceShared.m_channel = -1; // publicly release channel
184 
185  // No buddies so effectively close the device
186 
187  if ((m_deviceAPI->getSinkBuddies().size() == 0) && (m_deviceAPI->getSourceBuddies().size() == 0))
188  {
190  delete m_deviceShared.m_dev;
191  m_deviceShared.m_dev = 0;
192  }
193 }
194 
196 {
197  applySettings(m_settings, true, false);
198 }
199 
201 {
202  if (m_XTRXInputThread == 0) // this does not own the thread
203  {
204  XTRXInputThread *xtrxInputThread = 0;
205 
206  // find a buddy that has allocated the thread
207  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
208  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
209 
210  for (; it != sourceBuddies.end(); ++it)
211  {
212  XTRXInput *buddySource = ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source;
213 
214  if (buddySource)
215  {
216  xtrxInputThread = buddySource->getThread();
217 
218  if (xtrxInputThread) {
219  break;
220  }
221  }
222  }
223 
224  return xtrxInputThread;
225  }
226  else
227  {
228  return m_XTRXInputThread; // own thread
229  }
230 }
231 
233 {
234  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
235  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
236 
237  for (; it != sourceBuddies.end(); ++it)
238  {
239  XTRXInput *buddySource = ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source;
240 
241  if (buddySource)
242  {
243  buddySource->setThread(m_XTRXInputThread);
244  m_XTRXInputThread = 0; // zero for others
245  }
246  }
247 }
248 
250 {
251  // There is a single thread per physical device (Rx side). This thread is unique and referenced by a unique
252  // buddy in the group of source buddies associated with this physical device.
253  //
254  // This start method is responsible for managing the thread when the streaming of a Rx channel is started
255  //
256  // It checks the following conditions
257  // - the thread is allocated or not (by itself or one of its buddies). If it is it grabs the thread pointer.
258  // - the requested channel is another channel (one is already streaming).
259  //
260  // The XTRX support library lets you work in two possible modes:
261  // - Single Input (SI) with only one channel streaming. This can be channel 0 or 1 (channels can be swapped - unlike with BladeRF2).
262  // - Multiple Input (MI) with two channels streaming using interleaved samples. It MUST be in this configuration if both channels are
263  // streaming.
264  //
265  // It manages the transition form SI where only one channel is running to the Multiple Input (MI) if the both channels are requested.
266  // To perform the transition it stops the thread, deletes it and creates a new one.
267  // It marks the thread as needing start.
268  //
269  // If there is no thread allocated it means we are in SI mode and it creates a new one with the requested channel.
270  // It marks the thread as needing start.
271  //
272  // 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
273  // allocated in the thread and starts the thread.
274 
276  {
277  qDebug("XTRXInput::start: no device object");
278  return false;
279  }
280 
281  int requestedChannel = m_deviceAPI->getDeviceItemIndex();
282  XTRXInputThread *xtrxInputThread = findThread();
283  bool needsStart = false;
284 
285  if (xtrxInputThread) // if thread is already allocated
286  {
287  qDebug("XTRXInput::start: thread is already allocated");
288 
289  unsigned int nbOriginalChannels = xtrxInputThread->getNbChannels();
290 
291  // if one channel is already allocated it must be the other one so we'll end up with both channels
292  // thus we expand by deleting and re-creating the thread
293  if (nbOriginalChannels != 0)
294  {
295  qDebug("XTRXInput::start: expand channels. Re-allocate thread and take ownership");
296 
297  SampleSinkFifo **fifos = new SampleSinkFifo*[2];
298  unsigned int *log2Decims = new unsigned int[2];
299 
300  for (int i = 0; i < 2; i++) // save original FIFO references and data
301  {
302  fifos[i] = xtrxInputThread->getFifo(i);
303  log2Decims[i] = xtrxInputThread->getLog2Decimation(i);
304  }
305 
306  xtrxInputThread->stopWork();
307  delete xtrxInputThread;
308  xtrxInputThread = new XTRXInputThread(m_deviceShared.m_dev->getDevice(), 2); // MI mode (2 channels)
309  m_XTRXInputThread = xtrxInputThread; // take ownership
310  m_deviceShared.m_thread = xtrxInputThread;
311 
312  for (int i = 0; i < 2; i++) // restore original FIFO references
313  {
314  xtrxInputThread->setFifo(i, fifos[i]);
315  xtrxInputThread->setLog2Decimation(i, log2Decims[i]);
316  }
317 
318  // remove old thread address from buddies (reset in all buddies). The address being held only in the owning source.
319  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
320  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
321 
322  for (; it != sourceBuddies.end(); ++it)
323  {
324  ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0);
325  ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_thread = 0;
326  }
327 
328  // was used as temporary storage:
329  delete[] fifos;
330  delete[] log2Decims;
331 
332  needsStart = true;
333  }
334  else
335  {
336  qDebug("XTRXInput::start: keep buddy thread");
337  }
338  }
339  else // first allocation
340  {
341  qDebug("XTRXInput::start: allocate thread and take ownership");
342  xtrxInputThread = new XTRXInputThread(m_deviceShared.m_dev->getDevice(), 1, requestedChannel);
343  m_XTRXInputThread = xtrxInputThread; // take ownership
344  m_deviceShared.m_thread = xtrxInputThread;
345  needsStart = true;
346  }
347 
348  xtrxInputThread->setFifo(requestedChannel, &m_sampleFifo);
349  xtrxInputThread->setLog2Decimation(requestedChannel, m_settings.m_log2SoftDecim);
350 
351  applySettings(m_settings, true);
352 
353  if (needsStart)
354  {
355  qDebug("XTRXInput::start: (re)start thread");
356  xtrxInputThread->startWork();
357  }
358 
359  qDebug("XTRXInput::start: started");
360  m_running = true;
361 
362  return true;
363 }
364 
366 {
367  // This stop method is responsible for managing the thread when the streaming of a Rx channel is stopped
368  //
369  // If the thread is currently managing only one channel (SI mode). The thread can be just stopped and deleted.
370  // Then the channel is closed.
371  //
372  // If the thread is currently managing both channels (MI mode) then we are removing one channel. Thus we must
373  // transition from MI to SI. This transition is handled by stopping the thread, deleting it and creating a new one
374  // managing a single channel.
375 
376  if (!m_running) {
377  return;
378  }
379 
380  int removedChannel = m_deviceAPI->getDeviceItemIndex(); // channel to remove
381  int requestedChannel = removedChannel ^ 1; // channel to keep (opposite channel)
382  XTRXInputThread *xtrxInputThread = findThread();
383 
384  if (xtrxInputThread == 0) { // no thread allocated
385  return;
386  }
387 
388  int nbOriginalChannels = xtrxInputThread->getNbChannels();
389 
390  if (nbOriginalChannels == 1) // SI mode => just stop and delete the thread
391  {
392  qDebug("XTRXInput::stop: SI mode. Just stop and delete the thread");
393  xtrxInputThread->stopWork();
394  delete xtrxInputThread;
395  m_XTRXInputThread = 0;
397 
398  // remove old thread address from buddies (reset in all buddies)
399  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
400  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
401 
402  for (; it != sourceBuddies.end(); ++it)
403  {
404  ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0);
405  ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_thread = 0;
406  }
407  }
408  else if (nbOriginalChannels == 2) // Reduce from MI to SI by deleting and re-creating the thread
409  {
410  qDebug("XTRXInput::stop: MI mode. Reduce by deleting and re-creating the thread");
411  xtrxInputThread->stopWork();
412  delete xtrxInputThread;
413  xtrxInputThread = new XTRXInputThread(m_deviceShared.m_dev->getDevice(), 1, requestedChannel);
414  m_XTRXInputThread = xtrxInputThread; // take ownership
415  m_deviceShared.m_thread = xtrxInputThread;
416 
417  xtrxInputThread->setFifo(requestedChannel, &m_sampleFifo);
418  xtrxInputThread->setLog2Decimation(requestedChannel, m_settings.m_log2SoftDecim);
419 
420  // remove old thread address from buddies (reset in all buddies). The address being held only in the owning source.
421  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
422  std::vector<DeviceAPI*>::const_iterator it = sourceBuddies.begin();
423 
424  for (; it != sourceBuddies.end(); ++it)
425  {
426  ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0);
427  ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_thread = 0;
428  }
429 
430  applySettings(m_settings, true);
431  xtrxInputThread->startWork();
432  }
433 
434  m_running = false;
435 }
436 
438 {
439  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
440  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
441 
442  qDebug("XTRXInput::suspendTxThread (%lu)", sinkBuddies.size());
443 
444  for (; itSink != sinkBuddies.end(); ++itSink)
445  {
446  DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSink)->getBuddySharedPtr();
447 
448  if ((buddySharedPtr->m_thread) && buddySharedPtr->m_thread->isRunning())
449  {
450  buddySharedPtr->m_thread->stopWork();
451  buddySharedPtr->m_threadWasRunning = true;
452  }
453  else
454  {
455  buddySharedPtr->m_threadWasRunning = false;
456  }
457  }
458 }
459 
461 {
462  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
463  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
464 
465  qDebug("XTRXInput::resumeTxThread (%lu)", sinkBuddies.size());
466 
467  for (; itSink != sinkBuddies.end(); ++itSink)
468  {
469  DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSink)->getBuddySharedPtr();
470 
471  if (buddySharedPtr->m_threadWasRunning) {
472  buddySharedPtr->m_thread->startWork();
473  }
474  }
475 }
476 
477 QByteArray XTRXInput::serialize() const
478 {
479  return m_settings.serialize();
480 }
481 
482 bool XTRXInput::deserialize(const QByteArray& data)
483 {
484  bool success = true;
485 
486  if (!m_settings.deserialize(data))
487  {
489  success = false;
490  }
491 
493  m_inputMessageQueue.push(message);
494 
495  if (m_guiMessageQueue)
496  {
498  m_guiMessageQueue->push(messageToGUI);
499  }
500 
501  return success;
502 }
503 
504 const QString& XTRXInput::getDeviceDescription() const
505 {
506  return m_deviceDescription;
507 }
508 
510 {
511  double rate = m_settings.m_devSampleRate;
512 
513  if (m_deviceShared.m_dev) {
515  }
516 
517  return (int)((rate / (1<<m_settings.m_log2SoftDecim)));
518 }
519 
521 {
522  uint32_t devSampleRate = m_settings.m_devSampleRate;
523 
524  if (m_deviceShared.m_dev) {
525  devSampleRate = m_deviceShared.m_dev->getActualInputRate();
526  }
527 
528  return devSampleRate;
529 }
530 
532 {
533  uint32_t log2HardDecim = m_settings.m_log2HardDecim;
534 
536  log2HardDecim = log2(m_deviceShared.m_dev->getClockGen() / m_deviceShared.m_dev->getActualInputRate() / 4);
537  }
538 
539  return log2HardDecim;
540 }
541 
543 {
544  if (m_deviceShared.m_dev) {
545  return m_deviceShared.m_dev->getClockGen();
546  } else {
547  return 0.0;
548  }
549 }
550 
552 {
554 }
555 
556 void XTRXInput::setCenterFrequency(qint64 centerFrequency)
557 {
558  XTRXInputSettings settings = m_settings;
559  settings.m_centerFrequency = centerFrequency - (m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0);
560 
561  MsgConfigureXTRX* message = MsgConfigureXTRX::create(settings, false);
562  m_inputMessageQueue.push(message);
563 
564  if (m_guiMessageQueue)
565  {
566  MsgConfigureXTRX* messageToGUI = MsgConfigureXTRX::create(settings, false);
567  m_guiMessageQueue->push(messageToGUI);
568  }
569 }
570 
572 {
573  return m_deviceShared.m_channel;
574 }
575 
576 void XTRXInput::getLORange(float& minF, float& maxF, float& stepF) const
577 {
578  minF = 29e6;
579  maxF = 3840e6;
580  stepF = 10;
581  qDebug("XTRXInput::getLORange: min: %f max: %f step: %f",
582  minF, maxF, stepF);
583 }
584 
585 void XTRXInput::getSRRange(float& minF, float& maxF, float& stepF) const
586 {
587  minF = 100e3;
588  maxF = 120e6;
589  stepF = 10;
590  qDebug("XTRXInput::getSRRange: min: %f max: %f step: %f",
591  minF, maxF, stepF);
592 }
593 
594 void XTRXInput::getLPRange(float& minF, float& maxF, float& stepF) const
595 {
596  minF = 500e3;
597  maxF = 130e6;
598  stepF = 10;
599  qDebug("XTRXInput::getLPRange: min: %f max: %f step: %f",
600  minF, maxF, stepF);
601 }
602 
603 bool XTRXInput::handleMessage(const Message& message)
604 {
605  if (MsgConfigureXTRX::match(message))
606  {
607  MsgConfigureXTRX& conf = (MsgConfigureXTRX&) message;
608  qDebug() << "XTRXInput::handleMessage: MsgConfigureXTRX";
609 
610  if (!applySettings(conf.getSettings(), conf.getForce()))
611  {
612  qDebug("XTRXInput::handleMessage config error");
613  }
614 
615  return true;
616  }
618  {
620 
621  if (report.getRxElseTx())
622  {
626  }
627  else
628  {
631 
632  qDebug() << "XTRXInput::handleMessage: MsgReportBuddyChange:"
633  << " host_Hz: " << m_deviceShared.m_dev->getActualInputRate()
634  << " adc_Hz: " << m_deviceShared.m_dev->getClockGen() / 4
635  << " m_log2HardDecim: " << m_settings.m_log2HardDecim;
636  }
637 
638  if (m_settings.m_ncoEnable) // need to reset NCO after sample rate change
639  {
640  applySettings(m_settings, false, true);
641  }
642 
643  int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
644 
647  m_settings.m_centerFrequency + ncoShift);
649 
650  if (getMessageQueueToGUI())
651  {
654  getMessageQueueToGUI()->push(reportToGUI);
655  }
656 
657  return true;
658  }
660  {
662 
663  m_settings.m_extClock = report.getExtClock();
665 
666  if (getMessageQueueToGUI())
667  {
670  getMessageQueueToGUI()->push(reportToGUI);
671  }
672 
673  return true;
674  }
675  else if (MsgGetStreamInfo::match(message))
676  {
678  {
679  uint64_t fifolevel = 0;
680 
682  xtrx_val_get(m_deviceShared.m_dev->getDevice(), XTRX_RX, XTRX_CH_AB, XTRX_PERF_LLFIFO, &fifolevel);
683  }
684 
686  true,
687  true,
688  fifolevel,
689  65536);
690 
693  }
694  }
695 
696  return true;
697  }
698  else if (MsgGetDeviceInfo::match(message))
699  {
700  double board_temp = 0.0;
701  bool gps_locked = false;
702 
703  if (!m_deviceShared.m_dev->getDevice() || ((board_temp = m_deviceShared.get_board_temperature() / 256.0) == 0.0)) {
704  qDebug("XTRXInput::handleMessage: MsgGetDeviceInfo: cannot get board temperature");
705  }
706 
707  if (!m_deviceShared.m_dev->getDevice()) {
708  qDebug("XTRXInput::handleMessage: MsgGetDeviceInfo: cannot get GPS lock status");
709  } else {
710  gps_locked = m_deviceShared.get_gps_status();
711  }
712 
713  // send to oneself
715  {
718  }
719 
720  // send to source buddies
721  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
722  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
723 
724  for (; itSource != sourceBuddies.end(); ++itSource)
725  {
726  if ((*itSource)->getSamplingDeviceGUIMessageQueue())
727  {
729  (*itSource)->getSamplingDeviceGUIMessageQueue()->push(report);
730  }
731  }
732 
733  // send to sink buddies
734  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
735  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
736 
737  for (; itSink != sinkBuddies.end(); ++itSink)
738  {
739  if ((*itSink)->getSamplingDeviceGUIMessageQueue())
740  {
742  (*itSink)->getSamplingDeviceGUIMessageQueue()->push(report);
743  }
744  }
745 
746  return true;
747  }
748  else if (MsgFileRecord::match(message))
749  {
750  MsgFileRecord& conf = (MsgFileRecord&) message;
751  qDebug() << "XTRXInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
752 
753  if (conf.getStartStop()) {
755  } else {
757  }
758 
759  return true;
760  }
761  else if (MsgStartStop::match(message))
762  {
763  MsgStartStop& cmd = (MsgStartStop&) message;
764  qDebug() << "XTRXInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
765 
766  if (cmd.getStartStop())
767  {
769  {
771  }
772  }
773  else
774  {
776  }
777 
778  return true;
779  }
780  else
781  {
782  return false;
783  }
784 }
785 
786 static double tia_to_db(unsigned idx)
787 {
788  switch (idx) {
789  case 1: return 12;
790  case 2: return 9;
791  default: return 0;
792  }
793 }
794 
796 {
797  uint32_t lna, tia, pga;
798 
799  DeviceXTRX::getAutoGains(gain, lna, tia, pga);
800 
801  apply_gain_lna(lna);
802  apply_gain_tia(tia_to_db(tia));
803  apply_gain_pga(pga);
804 }
805 
806 void XTRXInput::apply_gain_lna(double gain)
807 {
808  if (xtrx_set_gain(m_deviceShared.m_dev->getDevice(),
809  m_deviceShared.m_channel == 0 ? XTRX_CH_A : XTRX_CH_B,
810  XTRX_RX_LNA_GAIN,
811  gain,
812  0) < 0) {
813  qDebug("XTRXInput::apply_gain_lna: xtrx_set_gain(LNA) failed");
814  } else {
815  qDebug() << "XTRXInput::apply_gain_lna: Gain (LNA) set to " << gain;
816  }
817 }
818 
819 void XTRXInput::apply_gain_tia(double gain)
820 {
821  if (xtrx_set_gain(m_deviceShared.m_dev->getDevice(),
822  m_deviceShared.m_channel == 0 ? XTRX_CH_A : XTRX_CH_B,
823  XTRX_RX_TIA_GAIN,
824  gain,
825  0) < 0) {
826  qDebug("XTRXInput::apply_gain_tia: xtrx_set_gain(TIA) failed");
827  } else {
828  qDebug() << "XTRXInput::apply_gain_tia: Gain (TIA) set to " << gain;
829  }
830 }
831 
832 void XTRXInput::apply_gain_pga(double gain)
833 {
834  if (xtrx_set_gain(m_deviceShared.m_dev->getDevice(),
835  m_deviceShared.m_channel == 0 ? XTRX_CH_A : XTRX_CH_B,
836  XTRX_RX_PGA_GAIN,
837  gain,
838  0) < 0)
839  {
840  qDebug("XTRXInput::apply_gain_pga: xtrx_set_gain(PGA) failed");
841  }
842  else
843  {
844  qDebug() << "XTRXInput::apply_gain_pga: Gain (PGA) set to " << gain;
845  }
846 }
847 
848 bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, bool forceNCOFrequency)
849 {
850  int requestedChannel = m_deviceAPI->getDeviceItemIndex();
851  XTRXInputThread *inputThread = findThread();
852  QList<QString> reverseAPIKeys;
853 
854  bool forwardChangeOwnDSP = false;
855  bool forwardChangeRxDSP = false;
856  bool forwardChangeAllDSP = false;
857  bool forwardClockSource = false;
858  bool rxThreadWasRunning = false;
859  bool doLPCalibration = false;
860  bool doChangeSampleRate = false;
861  bool doChangeFreq = false;
862 
863  bool doGainAuto = false;
864  bool doGainLna = false;
865  bool doGainTia = false;
866  bool doGainPga = false;
867 
868  // apply settings
869 
870  qDebug() << "XTRXInput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz"
871  << " device stream sample rate: " << getDevSampleRate() << "S/s"
872  << " sample rate with soft decimation: " << getSampleRate() << "S/s"
873  << " m_devSampleRate: " << m_settings.m_devSampleRate
874  << " m_dcBlock: " << m_settings.m_dcBlock
875  << " m_iqCorrection: " << m_settings.m_iqCorrection
876  << " m_log2SoftDecim: " << m_settings.m_log2SoftDecim
877  << " m_gain: " << m_settings.m_gain
878  << " m_lpfBW: " << m_settings.m_lpfBW
879  << " m_pwrmode: " << m_settings.m_pwrmode
880  << " m_ncoEnable: " << m_settings.m_ncoEnable
881  << " m_ncoFrequency: " << m_settings.m_ncoFrequency
882  << " m_antennaPath: " << m_settings.m_antennaPath
883  << " m_extClock: " << m_settings.m_extClock
884  << " m_extClockFreq: " << m_settings.m_extClockFreq
885  << " force: " << force
886  << " forceNCOFrequency: " << forceNCOFrequency
887  << " doLPCalibration: " << doLPCalibration;
888 
889  if ((m_settings.m_dcBlock != settings.m_dcBlock) || force)
890  {
891  reverseAPIKeys.append("dcBlock");
893  }
894 
895  if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force)
896  {
897  reverseAPIKeys.append("iqCorrection");
899  }
900 
901  if ((m_settings.m_pwrmode != settings.m_pwrmode))
902  {
903  reverseAPIKeys.append("pwrmode");
904 
905  if (m_deviceShared.m_dev->getDevice() != 0)
906  {
907  if (xtrx_val_set(m_deviceShared.m_dev->getDevice(),
908  XTRX_TRX,
909  m_deviceShared.m_channel == 0 ? XTRX_CH_A : XTRX_CH_B,
910  XTRX_LMS7_PWR_MODE,
911  settings.m_pwrmode) < 0) {
912  qCritical("XTRXInput::applySettings: could not set power mode %d", settings.m_pwrmode);
913  }
914  }
915  }
916 
917  if ((m_settings.m_extClock != settings.m_extClock) || force) {
918  reverseAPIKeys.append("extClock");
919  }
920  if ((m_settings.m_extClockFreq != settings.m_extClockFreq) || force) {
921  reverseAPIKeys.append("extClockFreq");
922  }
923 
924  if ((m_settings.m_extClock != settings.m_extClock)
925  || (settings.m_extClock && (m_settings.m_extClockFreq != settings.m_extClockFreq)) || force)
926  {
927  if (m_deviceShared.m_dev->getDevice() != 0)
928  {
929  xtrx_set_ref_clk(m_deviceShared.m_dev->getDevice(),
930  (settings.m_extClock) ? settings.m_extClockFreq : 0,
931  (settings.m_extClock) ? XTRX_CLKSRC_EXT : XTRX_CLKSRC_INT);
932  {
933  forwardClockSource = true;
934  doChangeSampleRate = true;
935  doChangeFreq = true;
936  qDebug("XTRXInput::applySettings: clock set to %s (Ext: %d Hz)",
937  settings.m_extClock ? "external" : "internal",
938  settings.m_extClockFreq);
939  }
940  }
941  }
942 
943  if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) {
944  reverseAPIKeys.append("devSampleRate");
945  }
946  if ((m_settings.m_log2HardDecim != settings.m_log2HardDecim) || force) {
947  reverseAPIKeys.append("log2HardDecim");
948  }
949 
950  if ((m_settings.m_devSampleRate != settings.m_devSampleRate)
951  || (m_settings.m_log2HardDecim != settings.m_log2HardDecim) || force)
952  {
953  forwardChangeAllDSP = true; //m_settings.m_devSampleRate != settings.m_devSampleRate;
954 
955  if (m_deviceShared.m_dev->getDevice() != 0) {
956  doChangeSampleRate = true;
957  }
958  }
959 
960  if ((m_settings.m_gainMode != settings.m_gainMode) || force) {
961  reverseAPIKeys.append("gainMode");
962  }
963  if ((m_settings.m_gain != settings.m_gain) || force) {
964  reverseAPIKeys.append("gain");
965  }
966  if ((m_settings.m_lnaGain != settings.m_lnaGain) || force) {
967  reverseAPIKeys.append("lnaGain");
968  }
969  if ((m_settings.m_tiaGain != settings.m_tiaGain) || force) {
970  reverseAPIKeys.append("tiaGain");
971  }
972  if ((m_settings.m_pgaGain != settings.m_pgaGain) || force) {
973  reverseAPIKeys.append("pgaGain");
974  }
975 
976  if (m_deviceShared.m_dev->getDevice() != 0)
977  {
978  if ((m_settings.m_gainMode != settings.m_gainMode) || force)
979  {
981  {
982  doGainAuto = true;
983  }
984  else
985  {
986  doGainLna = true;
987  doGainTia = true;
988  doGainPga = true;
989  }
990  }
992  {
993  if (m_settings.m_gain != settings.m_gain) {
994  doGainAuto = true;
995  }
996  }
998  {
999  if (m_settings.m_lnaGain != settings.m_lnaGain) {
1000  doGainLna = true;
1001  }
1002  if (m_settings.m_tiaGain != settings.m_tiaGain) {
1003  doGainTia = true;
1004  }
1005  if (m_settings.m_pgaGain != settings.m_pgaGain) {
1006  doGainPga = true;
1007  }
1008  }
1009  }
1010 
1011  if ((m_settings.m_lpfBW != settings.m_lpfBW) || force)
1012  {
1013  reverseAPIKeys.append("lpfBW");
1014 
1015  if (m_deviceShared.m_dev->getDevice() != 0) {
1016  doLPCalibration = true;
1017  }
1018  }
1019 
1020 #if 0
1021  if ((m_settings.m_lpfFIRBW != settings.m_lpfFIRBW) ||
1022  (m_settings.m_lpfFIREnable != settings.m_lpfFIREnable) || force)
1023  {
1024  if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired)
1025  {
1026  if (LMS_SetGFIRLPF(m_deviceShared.m_deviceParams->getDevice(),
1027  LMS_CH_RX,
1029  settings.m_lpfFIREnable,
1030  settings.m_lpfFIRBW) < 0)
1031  {
1032  qCritical("XTRXInput::applySettings: could %s and set LPF FIR to %f Hz",
1033  settings.m_lpfFIREnable ? "enable" : "disable",
1034  settings.m_lpfFIRBW);
1035  }
1036  else
1037  {
1038  //doCalibration = true;
1039  qDebug("XTRXInput::applySettings: %sd and set LPF FIR to %f Hz",
1040  settings.m_lpfFIREnable ? "enable" : "disable",
1041  settings.m_lpfFIRBW);
1042  }
1043  }
1044  }
1045 #endif
1046 
1047  if ((m_settings.m_log2SoftDecim != settings.m_log2SoftDecim) || force)
1048  {
1049  reverseAPIKeys.append("log2SoftDecim");
1050  forwardChangeOwnDSP = true;
1051 
1052  if (inputThread != 0)
1053  {
1054  inputThread->setLog2Decimation(requestedChannel, settings.m_log2SoftDecim);
1055  qDebug() << "XTRXInput::applySettings: set soft decimation to " << (1<<settings.m_log2SoftDecim);
1056  }
1057  }
1058 
1059  if ((m_settings.m_antennaPath != settings.m_antennaPath) || force)
1060  {
1061  reverseAPIKeys.append("antennaPath");
1062 
1063  if (m_deviceShared.m_dev->getDevice() != 0)
1064  {
1065  if (xtrx_set_antenna(m_deviceShared.m_dev->getDevice(), settings.m_antennaPath) < 0) {
1066  qCritical("XTRXInput::applySettings: could not set antenna path to %d", (int) settings.m_antennaPath);
1067  } else {
1068  qDebug("XTRXInput::applySettings: set antenna path to %d", (int) settings.m_antennaPath);
1069  }
1070  }
1071  }
1072 
1073  if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force)
1074  {
1075  reverseAPIKeys.append("centerFrequency");
1076  doChangeFreq = true;
1077  }
1078 
1079  if ((m_settings.m_ncoFrequency != settings.m_ncoFrequency) || force) {
1080  reverseAPIKeys.append("ncoFrequency");
1081  }
1082  if ((m_settings.m_ncoEnable != settings.m_ncoEnable) || force) {
1083  reverseAPIKeys.append("ncoEnable");
1084  }
1085 
1086  if ((m_settings.m_ncoFrequency != settings.m_ncoFrequency)
1087  || (m_settings.m_ncoEnable != settings.m_ncoEnable) || force)
1088  {
1089  forceNCOFrequency = true;
1090  }
1091 
1092  if (settings.m_useReverseAPI)
1093  {
1094  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
1098  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
1099  }
1100 
1101  m_settings = settings;
1102 
1103  if (doChangeSampleRate)
1104  {
1105  XTRXInputThread *rxThread = findThread();
1106 
1107  if (rxThread && rxThread->isRunning())
1108  {
1109  rxThread->stopWork();
1110  rxThreadWasRunning = true;
1111  }
1112 
1113  suspendTxThread();
1114 
1115  double master = (settings.m_log2HardDecim == 0) ? 0 : (settings.m_devSampleRate * 4 * (1 << settings.m_log2HardDecim));
1116 
1118  master, //(settings.m_devSampleRate<<settings.m_log2HardDecim)*4,
1119  false) < 0)
1120  {
1121  qCritical("XTRXInput::applySettings: could not set sample rate to %f with oversampling of %d",
1122  settings.m_devSampleRate,
1123  1<<settings.m_log2HardDecim);
1124  }
1125  else
1126  {
1127  doChangeFreq = true;
1128  forceNCOFrequency = true;
1129  forwardChangeAllDSP = true;
1130 
1131  qDebug("XTRXInput::applySettings: sample rate set to %f with oversampling of %d",
1133  1 << getLog2HardDecim());
1134  }
1135 
1136  resumeTxThread();
1137 
1138  if (rxThreadWasRunning) {
1139  rxThread->startWork();
1140  }
1141  }
1142 
1143  if (doLPCalibration)
1144  {
1145  if (xtrx_tune_rx_bandwidth(m_deviceShared.m_dev->getDevice(),
1146  m_deviceShared.m_channel == 0 ? XTRX_CH_A : XTRX_CH_B,
1148  0) < 0) {
1149  qCritical("XTRXInput::applySettings: could not set LPF to %f Hz", m_settings.m_lpfBW);
1150  } else {
1151  qDebug("XTRXInput::applySettings: LPF set to %f Hz", m_settings.m_lpfBW);
1152  }
1153  }
1154 
1155  if (doGainAuto)
1156  {
1158  }
1159  if (doGainLna)
1160  {
1162  }
1163  if (doGainTia)
1164  {
1165  apply_gain_tia(tia_to_db(m_settings.m_tiaGain));
1166  }
1167  if (doGainPga)
1168  {
1170  }
1171 
1172  if (doChangeFreq)
1173  {
1174  forwardChangeRxDSP = true;
1175 
1176  if (m_deviceShared.m_dev->getDevice() != 0)
1177  {
1178  if (xtrx_tune(m_deviceShared.m_dev->getDevice(),
1179  XTRX_TUNE_RX_FDD,
1180  settings.m_centerFrequency,
1181  0) < 0) {
1182  qCritical("XTRXInput::applySettings: could not set frequency to %lu", settings.m_centerFrequency);
1183  } else {
1184  //doCalibration = true;
1185  qDebug("XTRXInput::applySettings: frequency set to %lu", settings.m_centerFrequency);
1186  }
1187  }
1188  }
1189 
1190  if (forceNCOFrequency)
1191  {
1192  if (m_deviceShared.m_dev->getDevice() != 0)
1193  {
1194  if (xtrx_tune_ex(m_deviceShared.m_dev->getDevice(),
1195  XTRX_TUNE_BB_RX,
1196  m_deviceShared.m_channel == 0 ? XTRX_CH_A : XTRX_CH_B,
1197  (settings.m_ncoEnable) ? settings.m_ncoFrequency : 0,
1198  NULL) < 0)
1199  {
1200  qCritical("XTRXInput::applySettings: could not %s and set NCO to %d Hz",
1201  settings.m_ncoEnable ? "enable" : "disable",
1202  settings.m_ncoFrequency);
1203  }
1204  else
1205  {
1206  forwardChangeOwnDSP = true;
1207  qDebug("XTRXInput::applySettings: %sd and set NCO to %d Hz",
1208  settings.m_ncoEnable ? "enable" : "disable",
1209  settings.m_ncoFrequency);
1210  }
1211  }
1212  }
1213 
1214  // forward changes to buddies or oneself
1215 
1216  if (forwardChangeAllDSP)
1217  {
1218  qDebug("XTRXInput::applySettings: forward change to all buddies");
1219 
1220  int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
1221 
1222  // send to self first
1225 
1226  if (getMessageQueueToGUI())
1227  {
1229  getMessageQueueToGUI()->push(report);
1230  }
1231 
1232  // send to source buddies
1233  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
1234  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
1235 
1236  for (; itSource != sourceBuddies.end(); ++itSource)
1237  {
1240  (*itSource)->getSamplingDeviceInputMessageQueue()->push(report);
1241  }
1242 
1243  // send to sink buddies
1244  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
1245  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
1246 
1247  for (; itSink != sinkBuddies.end(); ++itSink)
1248  {
1251  (*itSink)->getSamplingDeviceInputMessageQueue()->push(report);
1252  }
1253  }
1254  else if (forwardChangeRxDSP)
1255  {
1256  qDebug("XTRXInput::applySettings: forward change to Rx buddies");
1257 
1258  int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
1259 
1260  // send to self first
1263 
1264  if (getMessageQueueToGUI())
1265  {
1267  getMessageQueueToGUI()->push(report);
1268  }
1269 
1270  // send to source buddies
1271  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
1272  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
1273 
1274  for (; itSource != sourceBuddies.end(); ++itSource)
1275  {
1278  (*itSource)->getSamplingDeviceInputMessageQueue()->push(report);
1279  }
1280  }
1281  else if (forwardChangeOwnDSP)
1282  {
1283  qDebug("XTRXInput::applySettings: forward change to self only");
1284 
1285  int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
1286 
1288  m_fileSink->handleMessage(*notif); // forward to file sink
1290 
1291  if (getMessageQueueToGUI())
1292  {
1294  getMessageQueueToGUI()->push(report);
1295  }
1296  }
1297 
1298  if (forwardClockSource)
1299  {
1300  // send to source buddies
1301  const std::vector<DeviceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
1302  std::vector<DeviceAPI*>::const_iterator itSource = sourceBuddies.begin();
1303 
1304  for (; itSource != sourceBuddies.end(); ++itSource)
1305  {
1308  (*itSource)->getSamplingDeviceInputMessageQueue()->push(report);
1309  }
1310 
1311  // send to sink buddies
1312  const std::vector<DeviceAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
1313  std::vector<DeviceAPI*>::const_iterator itSink = sinkBuddies.begin();
1314 
1315  for (; itSink != sinkBuddies.end(); ++itSink)
1316  {
1319  (*itSink)->getSamplingDeviceInputMessageQueue()->push(report);
1320  }
1321  }
1322 
1323  return true;
1324 }
1325 
1328  QString& errorMessage)
1329 {
1330  (void) errorMessage;
1332  response.getXtrxInputSettings()->init();
1334  return 200;
1335 }
1336 
1338  bool force,
1339  const QStringList& deviceSettingsKeys,
1340  SWGSDRangel::SWGDeviceSettings& response, // query + response
1341  QString& errorMessage)
1342 {
1343  (void) errorMessage;
1344  XTRXInputSettings settings = m_settings;
1345 
1346  if (deviceSettingsKeys.contains("centerFrequency")) {
1348  }
1349  if (deviceSettingsKeys.contains("devSampleRate")) {
1350  settings.m_devSampleRate = response.getXtrxInputSettings()->getDevSampleRate();
1351  }
1352  if (deviceSettingsKeys.contains("log2HardDecim")) {
1353  settings.m_log2HardDecim = response.getXtrxInputSettings()->getLog2HardDecim();
1354  }
1355  if (deviceSettingsKeys.contains("dcBlock")) {
1356  settings.m_dcBlock = response.getXtrxInputSettings()->getDcBlock() != 0;
1357  }
1358  if (deviceSettingsKeys.contains("iqCorrection")) {
1359  settings.m_iqCorrection = response.getXtrxInputSettings()->getIqCorrection() != 0;
1360  }
1361  if (deviceSettingsKeys.contains("log2SoftDecim")) {
1362  settings.m_log2SoftDecim = response.getXtrxInputSettings()->getLog2SoftDecim();
1363  }
1364  if (deviceSettingsKeys.contains("lpfBW")) {
1365  settings.m_lpfBW = response.getXtrxInputSettings()->getLpfBw();
1366  }
1367  if (deviceSettingsKeys.contains("gain")) {
1368  settings.m_gain = response.getXtrxInputSettings()->getGain();
1369  }
1370  if (deviceSettingsKeys.contains("ncoEnable")) {
1371  settings.m_ncoEnable = response.getXtrxInputSettings()->getNcoEnable() != 0;
1372  }
1373  if (deviceSettingsKeys.contains("ncoFrequency")) {
1374  settings.m_ncoFrequency = response.getXtrxInputSettings()->getNcoFrequency();
1375  }
1376  if (deviceSettingsKeys.contains("antennaPath")) {
1377  settings.m_antennaPath = (xtrx_antenna_t) response.getXtrxInputSettings()->getAntennaPath();
1378  }
1379  if (deviceSettingsKeys.contains("gainMode")) {
1381  }
1382  if (deviceSettingsKeys.contains("lnaGain")) {
1383  settings.m_lnaGain = response.getXtrxInputSettings()->getLnaGain();
1384  }
1385  if (deviceSettingsKeys.contains("tiaGain")) {
1386  settings.m_tiaGain = response.getXtrxInputSettings()->getTiaGain();
1387  }
1388  if (deviceSettingsKeys.contains("pgaGain")) {
1389  settings.m_pgaGain = response.getXtrxInputSettings()->getPgaGain();
1390  }
1391  if (deviceSettingsKeys.contains("extClock")) {
1392  settings.m_extClock = response.getXtrxInputSettings()->getExtClock() != 0;
1393  }
1394  if (deviceSettingsKeys.contains("extClockFreq")) {
1395  settings.m_extClockFreq = response.getXtrxInputSettings()->getExtClockFreq();
1396  }
1397  if (deviceSettingsKeys.contains("pwrmode")) {
1398  settings.m_pwrmode = response.getXtrxInputSettings()->getPwrmode();
1399  }
1400  if (deviceSettingsKeys.contains("fileRecordName")) {
1401  settings.m_fileRecordName = *response.getXtrxInputSettings()->getFileRecordName();
1402  }
1403  if (deviceSettingsKeys.contains("useReverseAPI")) {
1404  settings.m_useReverseAPI = response.getXtrxInputSettings()->getUseReverseApi() != 0;
1405  }
1406  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
1408  }
1409  if (deviceSettingsKeys.contains("reverseAPIPort")) {
1410  settings.m_reverseAPIPort = response.getXtrxInputSettings()->getReverseApiPort();
1411  }
1412  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
1414  }
1415 
1416  MsgConfigureXTRX *msg = MsgConfigureXTRX::create(settings, force);
1418 
1419  if (m_guiMessageQueue) // forward to GUI if any
1420  {
1421  MsgConfigureXTRX *msgToGUI = MsgConfigureXTRX::create(settings, force);
1422  m_guiMessageQueue->push(msgToGUI);
1423  }
1424 
1425  webapiFormatDeviceSettings(response, settings);
1426  return 200;
1427 }
1428 
1430 {
1434  response.getXtrxInputSettings()->setDcBlock(settings.m_dcBlock ? 1 : 0);
1435  response.getXtrxInputSettings()->setIqCorrection(settings.m_iqCorrection ? 1 : 0);
1437  response.getXtrxInputSettings()->setLpfBw(settings.m_lpfBW);
1438  response.getXtrxInputSettings()->setGain(settings.m_gain);
1439  response.getXtrxInputSettings()->setNcoEnable(settings.m_ncoEnable ? 1 : 0);
1440  response.getXtrxInputSettings()->setNcoFrequency(settings.m_ncoFrequency);
1441  response.getXtrxInputSettings()->setAntennaPath((int) settings.m_antennaPath);
1442  response.getXtrxInputSettings()->setGainMode((int) settings.m_gainMode);
1443  response.getXtrxInputSettings()->setLnaGain(settings.m_lnaGain);
1444  response.getXtrxInputSettings()->setTiaGain(settings.m_tiaGain);
1445  response.getXtrxInputSettings()->setPgaGain(settings.m_pgaGain);
1446  response.getXtrxInputSettings()->setExtClock(settings.m_extClock ? 1 : 0);
1447  response.getXtrxInputSettings()->setExtClockFreq(settings.m_extClockFreq);
1448  response.getXtrxInputSettings()->setPwrmode(settings.m_pwrmode);
1449 
1450  if (response.getXtrxInputSettings()->getFileRecordName()) {
1451  *response.getXtrxInputSettings()->getFileRecordName() = settings.m_fileRecordName;
1452  } else {
1453  response.getXtrxInputSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
1454  }
1455 
1456  response.getXtrxInputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
1457 
1458  if (response.getXtrxInputSettings()->getReverseApiAddress()) {
1460  } else {
1461  response.getXtrxInputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
1462  }
1463 
1466 }
1467 
1469  SWGSDRangel::SWGDeviceReport& response,
1470  QString& errorMessage)
1471 {
1472  (void) errorMessage;
1474  response.getXtrxInputReport()->init();
1475  webapiFormatDeviceReport(response);
1476  return 200;
1477 }
1478 
1480  SWGSDRangel::SWGDeviceState& response,
1481  QString& errorMessage)
1482 {
1483  (void) errorMessage;
1485  return 200;
1486 }
1487 
1489  bool run,
1490  SWGSDRangel::SWGDeviceState& response,
1491  QString& errorMessage)
1492 {
1493  (void) errorMessage;
1495  MsgStartStop *message = MsgStartStop::create(run);
1496  m_inputMessageQueue.push(message);
1497 
1498  if (m_guiMessageQueue) // forward to GUI if any
1499  {
1500  MsgStartStop *msgToGUI = MsgStartStop::create(run);
1501  m_guiMessageQueue->push(msgToGUI);
1502  }
1503 
1504  return 200;
1505 }
1506 
1508 {
1509  int ret;
1510  bool success = false;
1511  double temp = 0.0;
1512  bool gpsStatus = false;
1513  uint64_t fifolevel = 0;
1514  uint32_t fifosize = 1<<16;
1515 
1517  {
1518  ret = xtrx_val_get(m_deviceShared.m_dev->getDevice(),
1519  XTRX_RX, XTRX_CH_AB, XTRX_PERF_LLFIFO, &fifolevel);
1520  success = (ret >= 0);
1521  temp = m_deviceShared.get_board_temperature() / 256.0;
1522  gpsStatus = m_deviceShared.get_gps_status();
1523  }
1524 
1525  response.getXtrxInputReport()->setSuccess(success ? 1 : 0);
1526  response.getXtrxInputReport()->setFifoSize(fifosize);
1527  response.getXtrxInputReport()->setFifoFill(fifolevel);
1528  response.getXtrxInputReport()->setTemperature(temp);
1529  response.getXtrxInputReport()->setGpsLock(gpsStatus ? 1 : 0);
1530 }
1531 
1532 void XTRXInput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const XTRXInputSettings& settings, bool force)
1533 {
1535  swgDeviceSettings->setDirection(0); // single Rx
1536  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
1537  swgDeviceSettings->setDeviceHwType(new QString("XTRX"));
1538  swgDeviceSettings->setXtrxInputSettings(new SWGSDRangel::SWGXtrxInputSettings());
1539  SWGSDRangel::SWGXtrxInputSettings *swgXtrxInputSettings = swgDeviceSettings->getXtrxInputSettings();
1540 
1541  // transfer data that has been modified. When force is on transfer all data except reverse API data
1542 
1543  if (deviceSettingsKeys.contains("centerFrequency") || force) {
1544  swgXtrxInputSettings->setCenterFrequency(settings.m_centerFrequency);
1545  }
1546  if (deviceSettingsKeys.contains("devSampleRate") || force) {
1547  swgXtrxInputSettings->setDevSampleRate(settings.m_devSampleRate);
1548  }
1549  if (deviceSettingsKeys.contains("log2HardDecim") || force) {
1550  swgXtrxInputSettings->setLog2HardDecim(settings.m_log2HardDecim);
1551  }
1552  if (deviceSettingsKeys.contains("dcBlock") || force) {
1553  swgXtrxInputSettings->setDcBlock(settings.m_dcBlock ? 1 : 0);
1554  }
1555  if (deviceSettingsKeys.contains("iqCorrection") || force) {
1556  swgXtrxInputSettings->setIqCorrection(settings.m_iqCorrection ? 1 : 0);
1557  }
1558  if (deviceSettingsKeys.contains("log2SoftDecim") || force) {
1559  swgXtrxInputSettings->setLog2SoftDecim(settings.m_log2SoftDecim);
1560  }
1561  if (deviceSettingsKeys.contains("ncoEnable") || force) {
1562  swgXtrxInputSettings->setNcoEnable(settings.m_ncoEnable ? 1 : 0);
1563  }
1564  if (deviceSettingsKeys.contains("ncoFrequency") || force) {
1565  swgXtrxInputSettings->setNcoFrequency(settings.m_ncoFrequency);
1566  }
1567  if (deviceSettingsKeys.contains("lpfBW") || force) {
1568  swgXtrxInputSettings->setLpfBw(settings.m_lpfBW);
1569  }
1570  if (deviceSettingsKeys.contains("antennaPath") || force) {
1571  swgXtrxInputSettings->setAntennaPath((int) settings.m_antennaPath);
1572  }
1573  if (deviceSettingsKeys.contains("gainMode") || force) {
1574  swgXtrxInputSettings->setGainMode((int) settings.m_gainMode);
1575  }
1576  if (deviceSettingsKeys.contains("gain") || force) {
1577  swgXtrxInputSettings->setGain(settings.m_gain);
1578  }
1579  if (deviceSettingsKeys.contains("lnaGain") || force) {
1580  swgXtrxInputSettings->setLnaGain(settings.m_lnaGain);
1581  }
1582  if (deviceSettingsKeys.contains("tiaGain") || force) {
1583  swgXtrxInputSettings->setTiaGain(settings.m_tiaGain);
1584  }
1585  if (deviceSettingsKeys.contains("pgaGain") || force) {
1586  swgXtrxInputSettings->setPgaGain(settings.m_pgaGain);
1587  }
1588  if (deviceSettingsKeys.contains("extClock") || force) {
1589  swgXtrxInputSettings->setExtClock(settings.m_extClock ? 1 : 0);
1590  }
1591  if (deviceSettingsKeys.contains("extClockFreq") || force) {
1592  swgXtrxInputSettings->setExtClockFreq(settings.m_extClockFreq);
1593  }
1594  if (deviceSettingsKeys.contains("pwrmode") || force) {
1595  swgXtrxInputSettings->setPwrmode(settings.m_pwrmode);
1596  }
1597  if (deviceSettingsKeys.contains("fileRecordName") || force) {
1598  swgXtrxInputSettings->setFileRecordName(new QString(settings.m_fileRecordName));
1599  }
1600 
1601  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
1602  .arg(settings.m_reverseAPIAddress)
1603  .arg(settings.m_reverseAPIPort)
1604  .arg(settings.m_reverseAPIDeviceIndex);
1605  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
1606  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
1607 
1608  QBuffer *buffer=new QBuffer();
1609  buffer->open((QBuffer::ReadWrite));
1610  buffer->write(swgDeviceSettings->asJson().toUtf8());
1611  buffer->seek(0);
1612 
1613  // Always use PATCH to avoid passing reverse API settings
1614  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
1615 
1616  delete swgDeviceSettings;
1617 }
1618 
1620 {
1622  swgDeviceSettings->setDirection(0); // single Rx
1623  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
1624  swgDeviceSettings->setDeviceHwType(new QString("XTRX"));
1625 
1626  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
1630  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
1631  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
1632 
1633  QBuffer *buffer=new QBuffer();
1634  buffer->open((QBuffer::ReadWrite));
1635  buffer->write(swgDeviceSettings->asJson().toUtf8());
1636  buffer->seek(0);
1637 
1638  if (start) {
1639  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
1640  } else {
1641  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
1642  }
1643 
1644  delete swgDeviceSettings;
1645 }
1646 
1647 void XTRXInput::networkManagerFinished(QNetworkReply *reply)
1648 {
1649  QNetworkReply::NetworkError replyError = reply->error();
1650 
1651  if (replyError)
1652  {
1653  qWarning() << "XTRXInput::networkManagerFinished:"
1654  << " error(" << (int) replyError
1655  << "): " << replyError
1656  << ": " << reply->errorString();
1657  return;
1658  }
1659 
1660  QString answer = reply->readAll();
1661  answer.chop(1); // remove last \n
1662  qDebug("XTRXInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
1663 }
void moveThreadToBuddy()
Definition: xtrxinput.cpp:232
void webapiReverseSendStartStop(bool start)
Definition: xtrxinput.cpp:1619
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
Definition: xtrxinput.cpp:1488
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
virtual const QString & getDeviceDescription() const
Definition: xtrxinput.cpp:504
bool m_extClock
True if external clock source.
virtual void setCenterFrequency(qint64 centerFrequency)
Definition: xtrxinput.cpp:556
virtual quint64 getCenterFrequency() const
Center frequency exposed by the source.
Definition: xtrxinput.cpp:551
uint32_t getLog2HardDecim() const
Definition: xtrxinput.cpp:531
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
Definition: xtrxinput.cpp:1326
void setFileRecordName(QString *file_record_name)
QNetworkAccessManager * m_networkManager
Definition: xtrxinput.h:259
bool m_ncoEnable
Enable TSP NCO and mixing.
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void stopDeviceEngine()
Stop the device engine corresponding to the stream type.
Definition: deviceapi.cpp:266
DeviceAPI * m_deviceAPI
Definition: xtrxinput.h:252
void suspendTxThread()
Definition: xtrxinput.cpp:437
void getLORange(float &minF, float &maxF, float &stepF) const
Definition: xtrxinput.cpp:576
void setXtrxInputSettings(SWGXtrxInputSettings *xtrx_input_settings)
const std::vector< DeviceAPI * > & getSinkBuddies() const
Definition: deviceapi.h:166
bool applySettings(const XTRXInputSettings &settings, bool force=false, bool forceNCOFrequency=false)
Definition: xtrxinput.cpp:848
void startRecording()
Definition: filerecord.cpp:105
static MsgReportClockSourceChange * create(bool extClock, uint32_t m_extClockFreq)
QNetworkRequest m_networkRequest
Definition: xtrxinput.h:260
MessageQueue m_inputMessageQueue
Input queue to the source.
virtual QString asJson() override
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
void getLPRange(float &minF, float &maxF, float &stepF) const
Definition: xtrxinput.cpp:594
double getClockGen() const
Definition: devicextrx.h:38
XTRXInput * m_source
static MsgConfigureXTRX * create(const XTRXInputSettings &settings, bool force)
Definition: xtrxinput.h:49
bool getStartStop() const
Definition: xtrxinput.h:159
uint32_t getDeviceItemIndex() const
Definition: deviceapi.h:129
bool deserialize(const QByteArray &data)
bool m_running
Definition: xtrxinput.h:257
int m_ncoFrequency
Actual NCO frequency (the resulting frequency with mixing is displayed)
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
double set_samplerate(double rate, double master, bool output)
Definition: devicextrx.cpp:95
void setAntennaPath(qint32 antenna_path)
virtual void destroy()
Definition: xtrxinput.cpp:81
double getClockGen() const
Definition: xtrxinput.cpp:542
void setOriginatorIndex(qint32 originator_index)
SampleSinkFifo m_sampleFifo
struct xtrx_dev * getDevice()
Definition: devicextrx.h:35
bool setSize(int size)
MessageQueue * getMessageQueueToGUI()
unsigned int uint32_t
Definition: rtptypes_win.h:46
virtual QByteArray serialize() const
Definition: xtrxinput.cpp:477
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
virtual bool handleMessage(const Message &message)
Processing of a message. Returns true if message has actually been processed.
Definition: filerecord.cpp:128
uint16_t m_reverseAPIDeviceIndex
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
Definition: xtrxinput.cpp:1479
virtual void stopWork()
int getDeviceSetIndex() const
Definition: deviceapi.h:131
bool m_threadWasRunning
flag to know if thread needs to be resumed after suspend
GainMode m_gainMode
Gain mode: auto or manual.
void * getBuddySharedPtr() const
Definition: deviceapi.h:161
void apply_gain_lna(double gain)
Definition: xtrxinput.cpp:806
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
SWGXtrxInputSettings * getXtrxInputSettings()
float m_lpfBW
LMS analog lowpass filter bandwidth (Hz)
uint32_t m_gain
Optimally distributed gain (dB)
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
Definition: xtrxinput.cpp:1337
double getActualInputRate() const
Definition: devicextrx.h:39
uint32_t m_extClockFreq
Frequency (Hz) of external clock source.
bool getStartStop() const
Definition: xtrxinput.h:178
unsigned int getNbChannels() const
QString m_deviceDescription
Definition: xtrxinput.h:256
void setBuddySharedPtr(void *ptr)
Definition: deviceapi.h:162
void stopRecording()
Definition: filerecord.cpp:117
int32_t i
Definition: decimators.h:244
QByteArray serialize() const
virtual bool handleMessage(const Message &message)
Definition: xtrxinput.cpp:603
virtual bool deserialize(const QByteArray &data)
Definition: xtrxinput.cpp:482
void setCenterFrequency(qint64 center_frequency)
double get_board_temperature()
static bool match(const Message *message)
Definition: message.cpp:45
void setFifo(unsigned int channel, SampleSinkFifo *sampleFifo)
DeviceXTRX * m_dev
void setDevSampleRate(qint32 dev_sample_rate)
void removeAncillarySink(BasebandSampleSink *sink, unsigned int index=0)
Removes it.
Definition: deviceapi.cpp:100
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
Definition: xtrxinput.cpp:1468
void setReverseApiPort(qint32 reverse_api_port)
void setExtClockFreq(qint32 ext_clock_freq)
void apply_gain_tia(double gain)
Definition: xtrxinput.cpp:819
void setLog2Decimation(unsigned int channel, unsigned int log2_decim)
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
static MsgReportClockGenChange * create()
Definition: xtrxinput.h:99
virtual int getSampleRate() const
Sample rate exposed by the source.
Definition: xtrxinput.cpp:509
const XTRXInputSettings & getSettings() const
Definition: xtrxinput.h:46
void close()
Definition: devicextrx.cpp:70
int m_channel
allocated channel (-1 if none)
uint32_t m_tiaGain
Manual TIA gain.
void setIqCorrection(qint32 iq_correction)
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
Definition: xtrxinput.cpp:1507
void setThread(XTRXInputThread *thread)
Definition: xtrxinput.h:201
XTRXInputThread * m_XTRXInputThread
Definition: xtrxinput.h:255
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
const QString & getSamplingDeviceSerial() const
Definition: deviceapi.h:121
virtual bool isRunning()
void apply_gain_auto(uint32_t gain)
Definition: xtrxinput.cpp:795
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const XTRXInputSettings &settings, bool force)
Definition: xtrxinput.cpp:1532
bool openDevice()
Definition: xtrxinput.cpp:86
XTRXInputSettings m_settings
Definition: xtrxinput.h:254
unsigned int getLog2Decimation(unsigned int channel) const
XTRXInputThread * getThread()
Definition: xtrxinput.h:200
XTRXInputThread * findThread()
Definition: xtrxinput.cpp:200
void setUseReverseApi(qint32 use_reverse_api)
SampleSinkFifo * getFifo(unsigned int channel)
void closeDevice()
Definition: xtrxinput.cpp:168
void apply_gain_pga(double gain)
Definition: xtrxinput.cpp:832
static MsgReportBuddyChange * create(int devSampleRate, unsigned log2HardDecimInterp, uint64_t centerFrequency, bool rxElseTx)
DeviceXTRXShared m_deviceShared
Definition: xtrxinput.h:258
uint32_t m_lnaGain
Manual LNA gain.
void getSRRange(float &minF, float &maxF, float &stepF) const
Definition: xtrxinput.cpp:585
void setReverseApiAddress(QString *reverse_api_address)
void setXtrxInputReport(SWGXtrxInputReport *xtrx_input_report)
std::size_t getChannelIndex()
Definition: xtrxinput.cpp:571
virtual void stop()
Definition: xtrxinput.cpp:365
SWGXtrxInputReport * getXtrxInputReport()
static MsgStartStop * create(bool startStop)
Definition: xtrxinput.h:161
void setLog2HardDecim(qint32 log2_hard_decim)
const std::vector< DeviceAPI * > & getSourceBuddies() const
Definition: deviceapi.h:165
static MsgReportStreamInfo * create(bool success, bool active, uint32_t fifoFilledCount, uint32_t fifoSize)
Definition: xtrxinput.h:119
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const XTRXInputSettings &settings)
Definition: xtrxinput.cpp:1429
ThreadInterface * m_thread
holds the thread address if started else 0
static void getAutoGains(uint32_t autoGain, uint32_t &lnaGain, uint32_t &tiaGain, uint32_t &pgaGain)
Definition: devicextrx.cpp:79
virtual void startWork()
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
Definition: xtrxinput.cpp:195
void resumeTxThread()
Definition: xtrxinput.cpp:460
virtual ~XTRXInput()
Definition: xtrxinput.cpp:67
uint32_t getDevSampleRate() const
Definition: xtrxinput.cpp:520
void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection, int streamIndex=0)
Configure current device engine DSP corrections (Rx)
Definition: deviceapi.cpp:355
void setTemperature(float temperature)
bool open(const char *deviceStr)
Definition: devicextrx.cpp:54
void setDirection(qint32 direction)
void networkManagerFinished(QNetworkReply *reply)
Definition: xtrxinput.cpp:1647
xtrx_antenna_t m_antennaPath
void setNcoFrequency(qint32 nco_frequency)
void setLog2SoftDecim(qint32 log2_soft_decim)
uint32_t m_pgaGain
Manual PGA gain.
static MsgReportDeviceInfo * create(float temperature, bool gpsLocked)
void setDeviceHwType(QString *device_hw_type)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
virtual bool start()
Definition: xtrxinput.cpp:249
FileRecord * m_fileSink
File sink to record device I/Q output.
Definition: xtrxinput.h:262
MessageQueue * getSamplingDeviceGUIMessageQueue()
Sampling device (ex: single Tx) GUI input message queue.
Definition: deviceapi.cpp:342
unsigned __int64 uint64_t
Definition: rtptypes_win.h:48