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.
plutosdroutputgui.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 <stdio.h>
19 #include <QDebug>
20 #include <QMessageBox>
21 
22 #include "dsp/dspengine.h"
23 #include "dsp/dspcommands.h"
24 #include "gui/glspectrum.h"
25 #include "gui/crightclickenabler.h"
27 #include "device/deviceapi.h"
28 #include "device/deviceuiset.h"
30 #include "plutosdroutput.h"
31 #include "plutosdroutputgui.h"
32 #include "ui_plutosdroutputgui.h"
33 
34 PlutoSDROutputGUI::PlutoSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) :
35  QWidget(parent),
36  ui(new Ui::PlutoSDROutputGUI),
37  m_deviceUISet(deviceUISet),
38  m_settings(),
39  m_sampleRateMode(true),
40  m_forceSettings(true),
41  m_sampleSink(0),
42  m_sampleRate(0),
43  m_deviceCenterFrequency(0),
44  m_lastEngineState(DeviceAPI::StNotStarted),
45  m_doApplySettings(true),
46  m_statusCounter(0)
47 {
49 
50  ui->setupUi(this);
51  ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
53 
54  ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
56 
57  ui->lpf->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
58 
59  quint32 minLimit, maxLimit;
60  ((PlutoSDROutput *) m_sampleSink)->getbbLPRange(minLimit, maxLimit);
61  ui->lpf->setValueRange(5, minLimit/1000, maxLimit/1000);
62 
63  ui->lpFIR->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
64  ui->lpFIR->setValueRange(5, 1U, 56000U); // will be dynamically recalculated
65 
66  ui->swInterpLabel->setText(QString::fromUtf8("S\u2191"));
67  ui->lpFIRInterpolationLabel->setText(QString::fromUtf8("\u2191"));
68 
69  CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop);
70  connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
71 
72  blockApplySettings(true);
74  blockApplySettings(false);
75 
76  connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
77  connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
78  m_statusTimer.start(500);
79 
80  connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
81 }
82 
84 {
85  delete ui;
86 }
87 
89 {
90  delete this;
91 }
92 
93 void PlutoSDROutputGUI::setName(const QString& name)
94 {
95  setObjectName(name);
96 }
97 
99 {
100  return objectName();
101 }
102 
104 {
105 
106 }
107 
109 {
111 }
112 
113 void PlutoSDROutputGUI::setCenterFrequency(qint64 centerFrequency)
114 {
115  m_settings.m_centerFrequency = centerFrequency;
116  displaySettings();
117  sendSettings();
118 }
119 
121 {
122  return m_settings.serialize();
123 }
124 
125 bool PlutoSDROutputGUI::deserialize(const QByteArray& data)
126 {
127  if(m_settings.deserialize(data))
128  {
129  blockApplySettings(true);
130  displaySettings();
131  blockApplySettings(false);
132  sendSettings(true);
133  return true;
134  }
135  else
136  {
137  resetToDefaults();
138  return false;
139  }
140 }
141 
143 {
144  (void) message;
146  {
148  m_settings = cfg.getSettings();
149  blockApplySettings(true);
150  displaySettings();
151  blockApplySettings(false);
152  return true;
153  }
154  else if (DevicePlutoSDRShared::MsgCrossReportToBuddy::match(message)) // message from buddy
155  {
162  blockApplySettings(true);
163  displaySettings();
164  blockApplySettings(false);
165 
166  return true;
167  }
168  else if (PlutoSDROutput::MsgStartStop::match(message))
169  {
171  blockApplySettings(true);
172  ui->startStop->setChecked(notif.getStartStop());
173  blockApplySettings(false);
174  return true;
175  }
176  else
177  {
178  return false;
179  }
180 }
181 
183 {
184  if (m_doApplySettings)
185  {
188  }
189 }
190 
192 {
193  m_settings.m_centerFrequency = value * 1000;
194  sendSettings();
195 }
196 
198 {
199  ui->loPPMText->setText(QString("%1").arg(QString::number(value/10.0, 'f', 1)));
200  m_settings.m_LOppmTenths = value;
201  sendSettings();
202 }
203 
205 {
206  m_settings.m_log2Interp = index > 5 ? 5 : index;
208  m_settings.m_devSampleRate = ui->sampleRate->getValueNew();
209 
210  if (!m_sampleRateMode) {
212  }
213 
214  sendSettings();
215 }
216 
218 {
219  m_settings.m_devSampleRate = value;
220 
221  if (!m_sampleRateMode) {
223  }
224 
225  sendSettings();
226 }
227 
229 {
230  m_settings.m_lpfBW = value * 1000;
231  sendSettings();
232 }
233 
235 {
236  m_settings.m_lpfFIREnable = checked;
237  ui->lpFIRInterpolation->setEnabled(checked);
238  ui->lpFIRGain->setEnabled(checked);
239  sendSettings();
240 }
241 
243 {
244  m_settings.m_lpfFIRBW = value * 1000;
245  sendSettings();
246 }
247 
249 {
250  m_settings.m_lpfFIRlog2Interp = index > 2 ? 2 : index;
252  sendSettings();
253 }
254 
256 {
257  m_settings.m_lpfFIRGain = 6*(index > 1 ? 1 : index) - 6;
258  sendSettings();
259 }
260 
262 {
263  ui->attText->setText(QString("%1 dB").arg(QString::number(value*0.25, 'f', 2)));
264  m_settings.m_att = value;
265  sendSettings();
266 }
267 
269 {
271  sendSettings();
272 }
273 
275 {
276  m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive();
277  m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency();
278  qDebug("PlutoSDROutputGUI::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off");
280  m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000;
281  sendSettings();
282 }
283 
285 {
286  m_sampleRateMode = checked;
288 }
289 
291 {
292  ui->sampleRate->blockSignals(true);
293 
294  if (m_sampleRateMode)
295  {
296  ui->sampleRateMode->setStyleSheet("QToolButton { background:rgb(60,60,60); }");
297  ui->sampleRateMode->setText("SR");
298  ui->sampleRate->setValueRange(8, DevicePlutoSDR::srLowLimitFreq, DevicePlutoSDR::srHighLimitFreq);
299  ui->sampleRate->setValue(m_settings.m_devSampleRate);
300  ui->sampleRate->setToolTip("Host to device sample rate (S/s)");
301  ui->deviceRateText->setToolTip("Baseband sample rate (S/s)");
302  uint32_t basebandSampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2Interp);
303  ui->deviceRateText->setText(tr("%1k").arg(QString::number(basebandSampleRate / 1000.0f, 'g', 5)));
304  }
305  else
306  {
307  ui->sampleRateMode->setStyleSheet("QToolButton { background:rgb(50,50,50); }");
308  ui->sampleRateMode->setText("BB");
310  ui->sampleRate->setValue(m_settings.m_devSampleRate/(1<<m_settings.m_log2Interp));
311  ui->sampleRate->setToolTip("Baseband sample rate (S/s)");
312  ui->deviceRateText->setToolTip("Host to device sample rate (S/s)");
313  ui->deviceRateText->setText(tr("%1k").arg(QString::number(m_settings.m_devSampleRate / 1000.0f, 'g', 5)));
314  }
315 
316  ui->sampleRate->blockSignals(false);
317 }
318 
320 {
321  ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency);
322  ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode);
324  ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
326 
327  ui->loPPM->setValue(m_settings.m_LOppmTenths);
328  ui->loPPMText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1)));
329 
330  ui->swInterp->setCurrentIndex(m_settings.m_log2Interp);
331 
332  ui->lpf->setValue(m_settings.m_lpfBW / 1000);
333 
334  ui->lpFIREnable->setChecked(m_settings.m_lpfFIREnable);
335  ui->lpFIR->setValue(m_settings.m_lpfFIRBW / 1000);
336  ui->lpFIRInterpolation->setCurrentIndex(m_settings.m_lpfFIRlog2Interp);
337  ui->lpFIRGain->setCurrentIndex((m_settings.m_lpfFIRGain + 6)/6);
338  ui->lpFIRInterpolation->setEnabled(m_settings.m_lpfFIREnable);
339  ui->lpFIRGain->setEnabled(m_settings.m_lpfFIREnable);
340 
341  ui->att->setValue(m_settings.m_att);
342  ui->attText->setText(QString("%1 dB").arg(QString::number(m_settings.m_att*0.25, 'f', 2)));
343 
344  ui->antenna->setCurrentIndex((int) m_settings.m_antennaPath);
345 
346  setFIRBWLimits();
348 }
349 
350 void PlutoSDROutputGUI::sendSettings(bool forceSettings)
351 {
352  m_forceSettings = forceSettings;
353  if(!m_updateTimer.isActive()) { m_updateTimer.start(100); }
354 }
355 
357 {
358  if (m_doApplySettings)
359  {
360  qDebug() << "PlutoSDROutputGUI::updateHardware";
363  m_forceSettings = false;
364  m_updateTimer.stop();
365  }
366 }
367 
369 {
370  m_doApplySettings = !block;
371 }
372 
374 {
375  int state = m_deviceUISet->m_deviceAPI->state();
376 
377  if(m_lastEngineState != state)
378  {
379  switch(state)
380  {
382  ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
383  break;
384  case DeviceAPI::StIdle:
385  ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
386  break;
388  ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
389  break;
390  case DeviceAPI::StError:
391  ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
392  QMessageBox::information(this, tr("Message"), m_deviceUISet->m_deviceAPI->errorMessage());
393  break;
394  default:
395  break;
396  }
397 
398  m_lastEngineState = state;
399  }
400 
401  if (m_statusCounter % 2 == 0) // 1s
402  {
403  uint32_t dacRate = ((PlutoSDROutput *) m_sampleSink)->getDACSampleRate();
404 
405  if (dacRate < 100000000) {
406  ui->dacRateLabel->setText(tr("%1k").arg(QString::number(dacRate / 1000.0f, 'g', 5)));
407  } else {
408  ui->dacRateLabel->setText(tr("%1M").arg(QString::number(dacRate / 1000000.0f, 'g', 5)));
409  }
410  }
411 
412  if (m_statusCounter % 4 == 0) // 2s
413  {
414  std::string rssiStr;
415  ((PlutoSDROutput *) m_sampleSink)->getRSSI(rssiStr);
416  ui->rssiText->setText(tr("-%1").arg(QString::fromStdString(rssiStr)));
417  }
418 
419  if (m_statusCounter % 10 == 0) // 5s
420  {
422  ((PlutoSDROutput *) m_sampleSink)->fetchTemperature();
423  }
424 
425  ui->temperatureText->setText(tr("%1C").arg(QString::number(((PlutoSDROutput *) m_sampleSink)->getTemperature(), 'f', 0)));
426  }
427 
428  m_statusCounter++;
429 }
430 
432 {
433  float high = DevicePlutoSDR::firBWHighLimitFactor * ((PlutoSDROutput *) m_sampleSink)->getFIRSampleRate();
434  float low = DevicePlutoSDR::firBWLowLimitFactor * ((PlutoSDROutput *) m_sampleSink)->getFIRSampleRate();
435  ui->lpFIR->setValueRange(5, (int(low)/1000)+1, (int(high)/1000)+1);
436  ui->lpFIR->setValue(m_settings.m_lpfFIRBW/1000);
437 }
438 
440 {
441  uint32_t low = ui->lpFIREnable->isChecked() ? DevicePlutoSDR::srLowLimitFreq / (1<<ui->lpFIRInterpolation->currentIndex()) : DevicePlutoSDR::srLowLimitFreq;
442  ui->sampleRate->setValueRange(8, low, DevicePlutoSDR::srHighLimitFreq);
443  ui->sampleRate->setValue(m_settings.m_devSampleRate);
444 }
445 
447 {
448  qint64 minLimit, maxLimit;
449  // values in kHz
450  qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0;
451  ((PlutoSDROutput *) m_sampleSink)->getLORange(minLimit, maxLimit);
452 
453  minLimit = minLimit/1000 + deltaFrequency;
454  maxLimit = maxLimit/1000 + deltaFrequency;
455 
456  minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit;
457  maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit;
458 
459  qDebug("PlutoSDRInputGui::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit);
460 
461  ui->centerFrequency->setValueRange(7, minLimit, maxLimit);
462 }
463 
465 {
466  Message* message;
467 
468  while ((message = m_inputMessageQueue.pop()) != 0)
469  {
470  qDebug("PlutoSDROutputGUI::handleInputMessages: message: %s", message->getIdentifier());
471 
472  if (DSPSignalNotification::match(*message))
473  {
474  DSPSignalNotification* notif = (DSPSignalNotification*) message;
475  m_sampleRate = notif->getSampleRate();
477  qDebug("PlutoSDROutputGUI::handleInputMessages: DSPSignalNotification: SampleRate: %d, CenterFrequency: %llu", notif->getSampleRate(), notif->getCenterFrequency());
479  setFIRBWLimits();
480 
481  delete message;
482  }
483  else
484  {
485  if (handleMessage(*message))
486  {
487  delete message;
488  }
489  }
490  }
491 }
492 
494 {
498 }
499 
501 {
502  BasicDeviceSettingsDialog dialog(this);
507 
508  dialog.move(p);
509  dialog.exec();
510 
515 
516  sendSettings();
517 }
qint32 m_LOppmTenths
XO correction.
DeviceUISet * m_deviceUISet
virtual void destroy()
Message * pop()
Pop message from queue.
void openDeviceSettingsDialog(const QPoint &p)
const QString & getReverseAPIAddress() const
static const uint32_t srHighLimitFreq
Device sample rate higher limit in S/s.
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void setSampleRate(qint32 sampleRate)
Definition: glspectrum.cpp:211
static const float firBWHighLimitFactor
Factor by which the FIR working sample rate is multiplied to yield bandwidth higher limit...
void on_centerFrequency_changed(quint64 value)
bool isBuddyLeader() const
Definition: deviceapi.h:163
void setUseReverseAPI(bool useReverseAPI)
virtual bool handleMessage(const Message &message)
void on_sampleRateMode_toggled(bool checked)
qint32 m_att
"hardware" attenuation in dB fourths
void sendSettings(bool forceSettings=false)
QString errorMessage()
Last error message from the device engine.
Definition: deviceapi.cpp:290
DeviceSampleSink * getSampleSink()
Return pointer to the device sample sink (single Tx) or nullptr.
Definition: deviceapi.cpp:222
virtual QByteArray serialize() const
void on_swInterp_currentIndexChanged(int index)
unsigned int uint32_t
Definition: rtptypes_win.h:46
static const uint32_t srLowLimitFreq
Device sample rate lower limit in S/s.
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
GLSpectrum * getSpectrum()
Direct spectrum getter.
Definition: deviceuiset.h:57
engine is before initialization
Definition: deviceapi.h:53
qint64 getCenterFrequency() const
Definition: dspcommands.h:329
EngineState state() const
Return the state of the device engine corresponding to the stream type.
Definition: deviceapi.cpp:277
DeviceAPI * m_deviceAPI
Definition: deviceuiset.h:48
engine is idle
Definition: deviceapi.h:54
MessageQueue * getInputMessageQueue()
MessageQueue m_inputMessageQueue
void on_att_valueChanged(int value)
quint32 m_lpfBW
analog lowpass filter bandwidth (Hz)
bool deserialize(const QByteArray &data)
virtual void resetToDefaults()
virtual QString getName() const
static MsgConfigurePlutoSDR * create(const PlutoSDROutputSettings &settings, bool force)
bool m_lpfFIREnable
enable digital lowpass FIR filter
void on_lpFIR_changed(quint64 value)
void on_lpFIRGain_currentIndexChanged(int index)
static bool match(const Message *message)
Definition: message.cpp:45
void on_lpFIREnable_toggled(bool checked)
void on_lpf_changed(quint64 value)
const PlutoSDROutputSettings & getSettings() const
quint32 m_lpfFIRlog2Interp
digital lowpass FIR filter log2 of interpolation factor (0..2)
PlutoSDROutputGUI(DeviceUISet *deviceUISet, QWidget *parent=0)
virtual qint64 getCenterFrequency() const
virtual void setName(const QString &name)
Ui::PlutoSDROutputGUI * ui
quint64 m_devSampleRate
Host interface sample rate.
int getSampleRate() const
Definition: dspcommands.h:328
static const float firBWLowLimitFactor
Factor by which the FIR working sample rate is multiplied to yield bandwidth lower limit...
void setCenterFrequency(qint64 frequency)
Definition: glspectrum.cpp:175
virtual const char * getIdentifier() const
Definition: message.cpp:35
PlutoSDROutputSettings m_settings
void on_loPPM_valueChanged(int value)
void setReverseAPIAddress(const QString &address)
virtual void setCenterFrequency(qint64 centerFrequency)
void setReverseAPIDeviceIndex(uint16_t deviceIndex)
void on_antenna_currentIndexChanged(int index)
void on_lpFIRInterpolation_currentIndexChanged(int index)
engine is running
Definition: deviceapi.h:56
quint64 m_deviceCenterFrequency
Center frequency in device.
void blockApplySettings(bool block)
static MsgStartStop * create(bool startStop)
int m_lpfFIRGain
digital lowpass FIR filter gain (dB)
quint32 m_lpfFIRBW
digital lowpass FIR filter bandwidth (Hz)
bool m_sampleRateMode
true: device, false: base band sample rate update mode
engine is in error
Definition: deviceapi.h:57
DeviceSampleSink * m_sampleSink
virtual bool deserialize(const QByteArray &data)
void on_sampleRate_changed(quint64 value)
void on_startStop_toggled(bool checked)