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.
filesourcegui.cpp
Go to the documentation of this file.
1 // Copyright (C) 2018-2019 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 <QFileDialog>
19 #include <QMessageBox>
20 #include <QDebug>
21 
22 #include "filesourcegui.h"
23 
24 #include "device/deviceapi.h"
25 #include "device/deviceuiset.h"
28 #include "util/db.h"
29 
30 #include "mainwindow.h"
31 
32 #include "filesource.h"
33 #include "ui_filesourcegui.h"
34 
36 {
37  FileSourceGUI* gui = new FileSourceGUI(pluginAPI, deviceUISet, channelTx);
38  return gui;
39 }
40 
42 {
43  delete this;
44 }
45 
46 void FileSourceGUI::setName(const QString& name)
47 {
48  setObjectName(name);
49 }
50 
51 QString FileSourceGUI::getName() const
52 {
53  return objectName();
54 }
55 
57  return 0;
58 }
59 
60 void FileSourceGUI::setCenterFrequency(qint64 centerFrequency)
61 {
62  (void) centerFrequency;
63 }
64 
66 {
69  applySettings(true);
70 }
71 
72 QByteArray FileSourceGUI::serialize() const
73 {
74  return m_settings.serialize();
75 }
76 
77 bool FileSourceGUI::deserialize(const QByteArray& data)
78 {
79  if(m_settings.deserialize(data)) {
81  applySettings(true);
82  return true;
83  } else {
85  return false;
86  }
87 }
88 
90 {
92  {
94  m_sampleRate = notif.getSampleRate();
96  return true;
97  }
99  {
101  m_settings = cfg.getSettings();
102  blockApplySettings(true);
103  displaySettings();
104  blockApplySettings(false);
105  return true;
106  }
108  {
109  m_acquisition = ((FileSource::MsgReportFileSourceAcquisition&)message).getAcquisition();
111  return true;
112  }
114  {
115  m_fileSampleRate = ((FileSource::MsgReportFileSourceStreamData&)message).getSampleRate();
116  m_fileSampleSize = ((FileSource::MsgReportFileSourceStreamData&)message).getSampleSize();
117  m_startingTimeStamp = ((FileSource::MsgReportFileSourceStreamData&)message).getStartingTimeStamp();
118  m_recordLength = ((FileSource::MsgReportFileSourceStreamData&)message).getRecordLength();
120  return true;
121  }
123  {
124  m_samplesCount = ((FileSource::MsgReportFileSourceStreamTiming&)message).getSamplesCount();
126  return true;
127  }
128  else if (FileSource::MsgPlayPause::match(message))
129  {
131  bool checked = notif.getPlayPause();
132  ui->play->setChecked(checked);
133  ui->navTime->setEnabled(!checked);
134  m_enableNavTime = !checked;
135 
136  return true;
137  }
138  else if (FileSource::MsgReportHeaderCRC::match(message))
139  {
141 
142  if (notif.isOK()) {
143  ui->crcLabel->setStyleSheet("QLabel { background-color : green; }");
144  } else {
145  ui->crcLabel->setStyleSheet("QLabel { background-color : red; }");
146  }
147 
148  return true;
149  }
150  else
151  {
152  return false;
153  }
154 }
155 
156 FileSourceGUI::FileSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget* parent) :
157  RollupWidget(parent),
158  ui(new Ui::FileSourceGUI),
159  m_pluginAPI(pluginAPI),
160  m_deviceUISet(deviceUISet),
161  m_sampleRate(0),
163  m_fileSampleRate(0),
164  m_fileSampleSize(0),
165  m_recordLength(0),
167  m_samplesCount(0),
168  m_acquisition(false),
169  m_enableNavTime(false),
170  m_doApplySettings(true),
171  m_tickCount(0)
172 {
173  (void) channelTx;
174 
175  ui->setupUi(this);
176  ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
177 
178  setAttribute(Qt::WA_DeleteOnClose, true);
179  connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
180  connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
181 
182  m_fileSource = (FileSource*) channelTx;
184 
185  connect(&(m_deviceUISet->m_deviceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick()));
186 
187  m_channelMarker.blockSignals(true);
190  m_channelMarker.setTitle("File source");
191  m_channelMarker.setMovable(false); // do not let user move the center arbitrarily
193  m_channelMarker.blockSignals(false);
194  m_channelMarker.setVisible(true); // activate signal on the last setting only
195 
197 
201 
202  connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
203  connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
204 
205  m_time.start();
206 
207  displaySettings();
208  applySettings(true);
209 }
210 
212 {
214  delete m_fileSource;
215  delete ui;
216 }
217 
219 {
220  m_doApplySettings = !block;
221 }
222 
224 {
225  if (m_doApplySettings)
226  {
228 
231  }
232 }
233 
235 {
236  if (m_doApplySettings)
237  {
242  }
243 }
244 
246 {
247  qDebug() << "FileSourceGui::configureFileName: " << m_fileName.toStdString().c_str();
250 }
251 
253 {
254  ui->play->blockSignals(true);
255  ui->play->setChecked(m_acquisition);
256  ui->play->blockSignals(false);
257  ui->showFileDialog->setEnabled(!m_acquisition);
258 }
259 
261 {
262  ui->sampleRateText->setText(tr("%1k").arg((float) m_fileSampleRate / 1000));
263  ui->sampleSizeText->setText(tr("%1b").arg(m_fileSampleSize));
264  QTime recordLength(0, 0, 0, 0);
265  recordLength = recordLength.addSecs(m_recordLength);
266  QString s_time = recordLength.toString("HH:mm:ss");
267  ui->recordLengthText->setText(s_time);
269 }
270 
272 {
273  qint64 t_sec = 0;
274  qint64 t_msec = 0;
275 
276  if (m_fileSampleRate > 0)
277  {
279  t_msec = (m_samplesCount - (t_sec * m_fileSampleRate)) * 1000LL / m_fileSampleRate;
280  }
281 
282  QTime t(0, 0, 0, 0);
283  t = t.addSecs(t_sec);
284  t = t.addMSecs(t_msec);
285  QString s_timems = t.toString("HH:mm:ss.zzz");
286  ui->relTimeText->setText(s_timems);
287 
288  qint64 startingTimeStampMsec = m_startingTimeStamp * 1000LL;
289  QDateTime dt = QDateTime::fromMSecsSinceEpoch(startingTimeStampMsec);
290  dt = dt.addSecs(t_sec);
291  dt = dt.addMSecs(t_msec);
292  QString s_date = dt.toString("yyyy-MM-dd HH:mm:ss.zzz");
293  ui->absTimeText->setText(s_date);
294 
295  if (!m_enableNavTime)
296  {
297  float posRatio = (float) t_sec / (float) m_recordLength;
298  ui->navTime->setValue((int) (posRatio * 1000.0));
299  }
300 }
301 
303 {
304  m_channelMarker.blockSignals(true);
308  m_channelMarker.blockSignals(false);
309  m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
310 
312  setWindowTitle(m_channelMarker.getTitle());
313 
314  blockApplySettings(true);
315  ui->gain->setValue(m_settings.m_gainDB);
316  ui->gainText->setText(tr("%1 dB").arg(m_settings.m_gainDB));
317  ui->interpolationFactor->setCurrentIndex(m_settings.m_log2Interp);
319  blockApplySettings(false);
320 }
321 
323 {
324  int shift = m_shiftFrequencyFactor * m_sampleRate;
325  double channelSampleRate = ((double) m_sampleRate) / (1<<m_settings.m_log2Interp);
326  QLocale loc;
327  ui->offsetFrequencyText->setText(tr("%1 Hz").arg(loc.toString(shift)));
328  ui->channelRateText->setText(tr("%1k").arg(QString::number(channelSampleRate / 1000.0, 'g', 5)));
330  m_channelMarker.setBandwidth(channelSampleRate);
331 }
332 
334 {
336 }
337 
339 {
341 }
342 
344 {
345  Message* message;
346 
347  while ((message = getInputMessageQueue()->pop()) != 0)
348  {
349  if (handleMessage(*message))
350  {
351  delete message;
352  }
353  }
354 }
355 
356 void FileSourceGUI::onWidgetRolled(QWidget* widget, bool rollDown)
357 {
358  (void) widget;
359  (void) rollDown;
360 }
361 
363 {
365  {
372 
373  dialog.move(p);
374  dialog.exec();
375 
383 
384  setWindowTitle(m_settings.m_title);
386 
387  applySettings();
388  }
389 
391 }
392 
394 {
395  m_settings.m_log2Interp = index;
397 }
398 
400 {
402  applyPosition();
403 }
404 
406 {
407  ui->gainText->setText(tr("%1 dB").arg(value));
408  m_settings.m_gainDB = value;
409  applySettings();
410 }
411 
413 {
414  (void) checked;
415  QString fileName = QFileDialog::getOpenFileName(this,
416  tr("Open I/Q record file"), ".", tr("SDR I/Q Files (*.sdriq)"), 0, QFileDialog::DontUseNativeDialog);
417 
418  if (fileName != "")
419  {
420  m_fileName = fileName;
421  ui->fileNameText->setText(m_fileName);
422  ui->crcLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
424  }
425 }
426 
428 {
429  if (m_doApplySettings)
430  {
431  m_settings.m_loop = checked;
434  }
435 }
436 
438 {
441  ui->navTime->setEnabled(!checked);
442  m_enableNavTime = !checked;
443 }
444 
446 {
447  if (m_enableNavTime && ((value >= 0) && (value <= 1000)))
448  {
451  }
452 }
453 
455 {
456  uint32_t maxHash = 1;
457 
458  for (uint32_t i = 0; i < m_settings.m_log2Interp; i++) {
459  maxHash *= 3;
460  }
461 
462  ui->position->setMaximum(maxHash-1);
463  ui->position->setValue(m_settings.m_filterChainHash);
464  m_settings.m_filterChainHash = ui->position->value();
465  applyPosition();
466 }
467 
469 {
470  ui->filterChainIndex->setText(tr("%1").arg(m_settings.m_filterChainHash));
471  QString s;
473  ui->filterChainText->setText(s);
474 
477 }
478 
480 {
481  double magsqAvg, magsqPeak;
482  int nbMagsqSamples;
483  m_fileSource->getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples);
484  double powDbAvg = CalcDb::dbPower(magsqAvg);
485  double powDbPeak = CalcDb::dbPower(magsqPeak);
486 
487  ui->channelPowerMeter->levelChanged(
488  (100.0f + powDbAvg) / 100.0f,
489  (100.0f + powDbPeak) / 100.0f,
490  nbMagsqSamples);
491 
492  if (m_tickCount % 4 == 0) {
493  ui->channelPower->setText(QString::number(powDbAvg, 'f', 1));
494  }
495 
496  if (++m_tickCount == 20) // once per second
497  {
500  m_tickCount = 0;
501  }
502 }
503 
505 {
506 }
void applySettings(bool force=false)
void removeTxChannelInstance(PluginInstanceGUI *pluginGUI)
const QString & getReverseAPIAddress() const
virtual qint64 getCenterFrequency() const
void on_position_valueChanged(int value)
virtual ~FileSourceGUI()
bool deserialize(const QByteArray &data)
void registerTxChannelInstance(const QString &channelName, PluginInstanceGUI *pluginGUI)
Definition: deviceuiset.cpp:88
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void channelMarkerChangedByCursor()
QByteArray serialize() const
void updateWithStreamData()
void on_interpolationFactor_currentIndexChanged(int index)
static double dbPower(double magsq, double floor=1e-12)
Definition: db.cpp:22
bool getPlayPause() const
Definition: filesource.h:214
quint64 m_startingTimeStamp
Definition: filesourcegui.h:72
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void setName(const QString &name)
const QTimer & getMasterTimer() const
This is the DSPEngine master timer.
Definition: deviceapi.h:173
void setReverseAPIChannelIndex(uint16_t channelIndex)
void resetContextMenuType()
Definition: rollupwidget.h:50
void addChannelMarker(ChannelMarker *channelMarker)
Add channel marker to spectrum.
Definition: deviceuiset.cpp:72
quint32 m_fileSampleSize
Definition: filesourcegui.h:70
static FileSourceGUI * create(PluginAPI *pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx)
void on_playLoop_toggled(bool checked)
void configureFileName()
void on_navTime_valueChanged(int value)
unsigned int uint32_t
Definition: rtptypes_win.h:46
ContextMenuType m_contextMenuType
Definition: rollupwidget.h:33
void updateWithStreamTime()
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
QByteArray serialize() const
void setReverseAPIDeviceIndex(uint16_t deviceIndex)
void onWidgetRolled(QWidget *widget, bool rollDown)
static double convertToString(unsigned int log2, unsigned int chainHash, QString &chainString)
DeviceAPI * m_deviceAPI
Definition: deviceuiset.h:48
void enterEvent(QEvent *)
void displaySettings()
FileSourceGUI(PluginAPI *pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget *parent=nullptr)
void blockApplySettings(bool block)
void getMagSqLevels(double &avg, double &peak, int &nbSamples)
Definition: filesource.h:359
static MsgConfigureFileSourceSeek * create(int seekMillis)
Definition: filesource.h:176
void displayRateAndShift()
void on_play_toggled(bool checked)
void setSourceOrSinkStream(bool sourceOrSinkStream)
Definition: channelmarker.h:75
static MsgConfigureFileSource * create(const FileSourceSettings &settings, bool force)
Definition: filesource.h:77
void onMenuDialogCalled(const QPoint &p)
uint32_t m_tickCount
Definition: filesourcegui.h:82
void setMovable(bool movable)
Definition: channelmarker.h:66
void setTitleColor(const QColor &c)
quint64 m_samplesCount
Definition: filesourcegui.h:73
void setHighlighted(bool highlighted)
virtual void setCenterFrequency(qint64 centerFrequency)
FileSourceSettings m_settings
Definition: filesourcegui.h:65
quint64 m_recordLength
Definition: filesourcegui.h:71
int32_t i
Definition: decimators.h:244
void addRollupWidget(QWidget *widget)
Add rollup widget to channel window.
Definition: deviceuiset.cpp:77
virtual void setMessageQueueToGUI(MessageQueue *queue)
const QString & getTitle() const
Definition: channelmarker.h:38
static bool match(const Message *message)
Definition: message.cpp:45
virtual void destroy()
void handleSourceMessages()
void updateWithAcquisition()
uint16_t m_reverseAPIChannelIndex
void applyInterpolation()
static MsgConfigureFileSourceStreamTiming * create()
Definition: filesource.h:158
bool m_enableNavTime
Definition: filesourcegui.h:75
bool deserialize(const QByteArray &data)
Ui::FileSourceGUI * ui
Definition: filesourcegui.h:61
uint16_t m_reverseAPIDeviceIndex
bool m_doApplySettings
Definition: filesourcegui.h:76
static MsgConfigureChannelizer * create(unsigned int m_log2Interp, unsigned int m_filterChainHash)
Definition: filesource.h:55
FileSource * m_fileSource
Definition: filesourcegui.h:78
void setReverseAPIAddress(const QString &address)
ChannelMarker m_channelMarker
Definition: filesourcegui.h:64
QString getName() const
void leaveEvent(QEvent *)
void setColor(const QColor &color)
double m_shiftFrequencyFactor
Channel frequency shift factor.
Definition: filesourcegui.h:67
virtual MessageQueue * getInputMessageQueue()
Definition: filesourcegui.h:54
void on_showFileDialog_clicked(bool checked)
const FileSourceSettings & getSettings() const
Definition: filesource.h:74
void setVisible(bool visible)
void setBandwidth(int bandwidth)
const QColor & getColor() const
Definition: channelmarker.h:64
void setTitle(const QString &title)
void applyChannelSettings()
PluginAPI * m_pluginAPI
Definition: filesourcegui.h:62
virtual bool handleMessage(const Message &message)
void setCenterFrequency(int centerFrequency)
QString m_fileName
Definition: filesourcegui.h:68
static MsgConfigureFileSourceName * create(const QString &fileName)
Definition: filesource.h:119
void setChannelMarker(Serializable *channelMarker)
void on_gain_valueChanged(int value)
void widgetRolled(QWidget *widget, bool rollDown)
void setUseReverseAPI(bool useReverseAPI)
static const QString m_channelIdURI
Definition: filesource.h:377
void resetToDefaults()
static MsgConfigureFileSourceWork * create(bool working)
Definition: filesource.h:139
DeviceUISet * m_deviceUISet
Definition: filesourcegui.h:63