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.
limesdroutputgui.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 <QDebug>
19 #include <QMessageBox>
20 
21 #include "ui_limesdroutputgui.h"
22 #include "gui/colormapper.h"
23 #include "gui/glspectrum.h"
24 #include "gui/crightclickenabler.h"
26 #include "dsp/dspengine.h"
27 #include "dsp/dspcommands.h"
28 #include "device/deviceapi.h"
29 #include "device/deviceuiset.h"
30 #include "limesdroutputgui.h"
31 
32 LimeSDROutputGUI::LimeSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) :
33  QWidget(parent),
34  ui(new Ui::LimeSDROutputGUI),
35  m_deviceUISet(deviceUISet),
36  m_settings(),
37  m_sampleRateMode(true),
38  m_sampleRate(0),
39  m_lastEngineState(DeviceAPI::StNotStarted),
40  m_doApplySettings(true),
41  m_forceSettings(true),
42  m_statusCounter(0),
43  m_deviceStatusCounter(0)
44 {
46 
47  ui->setupUi(this);
48 
49  float minF, maxF;
50 
51  m_limeSDROutput->getLORange(minF, maxF);
52  ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
53  ui->centerFrequency->setValueRange(7, ((uint32_t) minF)/1000, ((uint32_t) maxF)/1000); // frequency dial is in kHz
54 
55  m_limeSDROutput->getSRRange(minF, maxF);
56  ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
57  ui->sampleRate->setValueRange(8, (uint32_t) minF, (uint32_t) maxF);
58 
59  m_limeSDROutput->getLPRange(minF, maxF);
60  ui->lpf->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
61  ui->lpf->setValueRange(6, (minF/1000)+1, maxF/1000);
62 
63  ui->lpFIR->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
64  ui->lpFIR->setValueRange(5, 1U, 56000U);
65 
66  ui->ncoFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
67 
68  ui->channelNumberText->setText(tr("#%1").arg(m_limeSDROutput->getChannelIndex()));
69 
71  {
72  ui->antenna->setItemText(1, "Hi");
73  ui->antenna->setItemText(2, "Lo");
74  }
75  else
76  {
77  ui->antenna->setItemText(1, "Lo");
78  ui->antenna->setItemText(2, "Hi");
79  }
80 
81  ui->hwInterpLabel->setText(QString::fromUtf8("H\u2191"));
82  ui->swInterpLabel->setText(QString::fromUtf8("S\u2191"));
83 
84  connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
85  connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
86  m_statusTimer.start(500);
87 
89 
90  char recFileNameCStr[30];
91  sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceUISet->m_deviceAPI->getDeviceUID());
92 
93  connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
94 
95  CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop);
96  connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
97 
98  sendSettings();
99 }
100 
102 {
103  delete ui;
104 }
105 
107 {
108  delete this;
109 }
110 
111 void LimeSDROutputGUI::setName(const QString& name)
112 {
113  setObjectName(name);
114 }
115 
117 {
118  return objectName();
119 }
120 
122 {
124  displaySettings();
125  sendSettings();
126 }
127 
129 {
131 }
132 
133 void LimeSDROutputGUI::setCenterFrequency(qint64 centerFrequency)
134 {
136  displaySettings();
137  sendSettings();
138 }
139 
140 QByteArray LimeSDROutputGUI::serialize() const
141 {
142  return m_settings.serialize();
143 }
144 
145 bool LimeSDROutputGUI::deserialize(const QByteArray& data)
146 {
147  if (m_settings.deserialize(data))
148  {
149  displaySettings();
150  m_forceSettings = true;
151  sendSettings();
152  return true;
153  }
154  else
155  {
156  resetToDefaults();
157  return false;
158  }
159 }
160 
162 {
163  // values in kHz
164  float minF, maxF;
165  qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0;
166  m_limeSDROutput->getLORange(minF, maxF);
167  qint64 minLimit = minF/1000 + deltaFrequency;
168  qint64 maxLimit = maxF/1000 + deltaFrequency;
169 
170  minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit;
171  maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit;
172 
173  qDebug("LimeSDROutputGUI::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit);
174 
175  ui->centerFrequency->setValueRange(7, minLimit, maxLimit);
176 }
177 
179 {
181  {
183  m_settings = cfg.getSettings();
184  blockApplySettings(true);
185  displaySettings();
186  blockApplySettings(false);
187  return true;
188  }
190  {
194 
195  if (!report.getRxElseTx()) {
197  }
198 
199  blockApplySettings(true);
200  displaySettings();
201  blockApplySettings(false);
202 
203  return true;
204  }
206  {
209  m_settings.m_extClock = report.getExtClock();
210 
211  blockApplySettings(true);
212  ui->extClock->setExternalClockFrequency(m_settings.m_extClockFreq);
213  ui->extClock->setExternalClockActive(m_settings.m_extClock);
214  blockApplySettings(false);
215 
216  return true;
217  }
219  {
221 
222  if (report.getSuccess())
223  {
224  if (report.getActive()) {
225  ui->streamStatusLabel->setStyleSheet("QLabel { background-color : green; }");
226  } else {
227  ui->streamStatusLabel->setStyleSheet("QLabel { background-color : blue; }");
228  }
229 
230  ui->streamLinkRateText->setText(tr("%1 MB/s").arg(QString::number(report.getLinkRate() / 1000000.0f, 'f', 3)));
231 
232  if (report.getUnderrun() > 0) {
233  ui->underrunLabel->setStyleSheet("QLabel { background-color : red; }");
234  } else {
235  ui->underrunLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
236  }
237 
238  if (report.getOverrun() > 0) {
239  ui->overrunLabel->setStyleSheet("QLabel { background-color : red; }");
240  } else {
241  ui->overrunLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
242  }
243 
244  if (report.getDroppedPackets() > 0) {
245  ui->droppedLabel->setStyleSheet("QLabel { background-color : red; }");
246  } else {
247  ui->droppedLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
248  }
249 
250  ui->fifoBar->setMaximum(report.getFifoSize());
251  ui->fifoBar->setValue(report.getFifoFilledCount());
252  ui->fifoBar->setToolTip(tr("FIFO fill %1/%2 samples").arg(QString::number(report.getFifoFilledCount())).arg(QString::number(report.getFifoSize())));
253  }
254  else
255  {
256  ui->streamStatusLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
257  }
258 
259  return true;
260  }
262  {
264  ui->temperatureText->setText(tr("%1C").arg(QString::number(report.getTemperature(), 'f', 0)));
265  ui->gpioText->setText(tr("%1").arg(report.getGPIOPins(), 2, 16, QChar('0')).toUpper());
266  return true;
267  }
268 
269  return false;
270 }
271 
273 {
274  Message* message;
275 
276  while ((message = m_inputMessageQueue.pop()) != 0)
277  {
278  if (DSPSignalNotification::match(*message))
279  {
280  qDebug("LimeSDROutputGUI::handleInputMessages: message: %s", message->getIdentifier());
281  DSPSignalNotification* notif = (DSPSignalNotification*) message;
282  m_sampleRate = notif->getSampleRate();
283  m_deviceCenterFrequency = notif->getCenterFrequency();
284  qDebug("LimeSDROutputGUI::handleInputMessages: DSPSignalNotification: SampleRate: %d, CenterFrequency: %llu", notif->getSampleRate(), notif->getCenterFrequency());
286 
287  delete message;
288  }
290  {
292  m_settings = cfg.getSettings();
293  displaySettings();
294 
295  delete message;
296  }
297  else if (LimeSDROutput::MsgStartStop::match(*message))
298  {
300  blockApplySettings(true);
301  ui->startStop->setChecked(notif.getStartStop());
302  blockApplySettings(false);
303  delete message;
304  }
305  else
306  {
307  if (handleMessage(*message)) {
308  delete message;
309  }
310  }
311  }
312 }
313 
315 {
319 }
320 
322 {
324 
325  if (dacRate < 100000000) {
326  ui->dacRateLabel->setText(tr("%1k").arg(QString::number(dacRate / 1000.0f, 'g', 5)));
327  } else {
328  ui->dacRateLabel->setText(tr("%1M").arg(QString::number(dacRate / 1000000.0f, 'g', 5)));
329  }
330 }
331 
333 {
334  float minF, maxF;
335  m_limeSDROutput->getSRRange(minF, maxF);
336 
337  ui->sampleRate->blockSignals(true);
338 
339  if (m_sampleRateMode)
340  {
341  ui->sampleRateMode->setStyleSheet("QToolButton { background:rgb(60,60,60); }");
342  ui->sampleRateMode->setText("SR");
343  ui->sampleRate->setValueRange(8, (uint32_t) minF, (uint32_t) maxF);
344  ui->sampleRate->setValue(m_settings.m_devSampleRate);
345  ui->sampleRate->setToolTip("Host to device sample rate (S/s)");
346  ui->deviceRateText->setToolTip("Baseband sample rate (S/s)");
348  ui->deviceRateText->setText(tr("%1k").arg(QString::number(basebandSampleRate / 1000.0f, 'g', 5)));
349  }
350  else
351  {
352  ui->sampleRateMode->setStyleSheet("QToolButton { background:rgb(50,50,50); }");
353  ui->sampleRateMode->setText("BB");
354  ui->sampleRate->setValueRange(8, (uint32_t) minF/(1<<m_settings.m_log2SoftInterp), (uint32_t) maxF/(1<<m_settings.m_log2SoftInterp));
355  ui->sampleRate->setValue(m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftInterp));
356  ui->sampleRate->setToolTip("Baseband sample rate (S/s)");
357  ui->deviceRateText->setToolTip("Host to device sample rate (S/s)");
358  ui->deviceRateText->setText(tr("%1k").arg(QString::number(m_settings.m_devSampleRate / 1000.0f, 'g', 5)));
359  }
360 
361  ui->sampleRate->blockSignals(false);
362 }
363 
365 {
366  ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency);
367  ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode);
368 
369  ui->extClock->setExternalClockFrequency(m_settings.m_extClockFreq);
370  ui->extClock->setExternalClockActive(m_settings.m_extClock);
371 
374 
375  ui->hwInterp->setCurrentIndex(m_settings.m_log2HardInterp);
376  ui->swInterp->setCurrentIndex(m_settings.m_log2SoftInterp);
377 
378  updateDACRate();
379 
380  ui->lpf->setValue(m_settings.m_lpfBW / 1000);
381 
382  ui->lpFIREnable->setChecked(m_settings.m_lpfFIREnable);
383  ui->lpFIR->setValue(m_settings.m_lpfFIRBW / 1000);
384 
385  ui->gain->setValue(m_settings.m_gain);
386  ui->gainText->setText(tr("%1dB").arg(m_settings.m_gain));
387 
388  ui->antenna->setCurrentIndex((int) m_settings.m_antennaPath);
389 
390  setNCODisplay();
391 
392  ui->ncoEnable->setChecked(m_settings.m_ncoEnable);
393 }
394 
396 {
397  int ncoHalfRange = (m_settings.m_devSampleRate * (1<<(m_settings.m_log2HardInterp)))/2;
398  ui->ncoFrequency->setValueRange(
399  false,
400  8,
401  -ncoHalfRange,
402  ncoHalfRange);
403 
404  ui->ncoFrequency->blockSignals(true);
405  ui->ncoFrequency->setToolTip(QString("NCO frequency shift in Hz (Range: +/- %1 kHz)").arg(ncoHalfRange/1000));
406  ui->ncoFrequency->setValue(m_settings.m_ncoFrequency);
407  ui->ncoFrequency->blockSignals(false);
408 }
409 
411 {
412  int64_t centerFrequency = m_settings.m_centerFrequency;
413  ui->centerFrequency->setToolTip(QString("Main center frequency in kHz (LO: %1 kHz)").arg(centerFrequency/1000));
414 
415  if (m_settings.m_ncoEnable) {
416  centerFrequency += m_settings.m_ncoFrequency;
417  }
418 
419  ui->centerFrequency->blockSignals(true);
420  ui->centerFrequency->setValue(centerFrequency < 0 ? 0 : (uint64_t) centerFrequency/1000); // kHz
421  ui->centerFrequency->blockSignals(false);
422 }
423 
425 {
426  int64_t centerFrequency = kHzValue*1000;
427 
428  if (m_settings.m_ncoEnable) {
429  centerFrequency -= m_settings.m_ncoFrequency;
430  }
431 
432  m_settings.m_centerFrequency = centerFrequency < 0 ? 0 : (uint64_t) centerFrequency;
433  ui->centerFrequency->setToolTip(QString("Main center frequency in kHz (LO: %1 kHz)").arg(centerFrequency/1000));
434 }
435 
437 {
438  if(!m_updateTimer.isActive())
439  m_updateTimer.start(100);
440 }
441 
443 {
444  if (m_doApplySettings)
445  {
446  qDebug() << "LimeSDROutputGUI::updateHardware";
449  m_forceSettings = false;
450  m_updateTimer.stop();
451  }
452 }
453 
455 {
456  int state = m_deviceUISet->m_deviceAPI->state();
457 
458  if(m_lastEngineState != state)
459  {
460  switch(state)
461  {
463  ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
464  break;
465  case DeviceAPI::StIdle:
466  ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
467  break;
469  ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
470  break;
471  case DeviceAPI::StError:
472  ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
473  QMessageBox::information(this, tr("Message"), m_deviceUISet->m_deviceAPI->errorMessage());
474  break;
475  default:
476  break;
477  }
478 
479  m_lastEngineState = state;
480  }
481 
482  if (m_statusCounter < 1)
483  {
484  m_statusCounter++;
485  }
486  else
487  {
490  m_statusCounter = 0;
491  }
492 
493  if (m_deviceStatusCounter < 10)
494  {
496  }
497  else
498  {
500  {
503  }
504 
506  }
507 }
508 
510 {
511  m_doApplySettings = !block;
512 }
513 
515 {
516  if (m_doApplySettings)
517  {
520  }
521 }
522 
524 {
526  sendSettings();
527 }
528 
530 {
531  m_settings.m_ncoFrequency = value;
533  sendSettings();
534 }
535 
537 {
538  m_settings.m_ncoEnable = checked;
540  sendSettings();
541 }
542 
544 {
545  if (m_sampleRateMode) {
546  m_settings.m_devSampleRate = value;
547  } else {
549  }
550 
551  updateDACRate();
552  setNCODisplay();
553  sendSettings();}
554 
556 {
557  if ((index <0) || (index > 5))
558  return;
560  updateDACRate();
561  setNCODisplay();
562  sendSettings();
563 }
564 
566 {
567  if ((index <0) || (index > 6)) {
568  return;
569  }
570 
573 
574  if (m_sampleRateMode) {
575  m_settings.m_devSampleRate = ui->sampleRate->getValueNew();
576  } else {
577  m_settings.m_devSampleRate = ui->sampleRate->getValueNew() * (1 << m_settings.m_log2SoftInterp);
578  }
579 
580  sendSettings();
581 }
582 
584 {
585  m_settings.m_lpfBW = value * 1000;
586  sendSettings();
587 }
588 
590 {
591  m_settings.m_lpfFIREnable = checked;
592  sendSettings();
593 }
594 
596 {
597  m_settings.m_lpfFIRBW = value * 1000;
598  sendSettings();
599 }
600 
602 {
603  m_settings.m_gain = value;
604  ui->gainText->setText(tr("%1dB").arg(m_settings.m_gain));
605  sendSettings();
606 }
607 
609 {
611  sendSettings();
612 }
613 
615 {
616  m_settings.m_extClock = ui->extClock->getExternalClockActive();
617  m_settings.m_extClockFreq = ui->extClock->getExternalClockFrequency();
618  qDebug("LimeSDROutputGUI::on_extClock_clicked: %u Hz %s", m_settings.m_extClockFreq, m_settings.m_extClock ? "on" : "off");
619  sendSettings();
620 }
621 
623 {
624  m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive();
625  m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency();
626  qDebug("LimeSDRInputGUI::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off");
628  setCenterFrequencySetting(ui->centerFrequency->getValueNew());
629  sendSettings();
630 }
631 
633 {
634  m_sampleRateMode = checked;
636 }
637 
639 {
640  BasicDeviceSettingsDialog dialog(this);
645 
646  dialog.move(p);
647  dialog.exec();
648 
653 
654  sendSettings();
655 }
MessageQueue m_inputMessageQueue
virtual void setCenterFrequency(qint64 centerFrequency)
int m_ncoFrequency
Actual NCO frequency (the resulting frequency with mixing is displayed)
Message * pop()
Pop message from queue.
const QString & getReverseAPIAddress() const
void on_sampleRateMode_toggled(bool checked)
QString getName() const
QByteArray serialize() const
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void setSampleRate(qint32 sampleRate)
Definition: glspectrum.cpp:211
void setName(const QString &name)
void on_gain_valueChanged(int value)
uint getDeviceUID() const
Return the current device engine unique ID.
Definition: deviceapi.cpp:303
quint64 m_deviceCenterFrequency
Center frequency in device.
bool isBuddyLeader() const
Definition: deviceapi.h:163
void setUseReverseAPI(bool useReverseAPI)
uint32_t m_extClockFreq
Frequency (Hz) of external clock source.
void updateSampleRateAndFrequency()
static MsgGetDeviceInfo * create()
void on_lpFIREnable_toggled(bool checked)
virtual bool handleMessage(const Message &message)
static MsgConfigureLimeSDR * create(const LimeSDROutputSettings &settings, bool force)
Definition: limesdroutput.h:47
void on_swInterp_currentIndexChanged(int index)
QString errorMessage()
Last error message from the device engine.
Definition: deviceapi.cpp:290
void on_centerFrequency_changed(quint64 value)
bool deserialize(const QByteArray &data)
DeviceSampleSink * getSampleSink()
Return pointer to the device sample sink (single Tx) or nullptr.
Definition: deviceapi.cpp:222
__int64 int64_t
Definition: rtptypes_win.h:47
unsigned int uint32_t
Definition: rtptypes_win.h:46
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
bool m_sampleRateMode
true: device, false: base band sample rate update mode
GLSpectrum * getSpectrum()
Direct spectrum getter.
Definition: deviceuiset.h:57
engine is before initialization
Definition: deviceapi.h:53
EngineState state() const
Return the state of the device engine corresponding to the stream type.
Definition: deviceapi.cpp:277
void on_lpf_changed(quint64 value)
void getSRRange(float &minF, float &maxF) const
DeviceAPI * m_deviceAPI
Definition: deviceuiset.h:48
std::size_t getChannelIndex()
void getLPRange(float &minF, float &maxF) const
engine is idle
Definition: deviceapi.h:54
MessageQueue * getInputMessageQueue()
void getLORange(float &minF, float &maxF) const
bool deserialize(const QByteArray &data)
static MsgStartStop * create(bool startStop)
Definition: limesdroutput.h:69
void blockApplySettings(bool block)
void on_hwInterp_currentIndexChanged(int index)
bool m_ncoEnable
Enable TSP NCO and mixing.
virtual qint64 getCenterFrequency() const
static bool match(const Message *message)
Definition: message.cpp:45
const LimeSDROutputSettings & getSettings() const
Definition: limesdroutput.h:44
virtual void destroy()
QByteArray serialize() const
LimeSDROutputGUI(DeviceUISet *deviceUISet, QWidget *parent=0)
static MsgGetStreamInfo * create()
Definition: limesdroutput.h:86
DeviceUISet * m_deviceUISet
void on_sampleRate_changed(quint64 value)
void on_lpFIR_changed(quint64 value)
LimeSDROutput * m_limeSDROutput
Same object as above but gives easy access to LimeSDROutput methods and attributes that are used inte...
bool m_extClock
True if external clock source.
void on_startStop_toggled(bool checked)
void setCenterFrequency(qint64 frequency)
Definition: glspectrum.cpp:175
virtual const char * getIdentifier() const
Definition: message.cpp:35
bool m_lpfFIREnable
Enable LMS digital lowpass FIR filters.
void setReverseAPIAddress(const QString &address)
LimeSDROutputSettings m_settings
void openDeviceSettingsDialog(const QPoint &p)
uint32_t m_gain
Optimally distributed gain (dB)
void setReverseAPIDeviceIndex(uint16_t deviceIndex)
float m_lpfBW
LMS amalog lowpass filter bandwidth (Hz)
void on_ncoEnable_toggled(bool checked)
engine is running
Definition: deviceapi.h:56
float m_lpfFIRBW
LMS digital lowpass FIR filters bandwidth (Hz)
DeviceLimeSDRParams::LimeType getLimeType() const
Ui::LimeSDROutputGUI * ui
void on_ncoFrequency_changed(qint64 value)
void on_antenna_currentIndexChanged(int index)
engine is in error
Definition: deviceapi.h:57
void setCenterFrequencySetting(uint64_t kHzValue)
unsigned __int64 uint64_t
Definition: rtptypes_win.h:48