mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-15 12:51:49 -05:00
DaemonSrc: implemented status report to the GUI
This commit is contained in:
parent
472a9b2532
commit
b306aa8aa7
@ -35,6 +35,8 @@
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(DaemonSrc::MsgSampleRateNotification, Message)
|
||||
MESSAGE_CLASS_DEFINITION(DaemonSrc::MsgConfigureDaemonSrc, Message)
|
||||
MESSAGE_CLASS_DEFINITION(DaemonSrc::MsgQueryStreamData, Message)
|
||||
MESSAGE_CLASS_DEFINITION(DaemonSrc::MsgReportStreamData, Message)
|
||||
|
||||
const QString DaemonSrc::m_channelIdURI = "sdrangel.channeltx.daemonsrc";
|
||||
const QString DaemonSrc::m_channelId ="DaemonSrc";
|
||||
@ -140,6 +142,30 @@ bool DaemonSrc::handleMessage(const Message& cmd)
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MsgQueryStreamData::match(cmd))
|
||||
{
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
|
||||
MsgReportStreamData *msg = MsgReportStreamData::create(
|
||||
tv.tv_sec,
|
||||
tv.tv_usec,
|
||||
m_dataReadQueue.size(),
|
||||
m_dataReadQueue.length(),
|
||||
m_dataReadQueue.readSampleCount(),
|
||||
m_nbCorrectableErrors,
|
||||
m_nbUncorrectableErrors,
|
||||
m_currentMeta.m_nbOriginalBlocks,
|
||||
m_currentMeta.m_nbFECBlocks,
|
||||
m_currentMeta.m_centerFrequency,
|
||||
m_currentMeta.m_sampleRate);
|
||||
m_guiMessageQueue->push(msg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -422,3 +448,4 @@ void DaemonSrc::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respons
|
||||
response.getSdrDaemonChannelSourceReport()->setCorrectableErrorsCount(m_nbCorrectableErrors);
|
||||
response.getSdrDaemonChannelSourceReport()->setUncorrectableErrorsCount(m_nbUncorrectableErrors);
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,99 @@ public:
|
||||
int m_sampleRate;
|
||||
};
|
||||
|
||||
class MsgQueryStreamData : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
public:
|
||||
static MsgQueryStreamData* create() {
|
||||
return new MsgQueryStreamData();
|
||||
}
|
||||
private:
|
||||
MsgQueryStreamData() : Message() {}
|
||||
};
|
||||
|
||||
class MsgReportStreamData : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
uint32_t get_tv_sec() const { return m_tv_sec; }
|
||||
uint32_t get_tv_usec() const { return m_tv_usec; }
|
||||
uint32_t get_queueSize() const { return m_queueSize; }
|
||||
uint32_t get_queueLength() const { return m_queueLength; }
|
||||
uint32_t get_readSamplesCount() const { return m_readSamplesCount; }
|
||||
uint32_t get_nbCorrectableErrors() const { return m_nbCorrectableErrors; }
|
||||
uint32_t get_nbUncorrectableErrors() const { return m_nbUncorrectableErrors; }
|
||||
uint32_t get_nbOriginalBlocks() const { return m_nbOriginalBlocks; }
|
||||
uint32_t get_nbFECBlocks() const { return m_nbFECBlocks; }
|
||||
uint32_t get_centerFreq() const { return m_centerFreq; }
|
||||
uint32_t get_sampleRate() const { return m_sampleRate; }
|
||||
|
||||
static MsgReportStreamData* create(
|
||||
uint32_t tv_sec,
|
||||
uint32_t tv_usec,
|
||||
uint32_t queueSize,
|
||||
uint32_t queueLength,
|
||||
uint32_t readSamplesCount,
|
||||
uint32_t nbCorrectableErrors,
|
||||
uint32_t nbUncorrectableErrors,
|
||||
uint32_t nbOriginalBlocks,
|
||||
uint32_t nbFECBlocks,
|
||||
uint32_t centerFreq,
|
||||
uint32_t sampleRate)
|
||||
{
|
||||
return new MsgReportStreamData(
|
||||
tv_sec,
|
||||
tv_usec,
|
||||
queueSize,
|
||||
queueLength,
|
||||
readSamplesCount,
|
||||
nbCorrectableErrors,
|
||||
nbUncorrectableErrors,
|
||||
nbOriginalBlocks,
|
||||
nbFECBlocks,
|
||||
centerFreq,
|
||||
sampleRate);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t m_tv_sec;
|
||||
uint32_t m_tv_usec;
|
||||
uint32_t m_queueSize;
|
||||
uint32_t m_queueLength;
|
||||
uint32_t m_readSamplesCount;
|
||||
uint32_t m_nbCorrectableErrors;
|
||||
uint32_t m_nbUncorrectableErrors;
|
||||
uint32_t m_nbOriginalBlocks;
|
||||
uint32_t m_nbFECBlocks;
|
||||
uint32_t m_centerFreq;
|
||||
uint32_t m_sampleRate;
|
||||
|
||||
MsgReportStreamData(
|
||||
uint32_t tv_sec,
|
||||
uint32_t tv_usec,
|
||||
uint32_t queueSize,
|
||||
uint32_t queueLength,
|
||||
uint32_t readSamplesCount,
|
||||
uint32_t nbCorrectableErrors,
|
||||
uint32_t nbUncorrectableErrors,
|
||||
uint32_t nbOriginalBlocks,
|
||||
uint32_t nbFECBlocks,
|
||||
uint32_t centerFreq,
|
||||
uint32_t sampleRate) :
|
||||
Message(),
|
||||
m_tv_sec(tv_sec),
|
||||
m_tv_usec(tv_usec),
|
||||
m_queueSize(queueSize),
|
||||
m_queueLength(queueLength),
|
||||
m_readSamplesCount(readSamplesCount),
|
||||
m_nbCorrectableErrors(nbCorrectableErrors),
|
||||
m_nbUncorrectableErrors(nbUncorrectableErrors),
|
||||
m_nbOriginalBlocks(nbOriginalBlocks),
|
||||
m_nbFECBlocks(nbFECBlocks),
|
||||
m_centerFreq(centerFreq),
|
||||
m_sampleRate(sampleRate)
|
||||
{ }
|
||||
};
|
||||
|
||||
DaemonSrc(DeviceSinkAPI *deviceAPI);
|
||||
~DaemonSrc();
|
||||
|
||||
|
@ -93,6 +93,60 @@ bool DaemonSrcGUI::handleMessage(const Message& message)
|
||||
blockApplySettings(false);
|
||||
return true;
|
||||
}
|
||||
else if (DaemonSrc::MsgReportStreamData::match(message))
|
||||
{
|
||||
const DaemonSrc::MsgReportStreamData& report = (DaemonSrc::MsgReportStreamData&) message;
|
||||
ui->centerFrequency->setText(QString("%1").arg(report.get_centerFreq()));
|
||||
ui->sampleRate->setText(QString("%1").arg(report.get_sampleRate()));
|
||||
QString nominalNbBlocksText = QString("%1/%2")
|
||||
.arg(report.get_nbOriginalBlocks() + report.get_nbFECBlocks())
|
||||
.arg(report.get_nbFECBlocks());
|
||||
ui->nominalNbBlocksText->setText(nominalNbBlocksText);
|
||||
QString queueLengthText = QString("%1/%2").arg(report.get_queueLength()).arg(report.get_queueSize());
|
||||
ui->queueLengthText->setText(queueLengthText);
|
||||
int queueLengthPercent = (report.get_queueLength()*100)/report.get_queueSize();
|
||||
ui->queueLengthGauge->setValue(queueLengthPercent);
|
||||
int unrecoverableCount = report.get_nbUncorrectableErrors();
|
||||
int recoverableCount = report.get_nbCorrectableErrors();
|
||||
uint64_t timestampUs = report.get_tv_sec()*1000000ULL + report.get_tv_usec();
|
||||
|
||||
if (!m_resetCounts)
|
||||
{
|
||||
int recoverableCountDelta = recoverableCount - m_lastCountRecovered;
|
||||
int unrecoverableCountDelta = unrecoverableCount - m_lastCountUnrecoverable;
|
||||
displayEventStatus(recoverableCountDelta, unrecoverableCountDelta);
|
||||
m_countRecovered += recoverableCountDelta;
|
||||
m_countUnrecoverable += unrecoverableCountDelta;
|
||||
displayEventCounts();
|
||||
}
|
||||
|
||||
uint32_t sampleCountDelta, sampleCount;
|
||||
sampleCount = report.get_readSamplesCount();
|
||||
|
||||
if (sampleCount < m_lastSampleCount) {
|
||||
sampleCountDelta = (0xFFFFFFFFU - sampleCount) + m_lastSampleCount + 1;
|
||||
} else {
|
||||
sampleCountDelta = sampleCount - m_lastSampleCount;
|
||||
}
|
||||
|
||||
if (sampleCountDelta == 0) {
|
||||
ui->allFramesDecoded->setStyleSheet("QToolButton { background-color : blue; }");
|
||||
}
|
||||
|
||||
double remoteStreamRate = sampleCountDelta*1e6 / (double) (timestampUs - m_lastTimestampUs);
|
||||
|
||||
if (remoteStreamRate != 0) {
|
||||
ui->streamRateText->setText(QString("%1").arg(remoteStreamRate, 0, 'f', 0));
|
||||
}
|
||||
|
||||
m_resetCounts = false;
|
||||
m_lastCountRecovered = recoverableCount;
|
||||
m_lastCountUnrecoverable = unrecoverableCount;
|
||||
m_lastSampleCount = sampleCount;
|
||||
m_lastTimestampUs = timestampUs;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
@ -103,7 +157,15 @@ DaemonSrcGUI::DaemonSrcGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
||||
RollupWidget(parent),
|
||||
ui(new Ui::DaemonSrcGUI),
|
||||
m_pluginAPI(pluginAPI),
|
||||
m_deviceUISet(deviceUISet)
|
||||
m_deviceUISet(deviceUISet),
|
||||
m_countUnrecoverable(0),
|
||||
m_countRecovered(0),
|
||||
m_lastCountUnrecoverable(0),
|
||||
m_lastCountRecovered(0),
|
||||
m_lastSampleCount(0),
|
||||
m_lastTimestampUs(0),
|
||||
m_resetCounts(true),
|
||||
m_tickCount(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
@ -126,6 +188,9 @@ DaemonSrcGUI::DaemonSrcGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
||||
m_deviceUISet->addRollupWidget(this);
|
||||
|
||||
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
|
||||
connect(&(m_deviceUISet->m_deviceSinkAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick()));
|
||||
|
||||
m_time.start();
|
||||
|
||||
displaySettings();
|
||||
applySettings(true);
|
||||
@ -250,3 +315,59 @@ void DaemonSrcGUI::on_dataApplyButton_clicked(bool checked __attribute__((unused
|
||||
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DaemonSrcGUI::on_eventCountsReset_clicked(bool checked __attribute__((unused)))
|
||||
{
|
||||
m_countUnrecoverable = 0;
|
||||
m_countRecovered = 0;
|
||||
m_time.start();
|
||||
displayEventCounts();
|
||||
displayEventTimer();
|
||||
}
|
||||
|
||||
void DaemonSrcGUI::displayEventCounts()
|
||||
{
|
||||
QString nstr = QString("%1").arg(m_countUnrecoverable, 3, 10, QChar('0'));
|
||||
ui->eventUnrecText->setText(nstr);
|
||||
nstr = QString("%1").arg(m_countRecovered, 3, 10, QChar('0'));
|
||||
ui->eventRecText->setText(nstr);
|
||||
}
|
||||
|
||||
void DaemonSrcGUI::displayEventStatus(int recoverableCount, int unrecoverableCount)
|
||||
{
|
||||
|
||||
if (unrecoverableCount == 0)
|
||||
{
|
||||
if (recoverableCount == 0) {
|
||||
ui->allFramesDecoded->setStyleSheet("QToolButton { background-color : green; }");
|
||||
} else {
|
||||
ui->allFramesDecoded->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->allFramesDecoded->setStyleSheet("QToolButton { background-color : red; }");
|
||||
}
|
||||
}
|
||||
|
||||
void DaemonSrcGUI::displayEventTimer()
|
||||
{
|
||||
int elapsedTimeMillis = m_time.elapsed();
|
||||
QTime recordLength(0, 0, 0, 0);
|
||||
recordLength = recordLength.addSecs(elapsedTimeMillis/1000);
|
||||
QString s_time = recordLength.toString("HH:mm:ss");
|
||||
ui->eventCountsTimeText->setText(s_time);
|
||||
}
|
||||
|
||||
void DaemonSrcGUI::tick()
|
||||
{
|
||||
if (++m_tickCount == 20) // once per second
|
||||
{
|
||||
DaemonSrc::MsgQueryStreamData *msg = DaemonSrc::MsgQueryStreamData::create();
|
||||
m_daemonSrc->getInputMessageQueue()->push(msg);
|
||||
|
||||
displayEventTimer();
|
||||
|
||||
m_tickCount = 0;
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,12 @@
|
||||
#ifndef PLUGINS_CHANNELTX_DAEMONSRC_DAEMONSRCGUI_H_
|
||||
#define PLUGINS_CHANNELTX_DAEMONSRC_DAEMONSRCGUI_H_
|
||||
|
||||
#include <QTime>
|
||||
|
||||
#include "plugin/plugininstancegui.h"
|
||||
#include "dsp/channelmarker.h"
|
||||
#include "gui/rollupwidget.h"
|
||||
#include "util/messagequeue.h"
|
||||
#include "dsp/channelmarker.h"
|
||||
|
||||
#include "daemonsrcsettings.h"
|
||||
|
||||
@ -62,6 +64,16 @@ private:
|
||||
DaemonSrc* m_daemonSrc;
|
||||
MessageQueue m_inputMessageQueue;
|
||||
|
||||
uint32_t m_countUnrecoverable;
|
||||
uint32_t m_countRecovered;
|
||||
uint32_t m_lastCountUnrecoverable;
|
||||
uint32_t m_lastCountRecovered;
|
||||
uint32_t m_lastSampleCount;
|
||||
uint64_t m_lastTimestampUs;
|
||||
bool m_resetCounts;
|
||||
QTime m_time;
|
||||
uint32_t m_tickCount;
|
||||
|
||||
explicit DaemonSrcGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget* parent = 0);
|
||||
virtual ~DaemonSrcGUI();
|
||||
|
||||
@ -72,6 +84,10 @@ private:
|
||||
void leaveEvent(QEvent*);
|
||||
void enterEvent(QEvent*);
|
||||
|
||||
void displayEventCounts();
|
||||
void displayEventStatus(int recoverableCount, int unrecoverableCount);
|
||||
void displayEventTimer();
|
||||
|
||||
private slots:
|
||||
void handleSourceMessages();
|
||||
void on_dataAddress_returnPressed();
|
||||
@ -79,6 +95,8 @@ private slots:
|
||||
void on_dataApplyButton_clicked(bool checked);
|
||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||
void onMenuDialogCalled(const QPoint& p);
|
||||
void on_eventCountsReset_clicked(bool checked);
|
||||
void tick();
|
||||
};
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>320</width>
|
||||
<height>90</height>
|
||||
<height>140</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -19,7 +19,13 @@
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>90</height>
|
||||
<height>140</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
@ -37,7 +43,7 @@
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>301</width>
|
||||
<height>61</height>
|
||||
<height>121</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -150,6 +156,272 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="nominalValuesLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="centerFrequencyLabel">
|
||||
<property name="text">
|
||||
<string>Freq</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="centerFrequency">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Stream center frequency setting</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00000000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="centerFrequencyUnits">
|
||||
<property name="text">
|
||||
<string>kHz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sampleRateLabel">
|
||||
<property name="text">
|
||||
<string> SR</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sampleRate">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Stream nominal sample rate</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0000000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sampleRateUnits">
|
||||
<property name="text">
|
||||
<string>S/s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="monitorLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="nominalNbBlocksText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Nb total blocks / Nb FEC blocks</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>000/00</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="allFramesDecoded">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Frames status: green = all original received, none = some recovered by FEC, red = some lost, blue = remote not streaming</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/locked.png</normaloff>:/locked.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="streamRateText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Stream actual sample rate</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0000000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="streamRateUnits">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>S/s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="eventCountsReset">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="eventUnrecText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Number of unrecoverable errors since event counts reset</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="eventRecText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Number of correctable errors since event counts reset</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="eventCountsTimeText">
|
||||
<property name="toolTip">
|
||||
<string>Time since last event counts reset</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00:00:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="queueLengthLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="queueLengthLabel">
|
||||
<property name="text">
|
||||
<string>QL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="queueLengthGauge">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>14</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Queue length gauge</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="queueLengthText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Queued data blocks / Queue size in data blocks</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>000/000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@ -174,6 +446,8 @@
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -59,6 +59,8 @@ SDRdaemonSinkGui::SDRdaemonSinkGui(DeviceUISet *deviceUISet, QWidget* parent) :
|
||||
m_lastCountRecovered = 0;
|
||||
m_lastSampleCount = 0;
|
||||
m_lastTimestampRateCorrection = 0;
|
||||
m_nbSamplesSinceRateCorrection = 0;
|
||||
m_chunkSizeCorrection = 0;
|
||||
m_resetCounts = true;
|
||||
|
||||
m_paletteGreenText.setColor(QPalette::WindowText, Qt::green);
|
||||
@ -242,6 +244,9 @@ void SDRdaemonSinkGui::displaySettings()
|
||||
QString s1 = QString::number(m_settings.m_nbFECBlocks, 'f', 0);
|
||||
ui->nominalNbBlocksText->setText(tr("%1/%2").arg(s0).arg(s1));
|
||||
|
||||
ui->serverType->setCurrentIndex((int) m_settings.m_serverType);
|
||||
ui->deviceIndex->setText(tr("%1").arg(m_settings.m_deviceIndex));
|
||||
ui->channelIndex->setText(tr("%1").arg(m_settings.m_channelIndex));
|
||||
ui->apiAddress->setText(m_settings.m_apiAddress);
|
||||
ui->apiPort->setText(tr("%1").arg(m_settings.m_apiPort));
|
||||
ui->dataAddress->setText(m_settings.m_dataAddress);
|
||||
@ -455,6 +460,9 @@ void SDRdaemonSinkGui::on_startStop_toggled(bool checked)
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
m_nbSamplesSinceRateCorrection = 0;
|
||||
m_lastTimestampRateCorrection = 0;
|
||||
|
||||
SDRdaemonSinkOutput::MsgStartStop *message = SDRdaemonSinkOutput::MsgStartStop::create(checked);
|
||||
m_deviceSampleSink->getInputMessageQueue()->push(message);
|
||||
}
|
||||
@ -590,15 +598,6 @@ void SDRdaemonSinkGui::analyzeApiReply(const QJsonObject& jsonObject)
|
||||
int recoverableCount = report["correctableErrorsCount"].toInt();
|
||||
uint64_t timestampUs = report["tvSec"].toInt()*1000000ULL + report["tvUSec"].toInt();
|
||||
|
||||
if (m_lastTimestampRateCorrection == 0) {
|
||||
m_lastTimestampRateCorrection = timestampUs;
|
||||
}
|
||||
|
||||
if ((timestampUs - m_lastTimestampRateCorrection > 600e6) && ((queueLengthPercent > 60) || (queueLengthPercent < 40)))
|
||||
{
|
||||
m_lastTimestampRateCorrection = timestampUs;
|
||||
}
|
||||
|
||||
if (!m_resetCounts)
|
||||
{
|
||||
int recoverableCountDelta = recoverableCount - m_lastCountRecovered;
|
||||
@ -618,16 +617,31 @@ void SDRdaemonSinkGui::analyzeApiReply(const QJsonObject& jsonObject)
|
||||
sampleCountDelta = sampleCount - m_lastSampleCount;
|
||||
}
|
||||
|
||||
if (sampleCountDelta == 0) {
|
||||
if (sampleCountDelta == 0)
|
||||
{
|
||||
ui->allFramesDecoded->setStyleSheet("QToolButton { background-color : blue; }");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_lastTimestampRateCorrection == 0) {
|
||||
m_lastTimestampRateCorrection = timestampUs;
|
||||
}
|
||||
|
||||
//if ((timestampUs - m_lastTimestampRateCorrection > 300e6) && ((queueLengthPercent > 60) || (queueLengthPercent < 40)))
|
||||
if ((m_nbSamplesSinceRateCorrection > 20000000) && ((queueLengthPercent > 60) || (queueLengthPercent < 40)))
|
||||
{
|
||||
sampleRateCorrection(queueLength, queueSize, timestampUs - m_lastTimestampRateCorrection);
|
||||
m_lastTimestampRateCorrection = timestampUs;
|
||||
m_nbSamplesSinceRateCorrection = 0;
|
||||
}
|
||||
|
||||
m_nbSamplesSinceRateCorrection += sampleCountDelta;
|
||||
}
|
||||
|
||||
double remoteStreamRate = sampleCountDelta*1e6 / (double) (timestampUs - m_lastTimestampUs);
|
||||
|
||||
if (remoteStreamRate != 0)
|
||||
{
|
||||
m_rateMovingAverage(remoteStreamRate);
|
||||
ui->remoteStreamRateText->setText(QString("%1").arg(m_rateMovingAverage.instantAverage(), 0, 'f', 0));
|
||||
if (remoteStreamRate != 0) {
|
||||
ui->remoteStreamRateText->setText(QString("%1").arg(remoteStreamRate, 0, 'f', 0));
|
||||
}
|
||||
|
||||
m_resetCounts = false;
|
||||
@ -662,15 +676,16 @@ void SDRdaemonSinkGui::analyzeApiReply(const QJsonObject& jsonObject)
|
||||
}
|
||||
}
|
||||
|
||||
void SDRdaemonSinkGui::sampleRateCorrection(int queueLength, int queueSize, int64_t timeDelta)
|
||||
void SDRdaemonSinkGui::sampleRateCorrection(int queueLength, int queueSize, int64_t timeDeltaUs)
|
||||
{
|
||||
int nbBlocksDiff = queueLength - (queueSize/2);
|
||||
int nbSamplesDiff = nbBlocksDiff * 127 * 127;
|
||||
float sampleCorr = (nbSamplesDiff * 50000.0) / timeDelta;
|
||||
int chunkCorr = roundf(sampleCorr);
|
||||
float sampleCorr = (nbSamplesDiff * 50000.0) / timeDeltaUs; // correction for ~50ms chunks (50000 us)
|
||||
int chunkCorr = -roundf(sampleCorr);
|
||||
m_chunkSizeCorrection += chunkCorr;
|
||||
|
||||
qDebug("SDRdaemonSinkGui::sampleRateCorrection: %d samples", -chunkCorr);
|
||||
qDebug("SDRdaemonSinkGui::sampleRateCorrection: %d (%d) samples", m_chunkSizeCorrection, chunkCorr);
|
||||
|
||||
SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkChunkCorrection* message = SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkChunkCorrection::create(-chunkCorr);
|
||||
SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkChunkCorrection* message = SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkChunkCorrection::create(m_chunkSizeCorrection);
|
||||
m_deviceSampleSink->getInputMessageQueue()->push(message);
|
||||
}
|
||||
|
@ -17,15 +17,16 @@
|
||||
#ifndef INCLUDE_SDRDAEMONSINKGUI_H
|
||||
#define INCLUDE_SDRDAEMONSINKGUI_H
|
||||
|
||||
#include <plugin/plugininstancegui.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QTime>
|
||||
#include <QWidget>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
#include "plugin/plugininstancegui.h"
|
||||
#include "util/messagequeue.h"
|
||||
#include "util/limitedcounter.h"
|
||||
#include "util/movingaverage.h"
|
||||
|
||||
#include "sdrdaemonsinksettings.h"
|
||||
#include "sdrdaemonsinkoutput.h"
|
||||
@ -40,6 +41,33 @@ namespace Ui {
|
||||
class SDRdaemonSinkGui;
|
||||
}
|
||||
|
||||
class SDRdaemonSinkExpAvg {
|
||||
public:
|
||||
SDRdaemonSinkExpAvg(float alpha) :
|
||||
m_alpha(alpha),
|
||||
m_start(true),
|
||||
m_s(0)
|
||||
{}
|
||||
int put(int y)
|
||||
{
|
||||
if (m_start) {
|
||||
m_start = false;
|
||||
m_s = y;
|
||||
} else {
|
||||
m_s = m_alpha*y + (1.0-m_alpha)*m_s;
|
||||
}
|
||||
return roundf(m_s);
|
||||
}
|
||||
void reset() {
|
||||
m_start = true;
|
||||
}
|
||||
|
||||
private:
|
||||
float m_alpha;
|
||||
bool m_start;
|
||||
float m_s;
|
||||
};
|
||||
|
||||
class SDRdaemonSinkGui : public QWidget, public PluginInstanceGUI {
|
||||
Q_OBJECT
|
||||
|
||||
@ -71,7 +99,6 @@ private:
|
||||
int m_sampleRate;
|
||||
quint64 m_deviceCenterFrequency; //!< Center frequency in device
|
||||
int m_samplesCount;
|
||||
MovingAverageUtil<double, double, 30> m_rateMovingAverage; // ~30s average
|
||||
uint32_t m_tickCount;
|
||||
std::size_t m_nbSinceLastFlowCheck;
|
||||
int m_lastEngineState;
|
||||
@ -85,6 +112,8 @@ private:
|
||||
uint32_t m_lastSampleCount;
|
||||
uint64_t m_lastTimestampUs;
|
||||
uint64_t m_lastTimestampRateCorrection;
|
||||
uint32_t m_nbSamplesSinceRateCorrection;
|
||||
int m_chunkSizeCorrection;
|
||||
bool m_resetCounts;
|
||||
QTime m_time;
|
||||
|
||||
@ -108,7 +137,7 @@ private:
|
||||
void displayEventStatus(int recoverableCount, int unrecoverableCount);
|
||||
void displayEventTimer();
|
||||
void analyzeApiReply(const QJsonObject& jsonObject);
|
||||
void sampleRateCorrection(int queueLength, int queueSize, int64_t timeDelta);
|
||||
void sampleRateCorrection(int queueLength, int queueSize, int64_t timeDeltaUs);
|
||||
|
||||
private slots:
|
||||
void handleInputMessages();
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
|
||||
bool isRunning() const { return m_running; }
|
||||
|
||||
std::size_t getSamplesCount() const { return m_samplesCount; }
|
||||
uint32_t getSamplesCount() const { return m_samplesCount; }
|
||||
void setSamplesCount(int samplesCount) { m_samplesCount = samplesCount; }
|
||||
void setChunkCorrection(int chunkCorrection) { m_chunkCorrection = chunkCorrection; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user