diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.cpp b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.cpp index bc78b1704..98e70281b 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.cpp +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.cpp @@ -58,6 +58,7 @@ SDRdaemonSinkGui::SDRdaemonSinkGui(DeviceUISet *deviceUISet, QWidget* parent) : m_lastCountUnrecoverable = 0; m_lastCountRecovered = 0; m_lastSampleCount = 0; + m_lastTimestampRateCorrection = 0; m_resetCounts = true; m_paletteGreenText.setColor(QPalette::WindowText, Qt::green); @@ -176,12 +177,6 @@ bool SDRdaemonSinkGui::handleMessage(const Message& message) blockApplySettings(false); return true; } - else if (SDRdaemonSinkOutput::MsgReportSDRdaemonSinkStreamTiming::match(message)) - { - m_samplesCount = ((SDRdaemonSinkOutput::MsgReportSDRdaemonSinkStreamTiming&)message).getSamplesCount(); - updateWithStreamTime(); - return true; - } else if (SDRdaemonSinkOutput::MsgStartStop::match(message)) { SDRdaemonSinkOutput::MsgStartStop& notif = (SDRdaemonSinkOutput::MsgStartStop&) message; @@ -339,7 +334,7 @@ void SDRdaemonSinkGui::on_apiAddress_returnPressed() QString infoURL = QString("http://%1:%2/sdrdaemon").arg(m_settings.m_apiAddress).arg(m_settings.m_apiPort); m_networkRequest.setUrl(QUrl(infoURL)); - m_networkManager->get(m_networkRequest); + m_networkManager->get(m_networkRequest); } void SDRdaemonSinkGui::on_apiPort_returnPressed() @@ -360,7 +355,7 @@ void SDRdaemonSinkGui::on_apiPort_returnPressed() QString infoURL = QString("http://%1:%2/sdrdaemon").arg(m_settings.m_apiAddress).arg(m_settings.m_apiPort); m_networkRequest.setUrl(QUrl(infoURL)); - m_networkManager->get(m_networkRequest); + m_networkManager->get(m_networkRequest); } void SDRdaemonSinkGui::on_dataAddress_returnPressed() @@ -472,35 +467,17 @@ void SDRdaemonSinkGui::displayEventTimer() ui->eventCountsTimeText->setText(s_time); } -void SDRdaemonSinkGui::updateWithStreamTime() -{ - int t_sec = 0; - int t_msec = 0; - - if (m_settings.m_sampleRate > 0){ - t_msec = ((m_samplesCount * 1000) / m_settings.m_sampleRate) % 1000; - t_sec = m_samplesCount / m_settings.m_sampleRate; - } - - QTime t(0, 0, 0, 0); - t = t.addSecs(t_sec); - t = t.addMSecs(t_msec); - QString s_timems = t.toString("HH:mm:ss.zzz"); - //ui->relTimeText->setText(s_timems); TODO with absolute time -} - void SDRdaemonSinkGui::tick() { - if ((++m_tickCount & 0xf) == 0) // 16*50ms ~800ms + if (++m_tickCount == 20) // once per second { QString reportURL = QString("http://%1:%2/sdrdaemon/channel/report").arg(m_settings.m_apiAddress).arg(m_settings.m_apiPort); m_networkRequest.setUrl(QUrl(reportURL)); m_networkManager->get(m_networkRequest); -// SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkStreamTiming* message = SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkStreamTiming::create(); -// m_deviceSampleSink->getInputMessageQueue()->push(message); - displayEventTimer(); + + m_tickCount = 0; } } @@ -556,12 +533,22 @@ void SDRdaemonSinkGui::analyzeApiReply(const QJsonObject& jsonObject) int queueLength = report["queueLength"].toInt(); QString queueLengthText = QString("%1/%2").arg(queueLength).arg(queueSize); ui->queueLengthText->setText(queueLengthText); - ui->queueLengthGauge->setValue((queueLength*100)/queueSize); + int queueLengthPercent = (queueLength*100)/queueSize; + ui->queueLengthGauge->setValue(queueLengthPercent); int unrecoverableCount = report["uncorrectableErrorsCount"].toInt(); int recoverableCount = report["correctableErrorsCount"].toInt(); - int sampleCount = report["samplesCount"].toInt(); + LimitedCounter sampleCount(report["samplesCount"].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; @@ -572,12 +559,19 @@ void SDRdaemonSinkGui::analyzeApiReply(const QJsonObject& jsonObject) displayEventCounts(); } - if ((sampleCount - m_lastSampleCount) == 0) { + LimitedCounter sampleCountDelta = sampleCount - m_lastSampleCount; + + if (sampleCountDelta.value() == 0) { ui->allFramesDecoded->setStyleSheet("QToolButton { background-color : blue; }"); } - double remoteStreamRate = (sampleCount - m_lastSampleCount) / (double) (timestampUs - m_lastTimestampUs); - ui->remoteStreamRateText->setText(QString("%1").arg(remoteStreamRate * 1e6, 0, 'f', 0)); + double remoteStreamRate = sampleCountDelta.value()*1e6 / (double) (timestampUs - m_lastTimestampUs); + + if (remoteStreamRate != 0) + { + m_rateMovingAverage(remoteStreamRate); + ui->remoteStreamRateText->setText(QString("%1").arg(m_rateMovingAverage.instantAverage(), 0, 'f', 0)); + } m_resetCounts = false; m_lastCountRecovered = recoverableCount; @@ -610,3 +604,16 @@ void SDRdaemonSinkGui::analyzeApiReply(const QJsonObject& jsonObject) ui->infoText->setText(infoLine); } } + +void SDRdaemonSinkGui::sampleRateCorrection(int queueLength, int queueSize, int64_t timeDelta) +{ + int nbBlocksDiff = queueLength - (queueSize/2); + int nbSamplesDiff = nbBlocksDiff * 127 * 127; + float sampleCorr = (nbSamplesDiff * 50000.0) / timeDelta; + int chunkCorr = roundf(sampleCorr); + + qDebug("SDRdaemonSinkGui::sampleRateCorrection: %d samples", -chunkCorr); + + SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkChunkCorrection* message = SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkChunkCorrection::create(-chunkCorr); + m_deviceSampleSink->getInputMessageQueue()->push(message); +} diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h index 90af1cbc7..c1769c3ce 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h @@ -24,6 +24,8 @@ #include #include "util/messagequeue.h" +#include "util/limitedcounter.h" +#include "util/movingaverage.h" #include "sdrdaemonsinksettings.h" #include "sdrdaemonsinkoutput.h" @@ -69,7 +71,8 @@ private: int m_sampleRate; quint64 m_deviceCenterFrequency; //!< Center frequency in device int m_samplesCount; - std::size_t m_tickCount; + MovingAverageUtil m_rateMovingAverage; // ~2mn average + uint32_t m_tickCount; std::size_t m_nbSinceLastFlowCheck; int m_lastEngineState; bool m_doApplySettings; @@ -79,8 +82,9 @@ private: uint32_t m_countRecovered; uint32_t m_lastCountUnrecoverable; uint32_t m_lastCountRecovered; - uint32_t m_lastSampleCount; - uint64_t m_lastTimestampUs; + LimitedCounter m_lastSampleCount; + uint64_t m_lastTimestampUs; + uint64_t m_lastTimestampRateCorrection; bool m_resetCounts; QTime m_time; @@ -98,13 +102,13 @@ private: void displayTime(); void sendControl(bool force = false); void sendSettings(); - void updateWithStreamTime(); void updateSampleRateAndFrequency(); void updateTxDelayTooltip(); void displayEventCounts(); void displayEventStatus(int recoverableCount, int unrecoverableCount); void displayEventTimer(); void analyzeApiReply(const QJsonObject& jsonObject); + void sampleRateCorrection(int queueLength, int queueSize, int64_t timeDelta); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.cpp b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.cpp index c0803769e..01e6e0814 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.cpp +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.cpp @@ -36,9 +36,7 @@ MESSAGE_CLASS_DEFINITION(SDRdaemonSinkOutput::MsgConfigureSDRdaemonSink, Message) MESSAGE_CLASS_DEFINITION(SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkWork, Message) MESSAGE_CLASS_DEFINITION(SDRdaemonSinkOutput::MsgStartStop, Message) -MESSAGE_CLASS_DEFINITION(SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkStreamTiming, Message) MESSAGE_CLASS_DEFINITION(SDRdaemonSinkOutput::MsgConfigureSDRdaemonSinkChunkCorrection, Message) -MESSAGE_CLASS_DEFINITION(SDRdaemonSinkOutput::MsgReportSDRdaemonSinkStreamTiming, Message) SDRdaemonSinkOutput::SDRdaemonSinkOutput(DeviceSinkAPI *deviceAPI) : m_deviceAPI(deviceAPI), @@ -211,18 +209,6 @@ bool SDRdaemonSinkOutput::handleMessage(const Message& message) return true; } - else if (MsgConfigureSDRdaemonSinkStreamTiming::match(message)) - { - MsgReportSDRdaemonSinkStreamTiming *report; - - if (m_sdrDaemonSinkThread != 0 && getMessageQueueToGUI()) - { - report = MsgReportSDRdaemonSinkStreamTiming::create(m_sdrDaemonSinkThread->getSamplesCount()); - getMessageQueueToGUI()->push(report); - } - - return true; - } else if (MsgConfigureSDRdaemonSinkChunkCorrection::match(message)) { MsgConfigureSDRdaemonSinkChunkCorrection& conf = (MsgConfigureSDRdaemonSinkChunkCorrection&) message; diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.h b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.h index 51c7b21c7..a5b4ada47 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.h +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.h @@ -114,43 +114,6 @@ public: { } }; - class MsgConfigureSDRdaemonSinkStreamTiming : public Message { - MESSAGE_CLASS_DECLARATION - - public: - - static MsgConfigureSDRdaemonSinkStreamTiming* create() - { - return new MsgConfigureSDRdaemonSinkStreamTiming(); - } - - private: - - MsgConfigureSDRdaemonSinkStreamTiming() : - Message() - { } - }; - - class MsgReportSDRdaemonSinkStreamTiming : public Message { - MESSAGE_CLASS_DECLARATION - - public: - std::size_t getSamplesCount() const { return m_samplesCount; } - - static MsgReportSDRdaemonSinkStreamTiming* create(std::size_t samplesCount) - { - return new MsgReportSDRdaemonSinkStreamTiming(samplesCount); - } - - protected: - std::size_t m_samplesCount; - - MsgReportSDRdaemonSinkStreamTiming(std::size_t samplesCount) : - Message(), - m_samplesCount(samplesCount) - { } - }; - SDRdaemonSinkOutput(DeviceSinkAPI *deviceAPI); virtual ~SDRdaemonSinkOutput(); virtual void destroy(); diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkthread.h b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkthread.h index d2566abc9..c4ce84150 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkthread.h +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkthread.h @@ -67,7 +67,7 @@ private: int m_samplesChunkSize; SampleSourceFifo* m_sampleFifo; - std::size_t m_samplesCount; + uint32_t m_samplesCount; int m_chunkCorrection; int m_samplerate; diff --git a/sdrbase/util/limitedcounter.h b/sdrbase/util/limitedcounter.h new file mode 100644 index 000000000..2ee229705 --- /dev/null +++ b/sdrbase/util/limitedcounter.h @@ -0,0 +1,84 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_UTIL_LIMITEDCOUNTER_H_ +#define SDRBASE_UTIL_LIMITEDCOUNTER_H_ + +#include + +template +class LimitedCounter +{ +public: + LimitedCounter() : + m_counter(0) + {} + + LimitedCounter(StoreType value) : + m_counter(value < Limit ? value : Limit - 1) + {} + + void operator=(const LimitedCounter& rhs) { + m_counter = rhs.m_counter; + } + + LimitedCounter& operator++() { + m_counter++; + if (m_counter >= Limit) { + m_counter = 0; + } + return *this; + } + + LimitedCounter operator++(int) { + LimitedCounter temp = *this ; + m_counter++; + if (m_counter >= Limit) { + m_counter = 0; + } + return temp; + } + + LimitedCounter& operator+=(const uint32_t rhs) { + m_counter += rhs; + if (m_counter >= Limit) { + m_counter -= Limit; + } + return *this; + } + + StoreType value() const { return m_counter; } + + friend LimitedCounter operator-(const LimitedCounter lhs, const LimitedCounter& rhs) + { + LimitedCounter result; + + if (lhs.m_counter < rhs.m_counter) { + result.m_counter = Limit - lhs.m_counter + rhs.m_counter + 1; + } else { + result.m_counter = lhs.m_counter - rhs.m_counter; + } + + return result; + } + +private: + StoreType m_counter; +}; + + + +#endif /* SDRBASE_UTIL_LIMITEDCOUNTER_H_ */ diff --git a/sdrbase/util/movingaverage.h b/sdrbase/util/movingaverage.h index 74ac1e94e..dfd003d8c 100644 --- a/sdrbase/util/movingaverage.h +++ b/sdrbase/util/movingaverage.h @@ -58,6 +58,7 @@ class MovingAverageUtil double asDouble() const { return ((double)m_total) / N; } float asFloat() const { return ((float)m_total) / N; } operator T() const { return m_total / N; } + T instantAverage() const { return m_total / (m_num_samples == 0 ? 1 : m_num_samples); } private: T m_samples[N]; diff --git a/sdrdaemon/channel/sdrdaemonchannelsource.cpp b/sdrdaemon/channel/sdrdaemonchannelsource.cpp index f89e54738..cd6b14635 100644 --- a/sdrdaemon/channel/sdrdaemonchannelsource.cpp +++ b/sdrdaemon/channel/sdrdaemonchannelsource.cpp @@ -50,7 +50,6 @@ SDRDaemonChannelSource::SDRDaemonChannelSource(DeviceSinkAPI *deviceAPI) : m_deviceAPI(deviceAPI), m_sourceThread(0), m_running(false), - m_samplesCount(0), m_nbCorrectableErrors(0), m_nbUncorrectableErrors(0) { @@ -77,7 +76,6 @@ SDRDaemonChannelSource::~SDRDaemonChannelSource() void SDRDaemonChannelSource::pull(Sample& sample) { m_dataReadQueue.readSample(sample); - m_samplesCount++; } void SDRDaemonChannelSource::start() @@ -235,8 +233,8 @@ void SDRDaemonChannelSource::handleDataBlock(SDRDaemonDataBlock* dataBlock) } // update counters - if (dataBlock->m_rxControlBlock.m_recoveryCount > paramsCM256.RecoveryCount) { - m_nbUncorrectableErrors += SDRDaemonNbOrginalBlocks - dataBlock->m_rxControlBlock.m_originalCount; + if (dataBlock->m_rxControlBlock.m_originalCount < SDRDaemonNbOrginalBlocks - paramsCM256.RecoveryCount) { + m_nbUncorrectableErrors += SDRDaemonNbOrginalBlocks - paramsCM256.RecoveryCount - dataBlock->m_rxControlBlock.m_originalCount; } else { m_nbCorrectableErrors += dataBlock->m_rxControlBlock.m_recoveryCount; } @@ -409,7 +407,7 @@ void SDRDaemonChannelSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelRe response.getSdrDaemonChannelSourceReport()->setTvUSec(tv.tv_usec); response.getSdrDaemonChannelSourceReport()->setQueueSize(m_dataReadQueue.size()); response.getSdrDaemonChannelSourceReport()->setQueueLength(m_dataReadQueue.length()); - response.getSdrDaemonChannelSourceReport()->setSamplesCount(m_dataReadQueue.readSampleCount()); + response.getSdrDaemonChannelSourceReport()->setSamplesCount(m_dataReadQueue.readSampleCount().value()); response.getSdrDaemonChannelSourceReport()->setCorrectableErrorsCount(m_nbCorrectableErrors); response.getSdrDaemonChannelSourceReport()->setUncorrectableErrorsCount(m_nbUncorrectableErrors); } diff --git a/sdrdaemon/channel/sdrdaemonchannelsource.h b/sdrdaemon/channel/sdrdaemonchannelsource.h index 79621da5c..b9359204b 100644 --- a/sdrdaemon/channel/sdrdaemonchannelsource.h +++ b/sdrdaemon/channel/sdrdaemonchannelsource.h @@ -110,7 +110,6 @@ private: bool m_running; SDRDaemonChannelSourceSettings m_settings; - uint64_t m_samplesCount; CM256::cm256_block m_cm256DescriptorBlocks[2*SDRDaemonNbOrginalBlocks]; //!< CM256 decoder descriptors (block addresses and block indexes) SDRDaemonMetaDataFEC m_currentMeta; diff --git a/sdrdaemon/channel/sdrdaemondatareadqueue.cpp b/sdrdaemon/channel/sdrdaemondatareadqueue.cpp index 3c947c725..b14921166 100644 --- a/sdrdaemon/channel/sdrdaemondatareadqueue.cpp +++ b/sdrdaemon/channel/sdrdaemondatareadqueue.cpp @@ -30,7 +30,6 @@ SDRDaemonDataReadQueue::SDRDaemonDataReadQueue() : m_maxSize(MinimumMaxSize), m_blockIndex(1), m_sampleIndex(0), - m_sampleCount(0), m_full(false) {} diff --git a/sdrdaemon/channel/sdrdaemondatareadqueue.h b/sdrdaemon/channel/sdrdaemondatareadqueue.h index d96f98366..4390a435d 100644 --- a/sdrdaemon/channel/sdrdaemondatareadqueue.h +++ b/sdrdaemon/channel/sdrdaemondatareadqueue.h @@ -25,6 +25,8 @@ #include +#include "util/limitedcounter.h" + class SDRDaemonDataBlock; class Sample; @@ -40,7 +42,7 @@ public: uint32_t length() const { return m_dataReadQueue.size(); } //!< Returns queue length uint32_t size() const { return m_maxSize; } //!< Returns queue size (max length) void setSize(uint32_t size); //!< Sets the queue size (max length) - uint32_t readSampleCount() const { return m_sampleCount; } //!< Returns the absolute number of samples read + LimitedCounter readSampleCount() const { return m_sampleCount; } //!< Returns the absolute number of samples read static const uint32_t MinimumMaxSize; @@ -50,7 +52,7 @@ private: uint32_t m_maxSize; uint32_t m_blockIndex; uint32_t m_sampleIndex; - uint32_t m_sampleCount; + LimitedCounter m_sampleCount; //!< use a counter capped below 2^31 as it is going to be converted to an int in the web interface bool m_full; //!< full condition was hit };