diff --git a/plugins/channelrx/chanalyzer/chanalyzergui.cpp b/plugins/channelrx/chanalyzer/chanalyzergui.cpp index 147edac22..35b299576 100644 --- a/plugins/channelrx/chanalyzer/chanalyzergui.cpp +++ b/plugins/channelrx/chanalyzer/chanalyzergui.cpp @@ -1,497 +1,497 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2015 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 . // -/////////////////////////////////////////////////////////////////////////////////// - -#include "chanalyzergui.h" - -#include -#include -#include -#include - -#include "dsp/threadedbasebandsamplesink.h" -#include "ui_chanalyzergui.h" -#include "dsp/spectrumscopecombovis.h" -#include "dsp/spectrumvis.h" -#include "dsp/scopevis.h" -#include "gui/glspectrum.h" -#include "gui/glscope.h" -#include "plugin/pluginapi.h" -#include "util/simpleserializer.h" -#include "util/db.h" -#include "gui/basicchannelsettingswidget.h" -#include "dsp/dspengine.h" -#include "mainwindow.h" - -#include "chanalyzer.h" - -const QString ChannelAnalyzerGUI::m_channelID = "org.f4exb.sdrangelove.channel.chanalyzer"; - -ChannelAnalyzerGUI* ChannelAnalyzerGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) -{ - ChannelAnalyzerGUI* gui = new ChannelAnalyzerGUI(pluginAPI, deviceAPI); - return gui; -} - -void ChannelAnalyzerGUI::destroy() -{ - delete this; -} - -void ChannelAnalyzerGUI::setName(const QString& name) -{ - setObjectName(name); -} - -QString ChannelAnalyzerGUI::getName() const -{ - return objectName(); -} - -qint64 ChannelAnalyzerGUI::getCenterFrequency() const -{ - return m_channelMarker.getCenterFrequency(); -} - -void ChannelAnalyzerGUI::setCenterFrequency(qint64 centerFrequency) -{ - m_channelMarker.setCenterFrequency(centerFrequency); - applySettings(); -} - -void ChannelAnalyzerGUI::resetToDefaults() -{ - blockApplySettings(true); - - ui->BW->setValue(30); - ui->deltaFrequency->setValue(0); - ui->spanLog2->setValue(3); - - blockApplySettings(false); - applySettings(); -} - -QByteArray ChannelAnalyzerGUI::serialize() const -{ - SimpleSerializer s(1); - s.writeS32(1, m_channelMarker.getCenterFrequency()); - s.writeS32(2, ui->BW->value()); - s.writeBlob(3, ui->spectrumGUI->serialize()); - s.writeU32(4, m_channelMarker.getColor().rgb()); - s.writeS32(5, ui->lowCut->value()); - s.writeS32(6, ui->spanLog2->value()); - s.writeBool(7, ui->ssb->isChecked()); - s.writeBlob(8, ui->scopeGUI->serialize()); - return s.final(); -} - -bool ChannelAnalyzerGUI::deserialize(const QByteArray& data) -{ - SimpleDeserializer d(data); - - if(!d.isValid()) - { - resetToDefaults(); - return false; - } - - if(d.getVersion() == 1) - { - QByteArray bytetmp; - quint32 u32tmp; - qint32 tmp, bw, lowCut; - bool tmpBool; - - blockApplySettings(true); - m_channelMarker.blockSignals(true); - - d.readS32(1, &tmp, 0); - m_channelMarker.setCenterFrequency(tmp); - d.readS32(2, &bw, 30); - ui->BW->setValue(bw); - d.readBlob(3, &bytetmp); - ui->spectrumGUI->deserialize(bytetmp); - - if(d.readU32(4, &u32tmp)) - { - m_channelMarker.setColor(u32tmp); - } - - d.readS32(5, &lowCut, 3); - ui->lowCut->setValue(lowCut); - d.readS32(6, &tmp, 20); - ui->spanLog2->setValue(tmp); - setNewRate(tmp); - d.readBool(7, &tmpBool, false); - ui->ssb->setChecked(tmpBool); - d.readBlob(8, &bytetmp); - ui->scopeGUI->deserialize(bytetmp); - - blockApplySettings(false); - m_channelMarker.blockSignals(false); - - ui->BW->setValue(bw); - ui->lowCut->setValue(lowCut); // does applySettings(); - - return true; - } - else - { - resetToDefaults(); - return false; - } -} - -bool ChannelAnalyzerGUI::handleMessage(const Message& message) -{ - if (ChannelAnalyzer::MsgReportChannelSampleRateChanged::match(message)) - { - setNewRate(m_spanLog2); - return true; - } - - return false; -} - -void ChannelAnalyzerGUI::handleInputMessages() -{ - Message* message; - - while ((message = getInputMessageQueue()->pop()) != 0) - { - qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier()); - - if (handleMessage(*message)) - { - delete message; - } - } -} - -void ChannelAnalyzerGUI::viewChanged() -{ - applySettings(); -} - -void ChannelAnalyzerGUI::tick() -{ - Real powDb = CalcDb::dbPower(m_channelAnalyzer->getMagSq()); - m_channelPowerDbAvg.feed(powDb); - ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1)); -} - -void ChannelAnalyzerGUI::on_deltaMinus_toggled(bool minus) -{ - int deltaFrequency = m_channelMarker.getCenterFrequency(); - bool minusDelta = (deltaFrequency < 0); - - if (minus ^ minusDelta) // sign change - { - m_channelMarker.setCenterFrequency(-deltaFrequency); - } -} - -void ChannelAnalyzerGUI::on_deltaFrequency_changed(quint64 value) -{ - if (ui->deltaMinus->isChecked()) { - m_channelMarker.setCenterFrequency(-value); - } else { - m_channelMarker.setCenterFrequency(value); - } -} - -void ChannelAnalyzerGUI::on_BW_valueChanged(int value) -{ - QString s = QString::number(value/10.0, 'f', 1); - ui->BWText->setText(tr("%1k").arg(s)); - m_channelMarker.setBandwidth(value * 100 * 2); - - if (ui->ssb->isChecked()) - { - if (value < 0) { - m_channelMarker.setSidebands(ChannelMarker::lsb); - } else { - m_channelMarker.setSidebands(ChannelMarker::usb); - } - } - else - { - m_channelMarker.setSidebands(ChannelMarker::dsb); - } - - on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); -} - -int ChannelAnalyzerGUI::getEffectiveLowCutoff(int lowCutoff) -{ - int ssbBW = m_channelMarker.getBandwidth() / 2; - int effectiveLowCutoff = lowCutoff; - const int guard = 100; - - if (ssbBW < 0) { - if (effectiveLowCutoff < ssbBW + guard) { - effectiveLowCutoff = ssbBW + guard; - } - if (effectiveLowCutoff > 0) { - effectiveLowCutoff = 0; - } - } else { - if (effectiveLowCutoff > ssbBW - guard) { - effectiveLowCutoff = ssbBW - guard; - } - if (effectiveLowCutoff < 0) { - effectiveLowCutoff = 0; - } - } - - return effectiveLowCutoff; -} - -void ChannelAnalyzerGUI::on_lowCut_valueChanged(int value) -{ - int lowCutoff = getEffectiveLowCutoff(value * 100); - m_channelMarker.setLowCutoff(lowCutoff); - QString s = QString::number(lowCutoff/1000.0, 'f', 1); - ui->lowCutText->setText(tr("%1k").arg(s)); - ui->lowCut->setValue(lowCutoff/100); - applySettings(); -} - -void ChannelAnalyzerGUI::on_spanLog2_valueChanged(int value) -{ - if (setNewRate(value)) { - applySettings(); - } - -} - -void ChannelAnalyzerGUI::on_ssb_toggled(bool checked) -{ - if (checked) - { - if (ui->BW->value() < 0) { - m_channelMarker.setSidebands(ChannelMarker::lsb); - } else { - m_channelMarker.setSidebands(ChannelMarker::usb); - } - - ui->glSpectrum->setCenterFrequency(m_rate/4); - ui->glSpectrum->setSampleRate(m_rate/2); - ui->glSpectrum->setSsbSpectrum(true); - - on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); - } - else - { - m_channelMarker.setSidebands(ChannelMarker::dsb); - - ui->glSpectrum->setCenterFrequency(0); - ui->glSpectrum->setSampleRate(m_rate); - ui->glSpectrum->setSsbSpectrum(false); - - applySettings(); - } -} - -void ChannelAnalyzerGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) -{ - /* - if((widget == ui->spectrumContainer) && (m_ssbDemod != NULL)) - m_ssbDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); - */ -} - -void ChannelAnalyzerGUI::onMenuDoubleClicked() -{ - if(!m_basicSettingsShown) { - m_basicSettingsShown = true; - BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(&m_channelMarker, this); - bcsw->show(); - } -} - -ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent) : - RollupWidget(parent), - ui(new Ui::ChannelAnalyzerGUI), - m_pluginAPI(pluginAPI), - m_deviceAPI(deviceAPI), - m_channelMarker(this), - m_basicSettingsShown(false), - m_doApplySettings(true), - m_rate(6000), - m_spanLog2(3), - m_channelPowerDbAvg(40,0) -{ - ui->setupUi(this); - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); - - m_spectrumVis = new SpectrumVis(ui->glSpectrum); - m_scopeVis = new ScopeVis(ui->glScope); - m_spectrumScopeComboVis = new SpectrumScopeComboVis(m_spectrumVis, m_scopeVis); - m_channelAnalyzer = new ChannelAnalyzer(m_deviceAPI); - m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis); - m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue()); - - ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); - ui->deltaFrequency->setValueRange(7, 0U, 9999999U); - - ui->glSpectrum->setCenterFrequency(m_rate/2); - ui->glSpectrum->setSampleRate(m_rate); - ui->glSpectrum->setDisplayWaterfall(true); - ui->glSpectrum->setDisplayMaxHold(true); - ui->glSpectrum->setSsbSpectrum(true); - - ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); - - //m_channelMarker = new ChannelMarker(this); - m_channelMarker.setColor(Qt::gray); - m_channelMarker.setBandwidth(m_rate); - m_channelMarker.setSidebands(ChannelMarker::usb); - m_channelMarker.setCenterFrequency(0); - m_channelMarker.setVisible(true); - - connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); - - m_deviceAPI->registerChannelInstance(m_channelID, this); - m_deviceAPI->addChannelMarker(&m_channelMarker); - m_deviceAPI->addRollupWidget(this); - - ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); - ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); - - connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - - applySettings(); - setNewRate(m_spanLog2); -} - -ChannelAnalyzerGUI::~ChannelAnalyzerGUI() -{ - m_deviceAPI->removeChannelInstance(this); - delete m_channelAnalyzer; - delete m_spectrumVis; - delete m_scopeVis; - delete m_spectrumScopeComboVis; - //delete m_channelMarker; - delete ui; -} - -bool ChannelAnalyzerGUI::setNewRate(int spanLog2) -{ - qDebug("ChannelAnalyzerGUI::setNewRate"); - - if ((spanLog2 < 0) || (spanLog2 > 6)) { - return false; - } - - m_spanLog2 = spanLog2; - //m_rate = 48000 / (1<getSampleRate() / (1<BW->value() < -m_rate/200) { - ui->BW->setValue(-m_rate/200); - m_channelMarker.setBandwidth(-m_rate*2); - } else if (ui->BW->value() > m_rate/200) { - ui->BW->setValue(m_rate/200); - m_channelMarker.setBandwidth(m_rate*2); - } - - if (ui->lowCut->value() < -m_rate/200) { - ui->lowCut->setValue(-m_rate/200); - m_channelMarker.setLowCutoff(-m_rate); - } else if (ui->lowCut->value() > m_rate/200) { - ui->lowCut->setValue(m_rate/200); - m_channelMarker.setLowCutoff(m_rate); - } - - ui->BW->setMinimum(-m_rate/200); - ui->lowCut->setMinimum(-m_rate/200); - ui->BW->setMaximum(m_rate/200); - ui->lowCut->setMaximum(m_rate/200); - - QString s = QString::number(m_rate/1000.0, 'f', 1); - ui->spanText->setText(tr("%1k").arg(s)); - - if (ui->ssb->isChecked()) - { - if (ui->BW->value() < 0) { - m_channelMarker.setSidebands(ChannelMarker::lsb); - } else { - m_channelMarker.setSidebands(ChannelMarker::usb); - } - - ui->glSpectrum->setCenterFrequency(m_rate/4); - ui->glSpectrum->setSampleRate(m_rate/2); - ui->glSpectrum->setSsbSpectrum(true); - } - else - { - m_channelMarker.setSidebands(ChannelMarker::dsb); - - ui->glSpectrum->setCenterFrequency(0); - ui->glSpectrum->setSampleRate(m_rate); - ui->glSpectrum->setSsbSpectrum(false); - } - - ui->glScope->setSampleRate(m_rate); - m_scopeVis->setSampleRate(m_rate); - - return true; -} - -void ChannelAnalyzerGUI::blockApplySettings(bool block) -{ - ui->glScope->blockSignals(block); - ui->glSpectrum->blockSignals(block); - m_doApplySettings = !block; -} - -void ChannelAnalyzerGUI::applySettings() -{ - if (m_doApplySettings) - { - setTitleColor(m_channelMarker.getColor()); - ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency())); - ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0); - - ChannelAnalyzer::MsgConfigureChannelizer *msg = ChannelAnalyzer::MsgConfigureChannelizer::create(m_channelMarker.getCenterFrequency()); - m_channelAnalyzer->getInputMessageQueue()->push(msg); - - m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), - ui->BW->value() * 100.0, - ui->lowCut->value() * 100.0, - m_spanLog2, - ui->ssb->isChecked()); - } -} - -void ChannelAnalyzerGUI::leaveEvent(QEvent*) -{ - blockApplySettings(true); - m_channelMarker.setHighlighted(false); - blockApplySettings(false); -} - -void ChannelAnalyzerGUI::enterEvent(QEvent*) -{ - blockApplySettings(true); - m_channelMarker.setHighlighted(true); - blockApplySettings(false); -} - +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2015 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "chanalyzergui.h" + +#include +#include +#include +#include + +#include "dsp/threadedbasebandsamplesink.h" +#include "ui_chanalyzergui.h" +#include "dsp/spectrumscopecombovis.h" +#include "dsp/spectrumvis.h" +#include "dsp/scopevis.h" +#include "gui/glspectrum.h" +#include "gui/glscope.h" +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "util/db.h" +#include "gui/basicchannelsettingswidget.h" +#include "dsp/dspengine.h" +#include "mainwindow.h" + +#include "chanalyzer.h" + +const QString ChannelAnalyzerGUI::m_channelID = "org.f4exb.sdrangelove.channel.chanalyzer"; + +ChannelAnalyzerGUI* ChannelAnalyzerGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) +{ + ChannelAnalyzerGUI* gui = new ChannelAnalyzerGUI(pluginAPI, deviceAPI); + return gui; +} + +void ChannelAnalyzerGUI::destroy() +{ + delete this; +} + +void ChannelAnalyzerGUI::setName(const QString& name) +{ + setObjectName(name); +} + +QString ChannelAnalyzerGUI::getName() const +{ + return objectName(); +} + +qint64 ChannelAnalyzerGUI::getCenterFrequency() const +{ + return m_channelMarker.getCenterFrequency(); +} + +void ChannelAnalyzerGUI::setCenterFrequency(qint64 centerFrequency) +{ + m_channelMarker.setCenterFrequency(centerFrequency); + applySettings(); +} + +void ChannelAnalyzerGUI::resetToDefaults() +{ + blockApplySettings(true); + + ui->BW->setValue(30); + ui->deltaFrequency->setValue(0); + ui->spanLog2->setValue(3); + + blockApplySettings(false); + applySettings(); +} + +QByteArray ChannelAnalyzerGUI::serialize() const +{ + SimpleSerializer s(1); + s.writeS32(1, m_channelMarker.getCenterFrequency()); + s.writeS32(2, ui->BW->value()); + s.writeBlob(3, ui->spectrumGUI->serialize()); + s.writeU32(4, m_channelMarker.getColor().rgb()); + s.writeS32(5, ui->lowCut->value()); + s.writeS32(6, ui->spanLog2->value()); + s.writeBool(7, ui->ssb->isChecked()); + s.writeBlob(8, ui->scopeGUI->serialize()); + return s.final(); +} + +bool ChannelAnalyzerGUI::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + quint32 u32tmp; + qint32 tmp, bw, lowCut; + bool tmpBool; + + blockApplySettings(true); + m_channelMarker.blockSignals(true); + + d.readS32(1, &tmp, 0); + m_channelMarker.setCenterFrequency(tmp); + d.readS32(2, &bw, 30); + ui->BW->setValue(bw); + d.readBlob(3, &bytetmp); + ui->spectrumGUI->deserialize(bytetmp); + + if(d.readU32(4, &u32tmp)) + { + m_channelMarker.setColor(u32tmp); + } + + d.readS32(5, &lowCut, 3); + ui->lowCut->setValue(lowCut); + d.readS32(6, &tmp, 20); + ui->spanLog2->setValue(tmp); + setNewRate(tmp); + d.readBool(7, &tmpBool, false); + ui->ssb->setChecked(tmpBool); + d.readBlob(8, &bytetmp); + ui->scopeGUI->deserialize(bytetmp); + + blockApplySettings(false); + m_channelMarker.blockSignals(false); + + ui->BW->setValue(bw); + ui->lowCut->setValue(lowCut); // does applySettings(); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool ChannelAnalyzerGUI::handleMessage(const Message& message) +{ + if (ChannelAnalyzer::MsgReportChannelSampleRateChanged::match(message)) + { + setNewRate(m_spanLog2); + return true; + } + + return false; +} + +void ChannelAnalyzerGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier()); + + if (handleMessage(*message)) + { + delete message; + } + } +} + +void ChannelAnalyzerGUI::viewChanged() +{ + applySettings(); +} + +void ChannelAnalyzerGUI::tick() +{ + Real powDb = CalcDb::dbPower(m_channelAnalyzer->getMagSq()); + m_channelPowerDbAvg.feed(powDb); + ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1)); +} + +void ChannelAnalyzerGUI::on_deltaMinus_toggled(bool minus) +{ + int deltaFrequency = m_channelMarker.getCenterFrequency(); + bool minusDelta = (deltaFrequency < 0); + + if (minus ^ minusDelta) // sign change + { + m_channelMarker.setCenterFrequency(-deltaFrequency); + } +} + +void ChannelAnalyzerGUI::on_deltaFrequency_changed(quint64 value) +{ + if (ui->deltaMinus->isChecked()) { + m_channelMarker.setCenterFrequency(-value); + } else { + m_channelMarker.setCenterFrequency(value); + } +} + +void ChannelAnalyzerGUI::on_BW_valueChanged(int value) +{ + QString s = QString::number(value/10.0, 'f', 1); + ui->BWText->setText(tr("%1k").arg(s)); + m_channelMarker.setBandwidth(value * 100 * 2); + + if (ui->ssb->isChecked()) + { + if (value < 0) { + m_channelMarker.setSidebands(ChannelMarker::lsb); + } else { + m_channelMarker.setSidebands(ChannelMarker::usb); + } + } + else + { + m_channelMarker.setSidebands(ChannelMarker::dsb); + } + + on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); +} + +int ChannelAnalyzerGUI::getEffectiveLowCutoff(int lowCutoff) +{ + int ssbBW = m_channelMarker.getBandwidth() / 2; + int effectiveLowCutoff = lowCutoff; + const int guard = 100; + + if (ssbBW < 0) { + if (effectiveLowCutoff < ssbBW + guard) { + effectiveLowCutoff = ssbBW + guard; + } + if (effectiveLowCutoff > 0) { + effectiveLowCutoff = 0; + } + } else { + if (effectiveLowCutoff > ssbBW - guard) { + effectiveLowCutoff = ssbBW - guard; + } + if (effectiveLowCutoff < 0) { + effectiveLowCutoff = 0; + } + } + + return effectiveLowCutoff; +} + +void ChannelAnalyzerGUI::on_lowCut_valueChanged(int value) +{ + int lowCutoff = getEffectiveLowCutoff(value * 100); + m_channelMarker.setLowCutoff(lowCutoff); + QString s = QString::number(lowCutoff/1000.0, 'f', 1); + ui->lowCutText->setText(tr("%1k").arg(s)); + ui->lowCut->setValue(lowCutoff/100); + applySettings(); +} + +void ChannelAnalyzerGUI::on_spanLog2_valueChanged(int value) +{ + if (setNewRate(value)) { + applySettings(); + } + +} + +void ChannelAnalyzerGUI::on_ssb_toggled(bool checked) +{ + if (checked) + { + if (ui->BW->value() < 0) { + m_channelMarker.setSidebands(ChannelMarker::lsb); + } else { + m_channelMarker.setSidebands(ChannelMarker::usb); + } + + ui->glSpectrum->setCenterFrequency(m_rate/4); + ui->glSpectrum->setSampleRate(m_rate/2); + ui->glSpectrum->setSsbSpectrum(true); + + on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); + } + else + { + m_channelMarker.setSidebands(ChannelMarker::dsb); + + ui->glSpectrum->setCenterFrequency(0); + ui->glSpectrum->setSampleRate(m_rate); + ui->glSpectrum->setSsbSpectrum(false); + + applySettings(); + } +} + +void ChannelAnalyzerGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) +{ + /* + if((widget == ui->spectrumContainer) && (m_ssbDemod != NULL)) + m_ssbDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); + */ +} + +void ChannelAnalyzerGUI::onMenuDoubleClicked() +{ + if(!m_basicSettingsShown) { + m_basicSettingsShown = true; + BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(&m_channelMarker, this); + bcsw->show(); + } +} + +ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent) : + RollupWidget(parent), + ui(new Ui::ChannelAnalyzerGUI), + m_pluginAPI(pluginAPI), + m_deviceAPI(deviceAPI), + m_channelMarker(this), + m_basicSettingsShown(false), + m_doApplySettings(true), + m_rate(6000), + m_spanLog2(3), + m_channelPowerDbAvg(40,0) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); + + m_spectrumVis = new SpectrumVis(ui->glSpectrum); + m_scopeVis = new ScopeVis(ui->glScope); + m_spectrumScopeComboVis = new SpectrumScopeComboVis(m_spectrumVis, m_scopeVis); + m_channelAnalyzer = new ChannelAnalyzer(m_deviceAPI); + m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis); + m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue()); + + ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); + ui->deltaFrequency->setValueRange(7, 0U, 9999999U); + + ui->glSpectrum->setCenterFrequency(m_rate/2); + ui->glSpectrum->setSampleRate(m_rate); + ui->glSpectrum->setDisplayWaterfall(true); + ui->glSpectrum->setDisplayMaxHold(true); + ui->glSpectrum->setSsbSpectrum(true); + + ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer()); + ui->glScope->connectTimer(MainWindow::getInstance()->getMasterTimer()); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + + //m_channelMarker = new ChannelMarker(this); + m_channelMarker.setColor(Qt::gray); + m_channelMarker.setBandwidth(m_rate); + m_channelMarker.setSidebands(ChannelMarker::usb); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setVisible(true); + + connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); + + m_deviceAPI->registerChannelInstance(m_channelID, this); + m_deviceAPI->addChannelMarker(&m_channelMarker); + m_deviceAPI->addRollupWidget(this); + + ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); + ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + applySettings(); + setNewRate(m_spanLog2); +} + +ChannelAnalyzerGUI::~ChannelAnalyzerGUI() +{ + m_deviceAPI->removeChannelInstance(this); + delete m_channelAnalyzer; + delete m_spectrumVis; + delete m_scopeVis; + delete m_spectrumScopeComboVis; + //delete m_channelMarker; + delete ui; +} + +bool ChannelAnalyzerGUI::setNewRate(int spanLog2) +{ + qDebug("ChannelAnalyzerGUI::setNewRate"); + + if ((spanLog2 < 0) || (spanLog2 > 6)) { + return false; + } + + m_spanLog2 = spanLog2; + //m_rate = 48000 / (1<getSampleRate() / (1<BW->value() < -m_rate/200) { + ui->BW->setValue(-m_rate/200); + m_channelMarker.setBandwidth(-m_rate*2); + } else if (ui->BW->value() > m_rate/200) { + ui->BW->setValue(m_rate/200); + m_channelMarker.setBandwidth(m_rate*2); + } + + if (ui->lowCut->value() < -m_rate/200) { + ui->lowCut->setValue(-m_rate/200); + m_channelMarker.setLowCutoff(-m_rate); + } else if (ui->lowCut->value() > m_rate/200) { + ui->lowCut->setValue(m_rate/200); + m_channelMarker.setLowCutoff(m_rate); + } + + ui->BW->setMinimum(-m_rate/200); + ui->lowCut->setMinimum(-m_rate/200); + ui->BW->setMaximum(m_rate/200); + ui->lowCut->setMaximum(m_rate/200); + + QString s = QString::number(m_rate/1000.0, 'f', 1); + ui->spanText->setText(tr("%1k").arg(s)); + + if (ui->ssb->isChecked()) + { + if (ui->BW->value() < 0) { + m_channelMarker.setSidebands(ChannelMarker::lsb); + } else { + m_channelMarker.setSidebands(ChannelMarker::usb); + } + + ui->glSpectrum->setCenterFrequency(m_rate/4); + ui->glSpectrum->setSampleRate(m_rate/2); + ui->glSpectrum->setSsbSpectrum(true); + } + else + { + m_channelMarker.setSidebands(ChannelMarker::dsb); + + ui->glSpectrum->setCenterFrequency(0); + ui->glSpectrum->setSampleRate(m_rate); + ui->glSpectrum->setSsbSpectrum(false); + } + + ui->glScope->setSampleRate(m_rate); + m_scopeVis->setSampleRate(m_rate); + + return true; +} + +void ChannelAnalyzerGUI::blockApplySettings(bool block) +{ + ui->glScope->blockSignals(block); + ui->glSpectrum->blockSignals(block); + m_doApplySettings = !block; +} + +void ChannelAnalyzerGUI::applySettings() +{ + if (m_doApplySettings) + { + setTitleColor(m_channelMarker.getColor()); + ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency())); + ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0); + + ChannelAnalyzer::MsgConfigureChannelizer *msg = ChannelAnalyzer::MsgConfigureChannelizer::create(m_channelMarker.getCenterFrequency()); + m_channelAnalyzer->getInputMessageQueue()->push(msg); + + m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), + ui->BW->value() * 100.0, + ui->lowCut->value() * 100.0, + m_spanLog2, + ui->ssb->isChecked()); + } +} + +void ChannelAnalyzerGUI::leaveEvent(QEvent*) +{ + blockApplySettings(true); + m_channelMarker.setHighlighted(false); + blockApplySettings(false); +} + +void ChannelAnalyzerGUI::enterEvent(QEvent*) +{ + blockApplySettings(true); + m_channelMarker.setHighlighted(true); + blockApplySettings(false); +} + diff --git a/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp b/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp index cd05da0a3..bd36d521f 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp +++ b/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp @@ -1,582 +1,582 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 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 . // -/////////////////////////////////////////////////////////////////////////////////// - -#include "chanalyzernggui.h" - -#include -#include -#include -#include - -#include "dsp/threadedbasebandsamplesink.h" -#include "ui_chanalyzernggui.h" -#include "dsp/spectrumscopengcombovis.h" -#include "dsp/spectrumvis.h" -#include "dsp/scopevis.h" -#include "gui/glspectrum.h" -#include "gui/glscopeng.h" -#include "plugin/pluginapi.h" -#include "util/simpleserializer.h" -#include "util/db.h" -#include "gui/basicchannelsettingswidget.h" -#include "dsp/dspengine.h" -#include "mainwindow.h" - -#include "chanalyzerng.h" - -const QString ChannelAnalyzerNGGUI::m_channelID = "sdrangel.channel.chanalyzerng"; - -ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) -{ - ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceAPI); - return gui; -} - -void ChannelAnalyzerNGGUI::destroy() -{ - delete this; -} - -void ChannelAnalyzerNGGUI::setName(const QString& name) -{ - setObjectName(name); -} - -QString ChannelAnalyzerNGGUI::getName() const -{ - return objectName(); -} - -qint64 ChannelAnalyzerNGGUI::getCenterFrequency() const -{ - return m_channelMarker.getCenterFrequency(); -} - -void ChannelAnalyzerNGGUI::setCenterFrequency(qint64 centerFrequency) -{ - m_channelMarker.setCenterFrequency(centerFrequency); - applySettings(); -} - -void ChannelAnalyzerNGGUI::resetToDefaults() -{ - blockApplySettings(true); - - ui->useRationalDownsampler->setChecked(false); - ui->BW->setValue(30); - ui->deltaFrequency->setValue(0); - ui->spanLog2->setCurrentIndex(3); - - blockApplySettings(false); - applySettings(); -} - -QByteArray ChannelAnalyzerNGGUI::serialize() const -{ - SimpleSerializer s(1); - s.writeS32(1, m_channelMarker.getCenterFrequency()); - s.writeS32(2, ui->BW->value()); - s.writeBlob(3, ui->spectrumGUI->serialize()); - s.writeU32(4, m_channelMarker.getColor().rgb()); - s.writeS32(5, ui->lowCut->value()); - s.writeS32(6, ui->spanLog2->currentIndex()); - s.writeBool(7, ui->ssb->isChecked()); - s.writeBlob(8, ui->scopeGUI->serialize()); - s.writeU64(9, ui->channelSampleRate->getValueNew()); - return s.final(); -} - -bool ChannelAnalyzerNGGUI::deserialize(const QByteArray& data) -{ - SimpleDeserializer d(data); - - if(!d.isValid()) - { - resetToDefaults(); - return false; - } - - if(d.getVersion() == 1) - { - QByteArray bytetmp; - quint32 u32tmp; - quint64 u64tmp; - qint32 tmp, spanLog2, bw, lowCut; - bool tmpBool; - - blockApplySettings(true); - m_channelMarker.blockSignals(true); - - d.readS32(1, &tmp, 0); - m_channelMarker.setCenterFrequency(tmp); - d.readS32(2, &bw, 30); - d.readBlob(3, &bytetmp); - ui->spectrumGUI->deserialize(bytetmp); - - if(d.readU32(4, &u32tmp)) - { - m_channelMarker.setColor(u32tmp); - } - - d.readS32(5, &lowCut, 3); - d.readS32(6, &spanLog2, 3); - d.readBool(7, &tmpBool, false); - ui->ssb->setChecked(tmpBool); - d.readBlob(8, &bytetmp); - ui->scopeGUI->deserialize(bytetmp); - d.readU64(9, &u64tmp, 2000U); - ui->channelSampleRate->setValue(u64tmp); - - blockApplySettings(false); - m_channelMarker.blockSignals(false); - - ui->spanLog2->setCurrentIndex(spanLog2); - setNewFinalRate(spanLog2); - ui->BW->setValue(bw); - ui->lowCut->setValue(lowCut); // does applySettings(); - - return true; - } - else - { - resetToDefaults(); - return false; - } -} - -bool ChannelAnalyzerNGGUI::handleMessage(const Message& message __attribute__((unused))) -{ - if (ChannelAnalyzerNG::MsgReportChannelSampleRateChanged::match(message)) - { - setNewFinalRate(m_spanLog2); - applySettings(); - return true; - } - - return false; -} - -void ChannelAnalyzerNGGUI::handleInputMessages() -{ - Message* message; - - while ((message = getInputMessageQueue()->pop()) != 0) - { - qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier()); - - if (handleMessage(*message)) - { - delete message; - } - } -} - -void ChannelAnalyzerNGGUI::viewChanged() -{ - applySettings(); -} - -void ChannelAnalyzerNGGUI::tick() -{ - double powDb = CalcDb::dbPower(m_channelAnalyzer->getMagSq()); - m_channelPowerDbAvg.feed(powDb); - ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.average(), 0, 'f', 1)); -} - -//void ChannelAnalyzerNGGUI::channelizerInputSampleRateChanged() -//{ -// //ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); -// setNewFinalRate(m_spanLog2); -// applySettings(); -//} - -void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value) -{ - ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); - - if (ui->useRationalDownsampler->isChecked()) - { - qDebug("ChannelAnalyzerNGGUI::on_channelSampleRate_changed: %llu", value); - setNewFinalRate(m_spanLog2); - applySettings(); - } -} - -void ChannelAnalyzerNGGUI::on_useRationalDownsampler_toggled(bool checked __attribute__((unused))) -{ - setNewFinalRate(m_spanLog2); - applySettings(); -} - -int ChannelAnalyzerNGGUI::getRequestedChannelSampleRate() -{ - if (ui->useRationalDownsampler->isChecked()) { - return ui->channelSampleRate->getValueNew(); - } else { - return m_channelAnalyzer->getChannelizer()->getInputSampleRate(); - } -} - -void ChannelAnalyzerNGGUI::on_deltaFrequency_changed(qint64 value) -{ - m_channelMarker.setCenterFrequency(value); -} - -void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value) -{ - m_channelMarker.setBandwidth(value * 100 * 2); - - if (ui->ssb->isChecked()) - { - QString s = QString::number(value/10.0, 'f', 1); - ui->BWText->setText(tr("%1k").arg(s)); - } - else - { - QString s = QString::number(value/5.0, 'f', 1); // BW = value * 2 - ui->BWText->setText(tr("%1k").arg(s)); - } - - displayBandwidth(); - on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); -} - -int ChannelAnalyzerNGGUI::getEffectiveLowCutoff(int lowCutoff) -{ - int ssbBW = m_channelMarker.getBandwidth() / 2; - int effectiveLowCutoff = lowCutoff; - const int guard = 100; - - if (ssbBW < 0) { - if (effectiveLowCutoff < ssbBW + guard) { - effectiveLowCutoff = ssbBW + guard; - } - if (effectiveLowCutoff > 0) { - effectiveLowCutoff = 0; - } - } else { - if (effectiveLowCutoff > ssbBW - guard) { - effectiveLowCutoff = ssbBW - guard; - } - if (effectiveLowCutoff < 0) { - effectiveLowCutoff = 0; - } - } - - return effectiveLowCutoff; -} - -void ChannelAnalyzerNGGUI::on_lowCut_valueChanged(int value) -{ - int lowCutoff = getEffectiveLowCutoff(value * 100); - m_channelMarker.setLowCutoff(lowCutoff); - QString s = QString::number(lowCutoff/1000.0, 'f', 1); - ui->lowCutText->setText(tr("%1k").arg(s)); - ui->lowCut->setValue(lowCutoff/100); - applySettings(); -} - -void ChannelAnalyzerNGGUI::on_spanLog2_currentIndexChanged(int index) -{ - if (setNewFinalRate(index)) { - applySettings(); - } - -} - -void ChannelAnalyzerNGGUI::on_ssb_toggled(bool checked) -{ - //int bw = m_channelMarker.getBandwidth(); - - if (checked) - { - setFiltersUIBoundaries(); - - ui->BWLabel->setText("LP"); - QString s = QString::number(ui->BW->value()/10.0, 'f', 1); // bw/2 - ui->BWText->setText(tr("%1k").arg(s)); - - on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); - } - else - { - if (ui->BW->value() < 0) { - ui->BW->setValue(-ui->BW->value()); - } - - setFiltersUIBoundaries(); - //m_channelMarker.setBandwidth(ui->BW->value() * 200.0); - - ui->BWLabel->setText("BP"); - QString s = QString::number(ui->BW->value()/5.0, 'f', 1); // bw - ui->BWText->setText(tr("%1k").arg(s)); - - ui->lowCut->setEnabled(false); - ui->lowCut->setValue(0); - ui->lowCutText->setText("0.0k"); - } - - applySettings(); - displayBandwidth(); -} - -void ChannelAnalyzerNGGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) -{ - /* - if((widget == ui->spectrumContainer) && (m_ssbDemod != NULL)) - m_ssbDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); - */ -} - -void ChannelAnalyzerNGGUI::onMenuDoubleClicked() -{ - if(!m_basicSettingsShown) { - m_basicSettingsShown = true; - BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(&m_channelMarker, this); - bcsw->show(); - } -} - -ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent) : - RollupWidget(parent), - ui(new Ui::ChannelAnalyzerNGGUI), - m_pluginAPI(pluginAPI), - m_deviceAPI(deviceAPI), - m_channelMarker(this), - m_basicSettingsShown(false), - m_doApplySettings(true), - m_rate(6000), - m_spanLog2(0), - m_channelPowerDbAvg(40,0) -{ - ui->setupUi(this); - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); - - m_spectrumVis = new SpectrumVis(ui->glSpectrum); - m_scopeVis = new ScopeVisNG(ui->glScope); - m_spectrumScopeComboVis = new SpectrumScopeNGComboVis(m_spectrumVis, m_scopeVis); - m_channelAnalyzer = new ChannelAnalyzerNG(m_deviceAPI); - m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis); - m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue()); -// m_channelizer = new DownChannelizer(m_channelAnalyzer); -// m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); -// connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged())); -// m_deviceAPI->addThreadedSink(m_threadedChannelizer); - - ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); - ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); - - ui->channelSampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); - ui->channelSampleRate->setValueRange(7, 2000U, 9999999U); - - ui->glSpectrum->setCenterFrequency(m_rate/2); - ui->glSpectrum->setSampleRate(m_rate); - ui->glSpectrum->setDisplayWaterfall(true); - ui->glSpectrum->setDisplayMaxHold(true); - ui->glSpectrum->setSsbSpectrum(false); - ui->glSpectrum->setLsbDisplay(false); - ui->BWLabel->setText("BP"); - - ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); - - //m_channelMarker = new ChannelMarker(this); - m_channelMarker.setColor(Qt::gray); - m_channelMarker.setBandwidth(m_rate); - m_channelMarker.setSidebands(ChannelMarker::usb); - m_channelMarker.setCenterFrequency(0); - m_channelMarker.setVisible(true); - - connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); - - m_deviceAPI->registerChannelInstance(m_channelID, this); - m_deviceAPI->addChannelMarker(&m_channelMarker); - m_deviceAPI->addRollupWidget(this); - - ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); - ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); - - connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - - applySettings(); - setNewFinalRate(m_spanLog2); -} - -ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI() -{ - m_deviceAPI->removeChannelInstance(this); -// m_deviceAPI->removeThreadedSink(m_threadedChannelizer); -// delete m_threadedChannelizer; -// delete m_channelizer; - delete m_channelAnalyzer; - delete m_spectrumVis; - delete m_scopeVis; - delete m_spectrumScopeComboVis; - //delete m_channelMarker; - delete ui; -} - -bool ChannelAnalyzerNGGUI::setNewFinalRate(int spanLog2) -{ - qDebug("ChannelAnalyzerNGGUI::setNewRate"); - - if ((spanLog2 < 0) || (spanLog2 > 6)) { - return false; - } - - m_spanLog2 = spanLog2; - //m_rate = 48000 / (1<getInputSampleRate() / (1<spanText->setText(tr("%1 kS/s").arg(s)); - - displayBandwidth(); - - ui->glScope->setSampleRate(m_rate); - m_scopeVis->setSampleRate(m_rate); - - return true; -} - -void ChannelAnalyzerNGGUI::displayBandwidth() -{ - if (ui->ssb->isChecked()) - { - if (ui->BW->value() < 0) - { - m_channelMarker.setSidebands(ChannelMarker::lsb); - ui->glSpectrum->setLsbDisplay(true); - } - else - { - m_channelMarker.setSidebands(ChannelMarker::usb); - ui->glSpectrum->setLsbDisplay(false); - } - - ui->glSpectrum->setCenterFrequency(m_rate/4); - ui->glSpectrum->setSampleRate(m_rate/2); - ui->glSpectrum->setSsbSpectrum(true); - } - else - { - m_channelMarker.setSidebands(ChannelMarker::dsb); - - ui->glSpectrum->setCenterFrequency(0); - ui->glSpectrum->setSampleRate(m_rate); - ui->glSpectrum->setLsbDisplay(false); - ui->glSpectrum->setSsbSpectrum(false); - } - - -} - -void ChannelAnalyzerNGGUI::setFiltersUIBoundaries() -{ - if (ui->BW->value() < -m_rate/200) { - ui->BW->setValue(-m_rate/200); - m_channelMarker.setBandwidth(-m_rate*2); - } else if (ui->BW->value() > m_rate/200) { - ui->BW->setValue(m_rate/200); - m_channelMarker.setBandwidth(m_rate*2); - } - - if (ui->lowCut->value() < -m_rate/200) { - ui->lowCut->setValue(-m_rate/200); - m_channelMarker.setLowCutoff(-m_rate); - } else if (ui->lowCut->value() > m_rate/200) { - ui->lowCut->setValue(m_rate/200); - m_channelMarker.setLowCutoff(m_rate); - } - - if (ui->ssb->isChecked()) { - ui->BW->setMinimum(-m_rate/200); - ui->lowCut->setMinimum(-m_rate/200); - } else { - ui->BW->setMinimum(0); - ui->lowCut->setMinimum(-m_rate/200); - ui->lowCut->setValue(0); - } - - ui->BW->setMaximum(m_rate/200); - ui->lowCut->setMaximum(m_rate/200); -} - -void ChannelAnalyzerNGGUI::blockApplySettings(bool block) -{ - ui->glScope->blockSignals(block); - ui->glSpectrum->blockSignals(block); - m_doApplySettings = !block; -} - -void ChannelAnalyzerNGGUI::applySettings() -{ - if (m_doApplySettings) - { - setTitleColor(m_channelMarker.getColor()); - ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - - int sampleRate = getRequestedChannelSampleRate(); - - ChannelAnalyzerNG::MsgConfigureChannelizer *msgChannelizer = ChannelAnalyzerNG::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency()); - m_channelAnalyzer->getInputMessageQueue()->push(msgChannelizer); - - ChannelAnalyzerNG::MsgConfigureChannelizer *msg = - ChannelAnalyzerNG::MsgConfigureChannelizer::create( - sampleRate, - m_channelMarker.getCenterFrequency()); - m_channelAnalyzer->getInputMessageQueue()->push(msg); - -// m_channelizer->configure(m_channelizer->getInputMessageQueue(), -// //m_channelizer->getInputSampleRate(), -// getRequestedChannelSampleRate(), -// m_channelMarker.getCenterFrequency()); - - m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), - //m_channelizer->getInputSampleRate(), // TODO: specify required channel sample rate - sampleRate, // TODO: specify required channel sample rate - ui->BW->value() * 100.0, - ui->lowCut->value() * 100.0, - m_spanLog2, - ui->ssb->isChecked()); - } -} - -void ChannelAnalyzerNGGUI::leaveEvent(QEvent*) -{ - blockApplySettings(true); - m_channelMarker.setHighlighted(false); - blockApplySettings(false); -} - -void ChannelAnalyzerNGGUI::enterEvent(QEvent*) -{ - blockApplySettings(true); - m_channelMarker.setHighlighted(true); - blockApplySettings(false); -} - +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "chanalyzernggui.h" + +#include +#include +#include +#include + +#include "dsp/threadedbasebandsamplesink.h" +#include "ui_chanalyzernggui.h" +#include "dsp/spectrumscopengcombovis.h" +#include "dsp/spectrumvis.h" +#include "dsp/scopevis.h" +#include "gui/glspectrum.h" +#include "gui/glscopeng.h" +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "util/db.h" +#include "gui/basicchannelsettingswidget.h" +#include "dsp/dspengine.h" +#include "mainwindow.h" + +#include "chanalyzerng.h" + +const QString ChannelAnalyzerNGGUI::m_channelID = "sdrangel.channel.chanalyzerng"; + +ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) +{ + ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceAPI); + return gui; +} + +void ChannelAnalyzerNGGUI::destroy() +{ + delete this; +} + +void ChannelAnalyzerNGGUI::setName(const QString& name) +{ + setObjectName(name); +} + +QString ChannelAnalyzerNGGUI::getName() const +{ + return objectName(); +} + +qint64 ChannelAnalyzerNGGUI::getCenterFrequency() const +{ + return m_channelMarker.getCenterFrequency(); +} + +void ChannelAnalyzerNGGUI::setCenterFrequency(qint64 centerFrequency) +{ + m_channelMarker.setCenterFrequency(centerFrequency); + applySettings(); +} + +void ChannelAnalyzerNGGUI::resetToDefaults() +{ + blockApplySettings(true); + + ui->useRationalDownsampler->setChecked(false); + ui->BW->setValue(30); + ui->deltaFrequency->setValue(0); + ui->spanLog2->setCurrentIndex(3); + + blockApplySettings(false); + applySettings(); +} + +QByteArray ChannelAnalyzerNGGUI::serialize() const +{ + SimpleSerializer s(1); + s.writeS32(1, m_channelMarker.getCenterFrequency()); + s.writeS32(2, ui->BW->value()); + s.writeBlob(3, ui->spectrumGUI->serialize()); + s.writeU32(4, m_channelMarker.getColor().rgb()); + s.writeS32(5, ui->lowCut->value()); + s.writeS32(6, ui->spanLog2->currentIndex()); + s.writeBool(7, ui->ssb->isChecked()); + s.writeBlob(8, ui->scopeGUI->serialize()); + s.writeU64(9, ui->channelSampleRate->getValueNew()); + return s.final(); +} + +bool ChannelAnalyzerNGGUI::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + quint32 u32tmp; + quint64 u64tmp; + qint32 tmp, spanLog2, bw, lowCut; + bool tmpBool; + + blockApplySettings(true); + m_channelMarker.blockSignals(true); + + d.readS32(1, &tmp, 0); + m_channelMarker.setCenterFrequency(tmp); + d.readS32(2, &bw, 30); + d.readBlob(3, &bytetmp); + ui->spectrumGUI->deserialize(bytetmp); + + if(d.readU32(4, &u32tmp)) + { + m_channelMarker.setColor(u32tmp); + } + + d.readS32(5, &lowCut, 3); + d.readS32(6, &spanLog2, 3); + d.readBool(7, &tmpBool, false); + ui->ssb->setChecked(tmpBool); + d.readBlob(8, &bytetmp); + ui->scopeGUI->deserialize(bytetmp); + d.readU64(9, &u64tmp, 2000U); + ui->channelSampleRate->setValue(u64tmp); + + blockApplySettings(false); + m_channelMarker.blockSignals(false); + + ui->spanLog2->setCurrentIndex(spanLog2); + setNewFinalRate(spanLog2); + ui->BW->setValue(bw); + ui->lowCut->setValue(lowCut); // does applySettings(); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool ChannelAnalyzerNGGUI::handleMessage(const Message& message __attribute__((unused))) +{ + if (ChannelAnalyzerNG::MsgReportChannelSampleRateChanged::match(message)) + { + setNewFinalRate(m_spanLog2); + applySettings(); + return true; + } + + return false; +} + +void ChannelAnalyzerNGGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier()); + + if (handleMessage(*message)) + { + delete message; + } + } +} + +void ChannelAnalyzerNGGUI::viewChanged() +{ + applySettings(); +} + +void ChannelAnalyzerNGGUI::tick() +{ + double powDb = CalcDb::dbPower(m_channelAnalyzer->getMagSq()); + m_channelPowerDbAvg.feed(powDb); + ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.average(), 0, 'f', 1)); +} + +//void ChannelAnalyzerNGGUI::channelizerInputSampleRateChanged() +//{ +// //ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); +// setNewFinalRate(m_spanLog2); +// applySettings(); +//} + +void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value) +{ + ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); + + if (ui->useRationalDownsampler->isChecked()) + { + qDebug("ChannelAnalyzerNGGUI::on_channelSampleRate_changed: %llu", value); + setNewFinalRate(m_spanLog2); + applySettings(); + } +} + +void ChannelAnalyzerNGGUI::on_useRationalDownsampler_toggled(bool checked __attribute__((unused))) +{ + setNewFinalRate(m_spanLog2); + applySettings(); +} + +int ChannelAnalyzerNGGUI::getRequestedChannelSampleRate() +{ + if (ui->useRationalDownsampler->isChecked()) { + return ui->channelSampleRate->getValueNew(); + } else { + return m_channelAnalyzer->getChannelizer()->getInputSampleRate(); + } +} + +void ChannelAnalyzerNGGUI::on_deltaFrequency_changed(qint64 value) +{ + m_channelMarker.setCenterFrequency(value); +} + +void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value) +{ + m_channelMarker.setBandwidth(value * 100 * 2); + + if (ui->ssb->isChecked()) + { + QString s = QString::number(value/10.0, 'f', 1); + ui->BWText->setText(tr("%1k").arg(s)); + } + else + { + QString s = QString::number(value/5.0, 'f', 1); // BW = value * 2 + ui->BWText->setText(tr("%1k").arg(s)); + } + + displayBandwidth(); + on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); +} + +int ChannelAnalyzerNGGUI::getEffectiveLowCutoff(int lowCutoff) +{ + int ssbBW = m_channelMarker.getBandwidth() / 2; + int effectiveLowCutoff = lowCutoff; + const int guard = 100; + + if (ssbBW < 0) { + if (effectiveLowCutoff < ssbBW + guard) { + effectiveLowCutoff = ssbBW + guard; + } + if (effectiveLowCutoff > 0) { + effectiveLowCutoff = 0; + } + } else { + if (effectiveLowCutoff > ssbBW - guard) { + effectiveLowCutoff = ssbBW - guard; + } + if (effectiveLowCutoff < 0) { + effectiveLowCutoff = 0; + } + } + + return effectiveLowCutoff; +} + +void ChannelAnalyzerNGGUI::on_lowCut_valueChanged(int value) +{ + int lowCutoff = getEffectiveLowCutoff(value * 100); + m_channelMarker.setLowCutoff(lowCutoff); + QString s = QString::number(lowCutoff/1000.0, 'f', 1); + ui->lowCutText->setText(tr("%1k").arg(s)); + ui->lowCut->setValue(lowCutoff/100); + applySettings(); +} + +void ChannelAnalyzerNGGUI::on_spanLog2_currentIndexChanged(int index) +{ + if (setNewFinalRate(index)) { + applySettings(); + } + +} + +void ChannelAnalyzerNGGUI::on_ssb_toggled(bool checked) +{ + //int bw = m_channelMarker.getBandwidth(); + + if (checked) + { + setFiltersUIBoundaries(); + + ui->BWLabel->setText("LP"); + QString s = QString::number(ui->BW->value()/10.0, 'f', 1); // bw/2 + ui->BWText->setText(tr("%1k").arg(s)); + + on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); + } + else + { + if (ui->BW->value() < 0) { + ui->BW->setValue(-ui->BW->value()); + } + + setFiltersUIBoundaries(); + //m_channelMarker.setBandwidth(ui->BW->value() * 200.0); + + ui->BWLabel->setText("BP"); + QString s = QString::number(ui->BW->value()/5.0, 'f', 1); // bw + ui->BWText->setText(tr("%1k").arg(s)); + + ui->lowCut->setEnabled(false); + ui->lowCut->setValue(0); + ui->lowCutText->setText("0.0k"); + } + + applySettings(); + displayBandwidth(); +} + +void ChannelAnalyzerNGGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) +{ + /* + if((widget == ui->spectrumContainer) && (m_ssbDemod != NULL)) + m_ssbDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); + */ +} + +void ChannelAnalyzerNGGUI::onMenuDoubleClicked() +{ + if(!m_basicSettingsShown) { + m_basicSettingsShown = true; + BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(&m_channelMarker, this); + bcsw->show(); + } +} + +ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent) : + RollupWidget(parent), + ui(new Ui::ChannelAnalyzerNGGUI), + m_pluginAPI(pluginAPI), + m_deviceAPI(deviceAPI), + m_channelMarker(this), + m_basicSettingsShown(false), + m_doApplySettings(true), + m_rate(6000), + m_spanLog2(0), + m_channelPowerDbAvg(40,0) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); + + m_spectrumVis = new SpectrumVis(ui->glSpectrum); + m_scopeVis = new ScopeVisNG(ui->glScope); + m_spectrumScopeComboVis = new SpectrumScopeNGComboVis(m_spectrumVis, m_scopeVis); + m_channelAnalyzer = new ChannelAnalyzerNG(m_deviceAPI); + m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis); + m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue()); +// m_channelizer = new DownChannelizer(m_channelAnalyzer); +// m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); +// connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged())); +// m_deviceAPI->addThreadedSink(m_threadedChannelizer); + + ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); + ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); + + ui->channelSampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); + ui->channelSampleRate->setValueRange(7, 2000U, 9999999U); + + ui->glSpectrum->setCenterFrequency(m_rate/2); + ui->glSpectrum->setSampleRate(m_rate); + ui->glSpectrum->setDisplayWaterfall(true); + ui->glSpectrum->setDisplayMaxHold(true); + ui->glSpectrum->setSsbSpectrum(false); + ui->glSpectrum->setLsbDisplay(false); + ui->BWLabel->setText("BP"); + + ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer()); + ui->glScope->connectTimer(MainWindow::getInstance()->getMasterTimer()); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + + //m_channelMarker = new ChannelMarker(this); + m_channelMarker.setColor(Qt::gray); + m_channelMarker.setBandwidth(m_rate); + m_channelMarker.setSidebands(ChannelMarker::usb); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setVisible(true); + + connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); + + m_deviceAPI->registerChannelInstance(m_channelID, this); + m_deviceAPI->addChannelMarker(&m_channelMarker); + m_deviceAPI->addRollupWidget(this); + + ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); + ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + applySettings(); + setNewFinalRate(m_spanLog2); +} + +ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI() +{ + m_deviceAPI->removeChannelInstance(this); +// m_deviceAPI->removeThreadedSink(m_threadedChannelizer); +// delete m_threadedChannelizer; +// delete m_channelizer; + delete m_channelAnalyzer; + delete m_spectrumVis; + delete m_scopeVis; + delete m_spectrumScopeComboVis; + //delete m_channelMarker; + delete ui; +} + +bool ChannelAnalyzerNGGUI::setNewFinalRate(int spanLog2) +{ + qDebug("ChannelAnalyzerNGGUI::setNewRate"); + + if ((spanLog2 < 0) || (spanLog2 > 6)) { + return false; + } + + m_spanLog2 = spanLog2; + //m_rate = 48000 / (1<getInputSampleRate() / (1<spanText->setText(tr("%1 kS/s").arg(s)); + + displayBandwidth(); + + ui->glScope->setSampleRate(m_rate); + m_scopeVis->setSampleRate(m_rate); + + return true; +} + +void ChannelAnalyzerNGGUI::displayBandwidth() +{ + if (ui->ssb->isChecked()) + { + if (ui->BW->value() < 0) + { + m_channelMarker.setSidebands(ChannelMarker::lsb); + ui->glSpectrum->setLsbDisplay(true); + } + else + { + m_channelMarker.setSidebands(ChannelMarker::usb); + ui->glSpectrum->setLsbDisplay(false); + } + + ui->glSpectrum->setCenterFrequency(m_rate/4); + ui->glSpectrum->setSampleRate(m_rate/2); + ui->glSpectrum->setSsbSpectrum(true); + } + else + { + m_channelMarker.setSidebands(ChannelMarker::dsb); + + ui->glSpectrum->setCenterFrequency(0); + ui->glSpectrum->setSampleRate(m_rate); + ui->glSpectrum->setLsbDisplay(false); + ui->glSpectrum->setSsbSpectrum(false); + } + + +} + +void ChannelAnalyzerNGGUI::setFiltersUIBoundaries() +{ + if (ui->BW->value() < -m_rate/200) { + ui->BW->setValue(-m_rate/200); + m_channelMarker.setBandwidth(-m_rate*2); + } else if (ui->BW->value() > m_rate/200) { + ui->BW->setValue(m_rate/200); + m_channelMarker.setBandwidth(m_rate*2); + } + + if (ui->lowCut->value() < -m_rate/200) { + ui->lowCut->setValue(-m_rate/200); + m_channelMarker.setLowCutoff(-m_rate); + } else if (ui->lowCut->value() > m_rate/200) { + ui->lowCut->setValue(m_rate/200); + m_channelMarker.setLowCutoff(m_rate); + } + + if (ui->ssb->isChecked()) { + ui->BW->setMinimum(-m_rate/200); + ui->lowCut->setMinimum(-m_rate/200); + } else { + ui->BW->setMinimum(0); + ui->lowCut->setMinimum(-m_rate/200); + ui->lowCut->setValue(0); + } + + ui->BW->setMaximum(m_rate/200); + ui->lowCut->setMaximum(m_rate/200); +} + +void ChannelAnalyzerNGGUI::blockApplySettings(bool block) +{ + ui->glScope->blockSignals(block); + ui->glSpectrum->blockSignals(block); + m_doApplySettings = !block; +} + +void ChannelAnalyzerNGGUI::applySettings() +{ + if (m_doApplySettings) + { + setTitleColor(m_channelMarker.getColor()); + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + + int sampleRate = getRequestedChannelSampleRate(); + + ChannelAnalyzerNG::MsgConfigureChannelizer *msgChannelizer = ChannelAnalyzerNG::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency()); + m_channelAnalyzer->getInputMessageQueue()->push(msgChannelizer); + + ChannelAnalyzerNG::MsgConfigureChannelizer *msg = + ChannelAnalyzerNG::MsgConfigureChannelizer::create( + sampleRate, + m_channelMarker.getCenterFrequency()); + m_channelAnalyzer->getInputMessageQueue()->push(msg); + +// m_channelizer->configure(m_channelizer->getInputMessageQueue(), +// //m_channelizer->getInputSampleRate(), +// getRequestedChannelSampleRate(), +// m_channelMarker.getCenterFrequency()); + + m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), + //m_channelizer->getInputSampleRate(), // TODO: specify required channel sample rate + sampleRate, // TODO: specify required channel sample rate + ui->BW->value() * 100.0, + ui->lowCut->value() * 100.0, + m_spanLog2, + ui->ssb->isChecked()); + } +} + +void ChannelAnalyzerNGGUI::leaveEvent(QEvent*) +{ + blockApplySettings(true); + m_channelMarker.setHighlighted(false); + blockApplySettings(false); +} + +void ChannelAnalyzerNGGUI::enterEvent(QEvent*) +{ + blockApplySettings(true); + m_channelMarker.setHighlighted(true); + blockApplySettings(false); +} + diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index 23fe94d54..94929d2d5 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -186,7 +186,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget m_amDemod = new AMDemod(m_deviceAPI); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); diff --git a/plugins/channelrx/demodatv/atvdemodgui.cpp b/plugins/channelrx/demodatv/atvdemodgui.cpp index 7683dbc22..114cb6673 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.cpp +++ b/plugins/channelrx/demodatv/atvdemodgui.cpp @@ -1,773 +1,773 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 F4HKW // -// for F4EXB / SDRAngel // -// // -// 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 . // -/////////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "atvdemodgui.h" - -#include "device/devicesourceapi.h" -#include "dsp/downchannelizer.h" - -#include "dsp/threadedbasebandsamplesink.h" -#include "dsp/scopevisng.h" -#include "ui_atvdemodgui.h" -#include "plugin/pluginapi.h" -#include "util/simpleserializer.h" -#include "util/db.h" -#include "gui/basicchannelsettingswidget.h" -#include "dsp/dspengine.h" -#include "mainwindow.h" - -#include "atvdemod.h" - -const QString ATVDemodGUI::m_strChannelID = "sdrangel.channel.demodatv"; - -ATVDemodGUI* ATVDemodGUI::create(PluginAPI* objPluginAPI, - DeviceSourceAPI *objDeviceAPI) -{ - ATVDemodGUI* gui = new ATVDemodGUI(objPluginAPI, objDeviceAPI); - return gui; -} - -void ATVDemodGUI::destroy() -{ - delete this; -} - -void ATVDemodGUI::setName(const QString& strName) -{ - setObjectName(strName); -} - -QString ATVDemodGUI::getName() const -{ - return objectName(); -} - -qint64 ATVDemodGUI::getCenterFrequency() const -{ - return m_channelMarker.getCenterFrequency(); -} - -void ATVDemodGUI::setCenterFrequency(qint64 intCenterFrequency) -{ - m_channelMarker.setCenterFrequency(intCenterFrequency); - applySettings(); -} - -void ATVDemodGUI::resetToDefaults() -{ - blockApplySettings(true); - - //********** ATV Default values ********** - ui->synchLevel->setValue(100); - ui->blackLevel->setValue(310); - ui->lineTime->setValue(0); - ui->topTime->setValue(3); - ui->modulation->setCurrentIndex(0); - ui->fps->setCurrentIndex(0); - ui->hSync->setChecked(true); - ui->vSync->setChecked(true); - ui->halfImage->setChecked(false); - ui->invertVideo->setChecked(false); - ui->standard->setCurrentIndex(1); - - //********** RF Default values ********** - ui->decimatorEnable->setChecked(false); - ui->rfFiltering->setChecked(false); - ui->rfBW->setValue(10); - ui->rfOppBW->setValue(10); - ui->bfo->setValue(0); - ui->fmDeviation->setValue(250); - - blockApplySettings(false); - lineTimeUpdate(); - topTimeUpdate(); - applySettings(); -} - -QByteArray ATVDemodGUI::serialize() const -{ - SimpleSerializer s(1); - - s.writeS32(1, m_channelMarker.getCenterFrequency()); - s.writeU32(2, m_channelMarker.getColor().rgb()); - s.writeS32(3, ui->synchLevel->value()); - s.writeS32(4, ui->blackLevel->value()); - s.writeS32(5, ui->lineTime->value()); - s.writeS32(6, ui->topTime->value()); - s.writeS32(7, ui->modulation->currentIndex()); - s.writeS32(8, ui->fps->currentIndex()); - s.writeBool(9, ui->hSync->isChecked()); - s.writeBool(10, ui->vSync->isChecked()); - s.writeBool(11, ui->halfImage->isChecked()); - s.writeS32(12, ui->rfBW->value()); - s.writeS32(13, ui->rfOppBW->value()); - s.writeS32(14, ui->bfo->value()); - s.writeBool(15, ui->invertVideo->isChecked()); - s.writeS32(16, ui->nbLines->currentIndex()); - s.writeS32(17, ui->fmDeviation->value()); - s.writeS32(18, ui->standard->currentIndex()); - - return s.final(); -} - -bool ATVDemodGUI::deserialize(const QByteArray& arrData) -{ - SimpleDeserializer d(arrData); - - if (!d.isValid()) - { - resetToDefaults(); - return false; - } - - if (d.getVersion() == 1) - { - QByteArray bytetmp; - int tmp; - bool booltmp; - - blockApplySettings(true); - m_channelMarker.blockSignals(true); - - d.readS32(1, &tmp, 0); - m_channelMarker.setCenterFrequency(tmp); - -// if (d.readU32(2, &u32tmp)) { -// m_objChannelMarker.setColor(u32tmp); -// } else { -// m_objChannelMarker.setColor(Qt::white); -// } - - d.readS32(3, &tmp, 100); - ui->synchLevel->setValue(tmp); - d.readS32(4, &tmp, 310); - ui->blackLevel->setValue(tmp); - d.readS32(5, &tmp, 0); - ui->lineTime->setValue(tmp); - d.readS32(6, &tmp, 3); - ui->topTime->setValue(tmp); - d.readS32(7, &tmp, 0); - ui->modulation->setCurrentIndex(tmp); - d.readS32(8, &tmp, 0); - ui->fps->setCurrentIndex(tmp); - d.readBool(9, &booltmp, true); - ui->hSync->setChecked(booltmp); - d.readBool(10, &booltmp, true); - ui->vSync->setChecked(booltmp); - d.readBool(11, &booltmp, false); - ui->halfImage->setChecked(booltmp); - d.readS32(12, &tmp, 10); - ui->rfBW->setValue(tmp); - d.readS32(13, &tmp, 10); - ui->rfOppBW->setValue(tmp); - d.readS32(14, &tmp, 10); - ui->bfo->setValue(tmp); - d.readBool(15, &booltmp, true); - ui->invertVideo->setChecked(booltmp); - d.readS32(16, &tmp, 0); - ui->nbLines->setCurrentIndex(tmp); - d.readS32(17, &tmp, 250); - ui->fmDeviation->setValue(tmp); - d.readS32(18, &tmp, 1); - ui->standard->setCurrentIndex(tmp); - - blockApplySettings(false); - m_channelMarker.blockSignals(false); - - lineTimeUpdate(); - topTimeUpdate(); - applySettings(); - return true; - } - else - { - resetToDefaults(); - return false; - } -} - -bool ATVDemodGUI::handleMessage(const Message& objMessage) -{ - if (ATVDemod::MsgReportEffectiveSampleRate::match(objMessage)) - { - int sampleRate = ((ATVDemod::MsgReportEffectiveSampleRate&)objMessage).getSampleRate(); - int nbPointsPerLine = ((ATVDemod::MsgReportEffectiveSampleRate&)objMessage).getNbPointsPerLine(); - ui->channelSampleRateText->setText(tr("%1k").arg(sampleRate/1000.0f, 0, 'f', 2)); - ui->nbPointsPerLineText->setText(tr("%1p").arg(nbPointsPerLine)); - m_scopeVis->setSampleRate(sampleRate); - setRFFiltersSlidersRange(sampleRate); - lineTimeUpdate(); - topTimeUpdate(); - - return true; - } - else - { - return false; - } -} - -void ATVDemodGUI::viewChanged() -{ - qDebug("ATVDemodGUI::viewChanged"); - applySettings(); - applyRFSettings(); -} - -void ATVDemodGUI::channelSampleRateChanged() -{ - qDebug("ATVDemodGUI::channelSampleRateChanged"); - applySettings(); - applyRFSettings(); -} - -void ATVDemodGUI::handleSourceMessages() -{ - Message* message; - - while ((message = getInputMessageQueue()->pop()) != 0) - { - if (handleMessage(*message)) - { - delete message; - } - } -} - -void ATVDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) -{ -} - -void ATVDemodGUI::onMenuDoubleClicked() -{ - if (!m_blnBasicSettingsShown) - { - m_blnBasicSettingsShown = true; - BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget( - &m_channelMarker, this); - bcsw->show(); - } -} - -ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI, - QWidget* objParent) : - RollupWidget(objParent), - ui(new Ui::ATVDemodGUI), - m_pluginAPI(objPluginAPI), - m_deviceAPI(objDeviceAPI), - m_channelMarker(this), - m_blnBasicSettingsShown(false), - m_blnDoApplySettings(true), - m_objMagSqAverage(40, 0), - m_intTickCount(0) -{ - ui->setupUi(this); - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); - - m_scopeVis = new ScopeVisNG(ui->glScope); - m_atvDemod = new ATVDemod(m_deviceAPI); - m_atvDemod->setScopeSink(m_scopeVis); - m_atvDemod->setMessageQueueToGUI(getInputMessageQueue()); - m_atvDemod->setATVScreen(ui->screenTV); - - m_channelizer = new DownChannelizer(m_atvDemod); - m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); - m_deviceAPI->addThreadedSink(m_threadedChannelizer); - - ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms - - ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); - ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); - - connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); - - //m_objPluginAPI->addThreadedSink(m_objThreadedChannelizer); - m_channelMarker.setColor(Qt::white); - m_channelMarker.setMovable(false); - m_channelMarker.setBandwidth(6000000); - m_channelMarker.setCenterFrequency(0); - m_channelMarker.setVisible(true); - setTitleColor(m_channelMarker.getColor()); - - connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); - - m_deviceAPI->registerChannelInstance(m_strChannelID, this); - m_deviceAPI->addChannelMarker(&m_channelMarker); - m_deviceAPI->addRollupWidget(this); - - //ui->screenTV->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer()); - - m_objMagSqAverage.resize(4, 1.0); - - ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); - - resetToDefaults(); // does applySettings() - - ui->scopeGUI->setPreTrigger(1); - ScopeVisNG::TraceData traceData; - traceData.m_amp = 2.0; // amplification factor - traceData.m_ampIndex = 1; // this is second step - traceData.m_ofs = 0.5; // direct offset - traceData.m_ofsCoarse = 50; // this is 50 coarse steps - ui->scopeGUI->changeTrace(0, traceData); - ui->scopeGUI->focusOnTrace(0); // re-focus to take changes into account in the GUI - ScopeVisNG::TriggerData triggerData; - triggerData.m_triggerLevel = 0.1; - triggerData.m_triggerLevelCoarse = 10; - triggerData.m_triggerPositiveEdge = false; - ui->scopeGUI->changeTrigger(0, triggerData); - ui->scopeGUI->focusOnTrigger(0); // re-focus to take changes into account in the GUI - - connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); - - QChar delta = QChar(0x94, 0x03); - ui->fmDeviationLabel->setText(delta); -} - -ATVDemodGUI::~ATVDemodGUI() -{ - m_deviceAPI->removeChannelInstance(this); - m_deviceAPI->removeThreadedSink(m_threadedChannelizer); - delete m_threadedChannelizer; - delete m_channelizer; - delete m_atvDemod; - delete m_scopeVis; - delete ui; -} - -void ATVDemodGUI::blockApplySettings(bool blnBlock) -{ - m_blnDoApplySettings = !blnBlock; -} - -void ATVDemodGUI::applySettings() -{ - if (m_blnDoApplySettings) - { - ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - - m_channelizer->configure(m_channelizer->getInputMessageQueue(), - m_channelizer->getInputSampleRate(), // always use maximum available bandwidth - m_channelMarker.getCenterFrequency()); - - m_atvDemod->configure(m_atvDemod->getInputMessageQueue(), - getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) + ui->lineTime->value() * m_fltLineTimeMultiplier, - getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f) + ui->topTime->value() * m_fltTopTimeMultiplier, - getFps(ui->fps->currentIndex()), - (ATVDemod::ATVStd) ui->standard->currentIndex(), - getNumberOfLines(ui->nbLines->currentIndex()), - (ui->halfImage->checkState() == Qt::Checked) ? 0.5f : 1.0f, - ui->synchLevel->value() / 1000.0f, - ui->blackLevel->value() / 1000.0f, - ui->hSync->isChecked(), - ui->vSync->isChecked(), - ui->invertVideo->isChecked(), - ui->screenTabWidget->currentIndex()); - - qDebug() << "ATVDemodGUI::applySettings:" - << " m_objChannelizer.inputSampleRate: " << m_channelizer->getInputSampleRate() - << " m_objATVDemod.sampleRate: " << m_atvDemod->getSampleRate(); - } -} - -void ATVDemodGUI::applyRFSettings() -{ - if (m_blnDoApplySettings) - { - m_atvDemod->configureRF(m_atvDemod->getInputMessageQueue(), - (ATVDemod::ATVModulation) ui->modulation->currentIndex(), - ui->rfBW->value() * m_rfSliderDivisor * 1.0f, - ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f, - ui->rfFiltering->isChecked(), - ui->decimatorEnable->isChecked(), - ui->bfo->value(), - ui->fmDeviation->value() / 500.0f); - } -} - -void ATVDemodGUI::setChannelMarkerBandwidth() -{ - m_blnDoApplySettings = false; // avoid infinite recursion - - if (ui->rfFiltering->isChecked()) // FFT filter - { - m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); - m_channelMarker.setOppositeBandwidth(ui->rfOppBW->value()*m_rfSliderDivisor); - - if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_LSB) { - m_channelMarker.setSidebands(ChannelMarker::vlsb); - } else if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_USB) { - m_channelMarker.setSidebands(ChannelMarker::vusb); - } else { - m_channelMarker.setSidebands(ChannelMarker::vusb); - } - } - else - { - if (ui->decimatorEnable->isChecked()) { - m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); - } else { - m_channelMarker.setBandwidth(m_channelizer->getInputSampleRate()); - } - - m_channelMarker.setSidebands(ChannelMarker::dsb); - } - - m_blnDoApplySettings = true; -} - -void ATVDemodGUI::setRFFiltersSlidersRange(int sampleRate) -{ - // RF filters sliders range - int scaleFactor = (int) std::log10(sampleRate/2); - m_rfSliderDivisor = std::pow(10.0, scaleFactor-1); - - if (sampleRate/m_rfSliderDivisor < 50) { - m_rfSliderDivisor /= 10; - } - - if (ui->rfFiltering->isChecked()) - { - ui->rfBW->setMaximum((sampleRate) / (2*m_rfSliderDivisor)); - ui->rfOppBW->setMaximum((sampleRate) / (2*m_rfSliderDivisor)); - } - else - { - ui->rfBW->setMaximum((sampleRate) / m_rfSliderDivisor); - ui->rfOppBW->setMaximum((sampleRate) / m_rfSliderDivisor); - } - - ui->rfBWText->setText(QString("%1k").arg((ui->rfBW->value() * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); - ui->rfOppBWText->setText(QString("%1k").arg((ui->rfOppBW->value() * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); -} - -void ATVDemodGUI::leaveEvent(QEvent*) -{ - blockApplySettings(true); - m_channelMarker.setHighlighted(false); - blockApplySettings(false); -} - -void ATVDemodGUI::enterEvent(QEvent*) -{ - blockApplySettings(true); - m_channelMarker.setHighlighted(true); - blockApplySettings(false); -} - -void ATVDemodGUI::tick() -{ - if (m_intTickCount < 4) // ~200 ms - { - m_intTickCount++; - } - else - { - if (m_atvDemod) - { - m_objMagSqAverage.feed(m_atvDemod->getMagSq()); - double magSqDB = CalcDb::dbPower(m_objMagSqAverage.average() / (1<<30)); - ui->channePowerText->setText(tr("%1 dB").arg(magSqDB, 0, 'f', 1)); - - if (m_atvDemod->getBFOLocked()) { - ui->bfoLockedLabel->setStyleSheet("QLabel { background-color : green; }"); - } else { - ui->bfoLockedLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }"); - } - } - - m_intTickCount = 0; - } - - return; -} - -void ATVDemodGUI::on_synchLevel_valueChanged(int value) -{ - applySettings(); - ui->synchLevelText->setText(QString("%1 mV").arg(value)); -} - -void ATVDemodGUI::on_blackLevel_valueChanged(int value) -{ - applySettings(); - ui->blackLevelText->setText(QString("%1 mV").arg(value)); -} - -void ATVDemodGUI::on_lineTime_valueChanged(int value) -{ - ui->lineTime->setToolTip(QString("Line length adjustment (%1)").arg(value)); - lineTimeUpdate(); - applySettings(); -} - -void ATVDemodGUI::on_topTime_valueChanged(int value) -{ - ui->topTime->setToolTip(QString("Horizontal sync pulse length adjustment (%1)").arg(value)); - topTimeUpdate(); - applySettings(); -} - -void ATVDemodGUI::on_hSync_clicked() -{ - applySettings(); -} - -void ATVDemodGUI::on_vSync_clicked() -{ - applySettings(); -} - -void ATVDemodGUI::on_invertVideo_clicked() -{ - applySettings(); -} - -void ATVDemodGUI::on_halfImage_clicked() -{ - applySettings(); -} - -void ATVDemodGUI::on_nbLines_currentIndexChanged(int index __attribute__((unused))) -{ - lineTimeUpdate(); - topTimeUpdate(); - applySettings(); -} - -void ATVDemodGUI::on_fps_currentIndexChanged(int index __attribute__((unused))) -{ - lineTimeUpdate(); - topTimeUpdate(); - applySettings(); -} - -void ATVDemodGUI::on_standard_currentIndexChanged(int index __attribute__((unused))) -{ - applySettings(); -} - -void ATVDemodGUI::on_reset_clicked(bool checked __attribute__((unused))) -{ - resetToDefaults(); -} - -void ATVDemodGUI::on_modulation_currentIndexChanged(int index __attribute__((unused))) -{ - setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate()); - setChannelMarkerBandwidth(); - applyRFSettings(); -} - -void ATVDemodGUI::on_rfBW_valueChanged(int value) -{ - ui->rfBWText->setText(QString("%1k").arg((value * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); - setChannelMarkerBandwidth(); - applyRFSettings(); -} - -void ATVDemodGUI::on_rfOppBW_valueChanged(int value) -{ - ui->rfOppBWText->setText(QString("%1k").arg((value * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); - setChannelMarkerBandwidth(); - applyRFSettings(); -} - -void ATVDemodGUI::on_rfFiltering_toggled(bool checked __attribute__((unused))) -{ - setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate()); - setChannelMarkerBandwidth(); - applyRFSettings(); -} - -void ATVDemodGUI::on_decimatorEnable_toggled(bool checked __attribute__((unused))) -{ - setChannelMarkerBandwidth(); - applyRFSettings(); -} - -void ATVDemodGUI::on_deltaFrequency_changed(qint64 value) -{ - m_channelMarker.setCenterFrequency(value); -} - -void ATVDemodGUI::on_bfo_valueChanged(int value) -{ - ui->bfoText->setText(QString("%1").arg(value * 1.0, 0, 'f', 0)); - applyRFSettings(); -} - -void ATVDemodGUI::on_fmDeviation_valueChanged(int value) -{ - ui->fmDeviationText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); - applyRFSettings(); -} - -void ATVDemodGUI::on_screenTabWidget_currentChanged(int index __attribute__((unused))) -{ - applySettings(); -} - -void ATVDemodGUI::lineTimeUpdate() -{ - float nominalLineTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()); - int lineTimeScaleFactor = (int) std::log10(nominalLineTime); - - if (m_atvDemod->getEffectiveSampleRate() == 0) { - m_fltLineTimeMultiplier = std::pow(10.0, lineTimeScaleFactor-3); - } else { - m_fltLineTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate(); - } - - float lineTime = nominalLineTime + m_fltLineTimeMultiplier * ui->lineTime->value(); - - if (lineTime < 0.0) - ui->lineTimeText->setText("invalid"); - else if(lineTime < 0.000001) - ui->lineTimeText->setText(tr("%1 ns").arg(lineTime * 1000000000.0, 0, 'f', 2)); - else if(lineTime < 0.001) - ui->lineTimeText->setText(tr("%1 µs").arg(lineTime * 1000000.0, 0, 'f', 2)); - else if(lineTime < 1.0) - ui->lineTimeText->setText(tr("%1 ms").arg(lineTime * 1000.0, 0, 'f', 2)); - else - ui->lineTimeText->setText(tr("%1 s").arg(lineTime * 1.0, 0, 'f', 2)); -} - -void ATVDemodGUI::topTimeUpdate() -{ - float nominalTopTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f); - int topTimeScaleFactor = (int) std::log10(nominalTopTime); - - if (m_atvDemod->getEffectiveSampleRate() == 0) { - m_fltTopTimeMultiplier = std::pow(10.0, topTimeScaleFactor-3); - } else { - m_fltTopTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate(); - } - - float topTime = nominalTopTime + m_fltTopTimeMultiplier * ui->topTime->value(); - - if (topTime < 0.0) - ui->topTimeText->setText("invalid"); - else if (topTime < 0.000001) - ui->topTimeText->setText(tr("%1 ns").arg(topTime * 1000000000.0, 0, 'f', 2)); - else if(topTime < 0.001) - ui->topTimeText->setText(tr("%1 µs").arg(topTime * 1000000.0, 0, 'f', 2)); - else if(topTime < 1.0) - ui->topTimeText->setText(tr("%1 ms").arg(topTime * 1000.0, 0, 'f', 2)); - else - ui->topTimeText->setText(tr("%1 s").arg(topTime * 1.0, 0, 'f', 2)); -} - -float ATVDemodGUI::getFps(int fpsIndex) -{ - switch(fpsIndex) - { - case 0: - return 30.0f; - break; - case 2: - return 20.0f; - break; - case 3: - return 16.0f; - break; - case 4: - return 12.0f; - break; - case 5: - return 10.0f; - break; - case 6: - return 8.0f; - break; - case 7: - return 5.0f; - break; - case 8: - return 2.0f; - break; - case 9: - return 1.0f; - break; - case 1: - default: - return 25.0f; - break; - } -} - -float ATVDemodGUI::getNominalLineTime(int nbLinesIndex, int fpsIndex) -{ - float fps = getFps(fpsIndex); - int nbLines = getNumberOfLines(nbLinesIndex); - - return 1.0f / (nbLines * fps); -} - -int ATVDemodGUI::getNumberOfLines(int nbLinesIndex) -{ - switch(nbLinesIndex) - { - case 0: - return 640; - break; - case 2: - return 525; - break; - case 3: - return 480; - break; - case 4: - return 405; - break; - case 5: - return 360; - break; - case 6: - return 343; - break; - case 7: - return 240; - break; - case 8: - return 180; - break; - case 9: - return 120; - break; - case 10: - return 90; - break; - case 11: - return 60; - break; - case 12: - return 32; - break; - case 1: - default: - return 625; - break; - } -} +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 F4HKW // +// for F4EXB / SDRAngel // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "atvdemodgui.h" + +#include "device/devicesourceapi.h" +#include "dsp/downchannelizer.h" + +#include "dsp/threadedbasebandsamplesink.h" +#include "dsp/scopevisng.h" +#include "ui_atvdemodgui.h" +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "util/db.h" +#include "gui/basicchannelsettingswidget.h" +#include "dsp/dspengine.h" +#include "mainwindow.h" + +#include "atvdemod.h" + +const QString ATVDemodGUI::m_strChannelID = "sdrangel.channel.demodatv"; + +ATVDemodGUI* ATVDemodGUI::create(PluginAPI* objPluginAPI, + DeviceSourceAPI *objDeviceAPI) +{ + ATVDemodGUI* gui = new ATVDemodGUI(objPluginAPI, objDeviceAPI); + return gui; +} + +void ATVDemodGUI::destroy() +{ + delete this; +} + +void ATVDemodGUI::setName(const QString& strName) +{ + setObjectName(strName); +} + +QString ATVDemodGUI::getName() const +{ + return objectName(); +} + +qint64 ATVDemodGUI::getCenterFrequency() const +{ + return m_channelMarker.getCenterFrequency(); +} + +void ATVDemodGUI::setCenterFrequency(qint64 intCenterFrequency) +{ + m_channelMarker.setCenterFrequency(intCenterFrequency); + applySettings(); +} + +void ATVDemodGUI::resetToDefaults() +{ + blockApplySettings(true); + + //********** ATV Default values ********** + ui->synchLevel->setValue(100); + ui->blackLevel->setValue(310); + ui->lineTime->setValue(0); + ui->topTime->setValue(3); + ui->modulation->setCurrentIndex(0); + ui->fps->setCurrentIndex(0); + ui->hSync->setChecked(true); + ui->vSync->setChecked(true); + ui->halfImage->setChecked(false); + ui->invertVideo->setChecked(false); + ui->standard->setCurrentIndex(1); + + //********** RF Default values ********** + ui->decimatorEnable->setChecked(false); + ui->rfFiltering->setChecked(false); + ui->rfBW->setValue(10); + ui->rfOppBW->setValue(10); + ui->bfo->setValue(0); + ui->fmDeviation->setValue(250); + + blockApplySettings(false); + lineTimeUpdate(); + topTimeUpdate(); + applySettings(); +} + +QByteArray ATVDemodGUI::serialize() const +{ + SimpleSerializer s(1); + + s.writeS32(1, m_channelMarker.getCenterFrequency()); + s.writeU32(2, m_channelMarker.getColor().rgb()); + s.writeS32(3, ui->synchLevel->value()); + s.writeS32(4, ui->blackLevel->value()); + s.writeS32(5, ui->lineTime->value()); + s.writeS32(6, ui->topTime->value()); + s.writeS32(7, ui->modulation->currentIndex()); + s.writeS32(8, ui->fps->currentIndex()); + s.writeBool(9, ui->hSync->isChecked()); + s.writeBool(10, ui->vSync->isChecked()); + s.writeBool(11, ui->halfImage->isChecked()); + s.writeS32(12, ui->rfBW->value()); + s.writeS32(13, ui->rfOppBW->value()); + s.writeS32(14, ui->bfo->value()); + s.writeBool(15, ui->invertVideo->isChecked()); + s.writeS32(16, ui->nbLines->currentIndex()); + s.writeS32(17, ui->fmDeviation->value()); + s.writeS32(18, ui->standard->currentIndex()); + + return s.final(); +} + +bool ATVDemodGUI::deserialize(const QByteArray& arrData) +{ + SimpleDeserializer d(arrData); + + if (!d.isValid()) + { + resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + QByteArray bytetmp; + int tmp; + bool booltmp; + + blockApplySettings(true); + m_channelMarker.blockSignals(true); + + d.readS32(1, &tmp, 0); + m_channelMarker.setCenterFrequency(tmp); + +// if (d.readU32(2, &u32tmp)) { +// m_objChannelMarker.setColor(u32tmp); +// } else { +// m_objChannelMarker.setColor(Qt::white); +// } + + d.readS32(3, &tmp, 100); + ui->synchLevel->setValue(tmp); + d.readS32(4, &tmp, 310); + ui->blackLevel->setValue(tmp); + d.readS32(5, &tmp, 0); + ui->lineTime->setValue(tmp); + d.readS32(6, &tmp, 3); + ui->topTime->setValue(tmp); + d.readS32(7, &tmp, 0); + ui->modulation->setCurrentIndex(tmp); + d.readS32(8, &tmp, 0); + ui->fps->setCurrentIndex(tmp); + d.readBool(9, &booltmp, true); + ui->hSync->setChecked(booltmp); + d.readBool(10, &booltmp, true); + ui->vSync->setChecked(booltmp); + d.readBool(11, &booltmp, false); + ui->halfImage->setChecked(booltmp); + d.readS32(12, &tmp, 10); + ui->rfBW->setValue(tmp); + d.readS32(13, &tmp, 10); + ui->rfOppBW->setValue(tmp); + d.readS32(14, &tmp, 10); + ui->bfo->setValue(tmp); + d.readBool(15, &booltmp, true); + ui->invertVideo->setChecked(booltmp); + d.readS32(16, &tmp, 0); + ui->nbLines->setCurrentIndex(tmp); + d.readS32(17, &tmp, 250); + ui->fmDeviation->setValue(tmp); + d.readS32(18, &tmp, 1); + ui->standard->setCurrentIndex(tmp); + + blockApplySettings(false); + m_channelMarker.blockSignals(false); + + lineTimeUpdate(); + topTimeUpdate(); + applySettings(); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool ATVDemodGUI::handleMessage(const Message& objMessage) +{ + if (ATVDemod::MsgReportEffectiveSampleRate::match(objMessage)) + { + int sampleRate = ((ATVDemod::MsgReportEffectiveSampleRate&)objMessage).getSampleRate(); + int nbPointsPerLine = ((ATVDemod::MsgReportEffectiveSampleRate&)objMessage).getNbPointsPerLine(); + ui->channelSampleRateText->setText(tr("%1k").arg(sampleRate/1000.0f, 0, 'f', 2)); + ui->nbPointsPerLineText->setText(tr("%1p").arg(nbPointsPerLine)); + m_scopeVis->setSampleRate(sampleRate); + setRFFiltersSlidersRange(sampleRate); + lineTimeUpdate(); + topTimeUpdate(); + + return true; + } + else + { + return false; + } +} + +void ATVDemodGUI::viewChanged() +{ + qDebug("ATVDemodGUI::viewChanged"); + applySettings(); + applyRFSettings(); +} + +void ATVDemodGUI::channelSampleRateChanged() +{ + qDebug("ATVDemodGUI::channelSampleRateChanged"); + applySettings(); + applyRFSettings(); +} + +void ATVDemodGUI::handleSourceMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + if (handleMessage(*message)) + { + delete message; + } + } +} + +void ATVDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) +{ +} + +void ATVDemodGUI::onMenuDoubleClicked() +{ + if (!m_blnBasicSettingsShown) + { + m_blnBasicSettingsShown = true; + BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget( + &m_channelMarker, this); + bcsw->show(); + } +} + +ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI, + QWidget* objParent) : + RollupWidget(objParent), + ui(new Ui::ATVDemodGUI), + m_pluginAPI(objPluginAPI), + m_deviceAPI(objDeviceAPI), + m_channelMarker(this), + m_blnBasicSettingsShown(false), + m_blnDoApplySettings(true), + m_objMagSqAverage(40, 0), + m_intTickCount(0) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); + + m_scopeVis = new ScopeVisNG(ui->glScope); + m_atvDemod = new ATVDemod(m_deviceAPI); + m_atvDemod->setScopeSink(m_scopeVis); + m_atvDemod->setMessageQueueToGUI(getInputMessageQueue()); + m_atvDemod->setATVScreen(ui->screenTV); + + m_channelizer = new DownChannelizer(m_atvDemod); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); + + ui->glScope->connectTimer(MainWindow::getInstance()->getMasterTimer()); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms + + ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); + ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); + + connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); + + //m_objPluginAPI->addThreadedSink(m_objThreadedChannelizer); + m_channelMarker.setColor(Qt::white); + m_channelMarker.setMovable(false); + m_channelMarker.setBandwidth(6000000); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setVisible(true); + setTitleColor(m_channelMarker.getColor()); + + connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); + + m_deviceAPI->registerChannelInstance(m_strChannelID, this); + m_deviceAPI->addChannelMarker(&m_channelMarker); + m_deviceAPI->addRollupWidget(this); + + //ui->screenTV->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer()); + + m_objMagSqAverage.resize(4, 1.0); + + ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + + resetToDefaults(); // does applySettings() + + ui->scopeGUI->setPreTrigger(1); + ScopeVisNG::TraceData traceData; + traceData.m_amp = 2.0; // amplification factor + traceData.m_ampIndex = 1; // this is second step + traceData.m_ofs = 0.5; // direct offset + traceData.m_ofsCoarse = 50; // this is 50 coarse steps + ui->scopeGUI->changeTrace(0, traceData); + ui->scopeGUI->focusOnTrace(0); // re-focus to take changes into account in the GUI + ScopeVisNG::TriggerData triggerData; + triggerData.m_triggerLevel = 0.1; + triggerData.m_triggerLevelCoarse = 10; + triggerData.m_triggerPositiveEdge = false; + ui->scopeGUI->changeTrigger(0, triggerData); + ui->scopeGUI->focusOnTrigger(0); // re-focus to take changes into account in the GUI + + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + + QChar delta = QChar(0x94, 0x03); + ui->fmDeviationLabel->setText(delta); +} + +ATVDemodGUI::~ATVDemodGUI() +{ + m_deviceAPI->removeChannelInstance(this); + m_deviceAPI->removeThreadedSink(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; + delete m_atvDemod; + delete m_scopeVis; + delete ui; +} + +void ATVDemodGUI::blockApplySettings(bool blnBlock) +{ + m_blnDoApplySettings = !blnBlock; +} + +void ATVDemodGUI::applySettings() +{ + if (m_blnDoApplySettings) + { + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + + m_channelizer->configure(m_channelizer->getInputMessageQueue(), + m_channelizer->getInputSampleRate(), // always use maximum available bandwidth + m_channelMarker.getCenterFrequency()); + + m_atvDemod->configure(m_atvDemod->getInputMessageQueue(), + getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) + ui->lineTime->value() * m_fltLineTimeMultiplier, + getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f) + ui->topTime->value() * m_fltTopTimeMultiplier, + getFps(ui->fps->currentIndex()), + (ATVDemod::ATVStd) ui->standard->currentIndex(), + getNumberOfLines(ui->nbLines->currentIndex()), + (ui->halfImage->checkState() == Qt::Checked) ? 0.5f : 1.0f, + ui->synchLevel->value() / 1000.0f, + ui->blackLevel->value() / 1000.0f, + ui->hSync->isChecked(), + ui->vSync->isChecked(), + ui->invertVideo->isChecked(), + ui->screenTabWidget->currentIndex()); + + qDebug() << "ATVDemodGUI::applySettings:" + << " m_objChannelizer.inputSampleRate: " << m_channelizer->getInputSampleRate() + << " m_objATVDemod.sampleRate: " << m_atvDemod->getSampleRate(); + } +} + +void ATVDemodGUI::applyRFSettings() +{ + if (m_blnDoApplySettings) + { + m_atvDemod->configureRF(m_atvDemod->getInputMessageQueue(), + (ATVDemod::ATVModulation) ui->modulation->currentIndex(), + ui->rfBW->value() * m_rfSliderDivisor * 1.0f, + ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f, + ui->rfFiltering->isChecked(), + ui->decimatorEnable->isChecked(), + ui->bfo->value(), + ui->fmDeviation->value() / 500.0f); + } +} + +void ATVDemodGUI::setChannelMarkerBandwidth() +{ + m_blnDoApplySettings = false; // avoid infinite recursion + + if (ui->rfFiltering->isChecked()) // FFT filter + { + m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); + m_channelMarker.setOppositeBandwidth(ui->rfOppBW->value()*m_rfSliderDivisor); + + if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_LSB) { + m_channelMarker.setSidebands(ChannelMarker::vlsb); + } else if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_USB) { + m_channelMarker.setSidebands(ChannelMarker::vusb); + } else { + m_channelMarker.setSidebands(ChannelMarker::vusb); + } + } + else + { + if (ui->decimatorEnable->isChecked()) { + m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); + } else { + m_channelMarker.setBandwidth(m_channelizer->getInputSampleRate()); + } + + m_channelMarker.setSidebands(ChannelMarker::dsb); + } + + m_blnDoApplySettings = true; +} + +void ATVDemodGUI::setRFFiltersSlidersRange(int sampleRate) +{ + // RF filters sliders range + int scaleFactor = (int) std::log10(sampleRate/2); + m_rfSliderDivisor = std::pow(10.0, scaleFactor-1); + + if (sampleRate/m_rfSliderDivisor < 50) { + m_rfSliderDivisor /= 10; + } + + if (ui->rfFiltering->isChecked()) + { + ui->rfBW->setMaximum((sampleRate) / (2*m_rfSliderDivisor)); + ui->rfOppBW->setMaximum((sampleRate) / (2*m_rfSliderDivisor)); + } + else + { + ui->rfBW->setMaximum((sampleRate) / m_rfSliderDivisor); + ui->rfOppBW->setMaximum((sampleRate) / m_rfSliderDivisor); + } + + ui->rfBWText->setText(QString("%1k").arg((ui->rfBW->value() * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); + ui->rfOppBWText->setText(QString("%1k").arg((ui->rfOppBW->value() * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); +} + +void ATVDemodGUI::leaveEvent(QEvent*) +{ + blockApplySettings(true); + m_channelMarker.setHighlighted(false); + blockApplySettings(false); +} + +void ATVDemodGUI::enterEvent(QEvent*) +{ + blockApplySettings(true); + m_channelMarker.setHighlighted(true); + blockApplySettings(false); +} + +void ATVDemodGUI::tick() +{ + if (m_intTickCount < 4) // ~200 ms + { + m_intTickCount++; + } + else + { + if (m_atvDemod) + { + m_objMagSqAverage.feed(m_atvDemod->getMagSq()); + double magSqDB = CalcDb::dbPower(m_objMagSqAverage.average() / (1<<30)); + ui->channePowerText->setText(tr("%1 dB").arg(magSqDB, 0, 'f', 1)); + + if (m_atvDemod->getBFOLocked()) { + ui->bfoLockedLabel->setStyleSheet("QLabel { background-color : green; }"); + } else { + ui->bfoLockedLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }"); + } + } + + m_intTickCount = 0; + } + + return; +} + +void ATVDemodGUI::on_synchLevel_valueChanged(int value) +{ + applySettings(); + ui->synchLevelText->setText(QString("%1 mV").arg(value)); +} + +void ATVDemodGUI::on_blackLevel_valueChanged(int value) +{ + applySettings(); + ui->blackLevelText->setText(QString("%1 mV").arg(value)); +} + +void ATVDemodGUI::on_lineTime_valueChanged(int value) +{ + ui->lineTime->setToolTip(QString("Line length adjustment (%1)").arg(value)); + lineTimeUpdate(); + applySettings(); +} + +void ATVDemodGUI::on_topTime_valueChanged(int value) +{ + ui->topTime->setToolTip(QString("Horizontal sync pulse length adjustment (%1)").arg(value)); + topTimeUpdate(); + applySettings(); +} + +void ATVDemodGUI::on_hSync_clicked() +{ + applySettings(); +} + +void ATVDemodGUI::on_vSync_clicked() +{ + applySettings(); +} + +void ATVDemodGUI::on_invertVideo_clicked() +{ + applySettings(); +} + +void ATVDemodGUI::on_halfImage_clicked() +{ + applySettings(); +} + +void ATVDemodGUI::on_nbLines_currentIndexChanged(int index __attribute__((unused))) +{ + lineTimeUpdate(); + topTimeUpdate(); + applySettings(); +} + +void ATVDemodGUI::on_fps_currentIndexChanged(int index __attribute__((unused))) +{ + lineTimeUpdate(); + topTimeUpdate(); + applySettings(); +} + +void ATVDemodGUI::on_standard_currentIndexChanged(int index __attribute__((unused))) +{ + applySettings(); +} + +void ATVDemodGUI::on_reset_clicked(bool checked __attribute__((unused))) +{ + resetToDefaults(); +} + +void ATVDemodGUI::on_modulation_currentIndexChanged(int index __attribute__((unused))) +{ + setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate()); + setChannelMarkerBandwidth(); + applyRFSettings(); +} + +void ATVDemodGUI::on_rfBW_valueChanged(int value) +{ + ui->rfBWText->setText(QString("%1k").arg((value * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); + setChannelMarkerBandwidth(); + applyRFSettings(); +} + +void ATVDemodGUI::on_rfOppBW_valueChanged(int value) +{ + ui->rfOppBWText->setText(QString("%1k").arg((value * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); + setChannelMarkerBandwidth(); + applyRFSettings(); +} + +void ATVDemodGUI::on_rfFiltering_toggled(bool checked __attribute__((unused))) +{ + setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate()); + setChannelMarkerBandwidth(); + applyRFSettings(); +} + +void ATVDemodGUI::on_decimatorEnable_toggled(bool checked __attribute__((unused))) +{ + setChannelMarkerBandwidth(); + applyRFSettings(); +} + +void ATVDemodGUI::on_deltaFrequency_changed(qint64 value) +{ + m_channelMarker.setCenterFrequency(value); +} + +void ATVDemodGUI::on_bfo_valueChanged(int value) +{ + ui->bfoText->setText(QString("%1").arg(value * 1.0, 0, 'f', 0)); + applyRFSettings(); +} + +void ATVDemodGUI::on_fmDeviation_valueChanged(int value) +{ + ui->fmDeviationText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); + applyRFSettings(); +} + +void ATVDemodGUI::on_screenTabWidget_currentChanged(int index __attribute__((unused))) +{ + applySettings(); +} + +void ATVDemodGUI::lineTimeUpdate() +{ + float nominalLineTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()); + int lineTimeScaleFactor = (int) std::log10(nominalLineTime); + + if (m_atvDemod->getEffectiveSampleRate() == 0) { + m_fltLineTimeMultiplier = std::pow(10.0, lineTimeScaleFactor-3); + } else { + m_fltLineTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate(); + } + + float lineTime = nominalLineTime + m_fltLineTimeMultiplier * ui->lineTime->value(); + + if (lineTime < 0.0) + ui->lineTimeText->setText("invalid"); + else if(lineTime < 0.000001) + ui->lineTimeText->setText(tr("%1 ns").arg(lineTime * 1000000000.0, 0, 'f', 2)); + else if(lineTime < 0.001) + ui->lineTimeText->setText(tr("%1 µs").arg(lineTime * 1000000.0, 0, 'f', 2)); + else if(lineTime < 1.0) + ui->lineTimeText->setText(tr("%1 ms").arg(lineTime * 1000.0, 0, 'f', 2)); + else + ui->lineTimeText->setText(tr("%1 s").arg(lineTime * 1.0, 0, 'f', 2)); +} + +void ATVDemodGUI::topTimeUpdate() +{ + float nominalTopTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f); + int topTimeScaleFactor = (int) std::log10(nominalTopTime); + + if (m_atvDemod->getEffectiveSampleRate() == 0) { + m_fltTopTimeMultiplier = std::pow(10.0, topTimeScaleFactor-3); + } else { + m_fltTopTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate(); + } + + float topTime = nominalTopTime + m_fltTopTimeMultiplier * ui->topTime->value(); + + if (topTime < 0.0) + ui->topTimeText->setText("invalid"); + else if (topTime < 0.000001) + ui->topTimeText->setText(tr("%1 ns").arg(topTime * 1000000000.0, 0, 'f', 2)); + else if(topTime < 0.001) + ui->topTimeText->setText(tr("%1 µs").arg(topTime * 1000000.0, 0, 'f', 2)); + else if(topTime < 1.0) + ui->topTimeText->setText(tr("%1 ms").arg(topTime * 1000.0, 0, 'f', 2)); + else + ui->topTimeText->setText(tr("%1 s").arg(topTime * 1.0, 0, 'f', 2)); +} + +float ATVDemodGUI::getFps(int fpsIndex) +{ + switch(fpsIndex) + { + case 0: + return 30.0f; + break; + case 2: + return 20.0f; + break; + case 3: + return 16.0f; + break; + case 4: + return 12.0f; + break; + case 5: + return 10.0f; + break; + case 6: + return 8.0f; + break; + case 7: + return 5.0f; + break; + case 8: + return 2.0f; + break; + case 9: + return 1.0f; + break; + case 1: + default: + return 25.0f; + break; + } +} + +float ATVDemodGUI::getNominalLineTime(int nbLinesIndex, int fpsIndex) +{ + float fps = getFps(fpsIndex); + int nbLines = getNumberOfLines(nbLinesIndex); + + return 1.0f / (nbLines * fps); +} + +int ATVDemodGUI::getNumberOfLines(int nbLinesIndex) +{ + switch(nbLinesIndex) + { + case 0: + return 640; + break; + case 2: + return 525; + break; + case 3: + return 480; + break; + case 4: + return 405; + break; + case 5: + return 360; + break; + case 6: + return 343; + break; + case 7: + return 240; + break; + case 8: + return 180; + break; + case 9: + return 120; + break; + case 10: + return 90; + break; + case 11: + return 60; + break; + case 12: + return 32; + break; + case 1: + default: + return 625; + break; + } +} diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index 565b26a07..36c5f6f55 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -347,7 +347,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg ui->glSpectrum->setDisplayMaxHold(false); ui->glSpectrum->setSsbSpectrum(true); m_spectrumVis->configure(m_spectrumVis->getInputMessageQueue(), 64, 10, FFTWindow::BlackmanHarris); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); m_channelMarker.setTitle("Broadcast FM Demod"); m_channelMarker.setBandwidth(12500); diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index ab04a570b..d8acd1828 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -260,9 +260,9 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg ui->glScope->setSampleRate(48000); m_scopeVis->setSampleRate(48000); - ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); + ui->glScope->connectTimer(MainWindow::getInstance()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); ui->audioMute->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); @@ -304,8 +304,8 @@ DSDDemodGUI::~DSDDemodGUI() void DSDDemodGUI::updateMyPosition() { - float latitude = m_pluginAPI->getMainWindow()->getMainSettings().getLatitude(); - float longitude = m_pluginAPI->getMainWindow()->getMainSettings().getLongitude(); + float latitude = MainWindow::getInstance()->getMainSettings().getLatitude(); + float longitude = MainWindow::getInstance()->getMainSettings().getLongitude(); if ((m_myLatitude != latitude) || (m_myLongitude != longitude)) { diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.cpp b/plugins/channelrx/demodnfm/nfmdemodgui.cpp index 9c0c6f132..e07fb0ea1 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodgui.cpp @@ -241,7 +241,7 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg m_nfmDemod = new NFMDemod(m_deviceAPI); m_nfmDemod->setMessageQueueToGUI(getInputMessageQueue()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); blockApplySettings(true); diff --git a/plugins/channelrx/demodssb/ssbdemodgui.cpp b/plugins/channelrx/demodssb/ssbdemodgui.cpp index 39b14aa61..b053591a6 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.cpp +++ b/plugins/channelrx/demodssb/ssbdemodgui.cpp @@ -319,9 +319,9 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg ui->glSpectrum->setDisplayWaterfall(true); ui->glSpectrum->setDisplayMaxHold(true); - ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); + ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); m_channelMarker.setVisible(true); diff --git a/plugins/channelrx/demodwfm/wfmdemodgui.cpp b/plugins/channelrx/demodwfm/wfmdemodgui.cpp index 6ef42f7c6..e6a8e8865 100644 --- a/plugins/channelrx/demodwfm/wfmdemodgui.cpp +++ b/plugins/channelrx/demodwfm/wfmdemodgui.cpp @@ -173,7 +173,7 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg m_wfmDemod = new WFMDemod(m_deviceAPI); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); //m_channelMarker = new ChannelMarker(this); m_channelMarker.setBandwidth(WFMDemodSettings::getRFBW(4)); diff --git a/plugins/channelrx/tcpsrc/tcpsrcgui.cpp b/plugins/channelrx/tcpsrc/tcpsrcgui.cpp index eafd4b311..8d721bf5a 100644 --- a/plugins/channelrx/tcpsrc/tcpsrcgui.cpp +++ b/plugins/channelrx/tcpsrc/tcpsrcgui.cpp @@ -153,8 +153,8 @@ TCPSrcGUI::TCPSrcGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* ui->glSpectrum->setDisplayMaxHold(true); m_spectrumVis->configure(m_spectrumVis->getInputMessageQueue(), 64, 10, FFTWindow::BlackmanHarris); - ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer()); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); m_channelMarker.setBandwidth(16000); m_channelMarker.setCenterFrequency(0); diff --git a/plugins/channelrx/udpsrc/udpsrcgui.cpp b/plugins/channelrx/udpsrc/udpsrcgui.cpp index 0dc325634..9c1e391fe 100644 --- a/plugins/channelrx/udpsrc/udpsrcgui.cpp +++ b/plugins/channelrx/udpsrc/udpsrcgui.cpp @@ -166,8 +166,8 @@ UDPSrcGUI::UDPSrcGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* ui->glSpectrum->setDisplayMaxHold(true); m_spectrumVis->configure(m_spectrumVis->getInputMessageQueue(), 64, 10, FFTWindow::BlackmanHarris); - ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer()); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); m_channelMarker.setBandwidth(16000); m_channelMarker.setCenterFrequency(0); diff --git a/plugins/channeltx/modam/ammodgui.cpp b/plugins/channeltx/modam/ammodgui.cpp index 75501683d..2eab227a0 100644 --- a/plugins/channeltx/modam/ammodgui.cpp +++ b/plugins/channeltx/modam/ammodgui.cpp @@ -291,7 +291,7 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pare m_amMod = new AMMod(m_deviceAPI); m_amMod->setMessageQueueToGUI(getInputMessageQueue()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); diff --git a/plugins/channeltx/modatv/atvmodgui.cpp b/plugins/channeltx/modatv/atvmodgui.cpp index f21ec22ea..33cf98319 100644 --- a/plugins/channeltx/modatv/atvmodgui.cpp +++ b/plugins/channeltx/modatv/atvmodgui.cpp @@ -611,7 +611,7 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa m_atvMod = new ATVMod(m_deviceAPI); m_atvMod->setMessageQueueToGUI(getInputMessageQueue()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); diff --git a/plugins/channeltx/modnfm/nfmmodgui.cpp b/plugins/channeltx/modnfm/nfmmodgui.cpp index ae4a51374..a6ec2a9f7 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.cpp +++ b/plugins/channeltx/modnfm/nfmmodgui.cpp @@ -319,7 +319,7 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa m_nfmMod = new NFMMod(m_deviceAPI); m_nfmMod->setMessageQueueToGUI(getInputMessageQueue()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); diff --git a/plugins/channeltx/modssb/ssbmodgui.cpp b/plugins/channeltx/modssb/ssbmodgui.cpp index 61e86844a..aeba20489 100644 --- a/plugins/channeltx/modssb/ssbmodgui.cpp +++ b/plugins/channeltx/modssb/ssbmodgui.cpp @@ -472,9 +472,9 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa ui->glSpectrum->setDisplayWaterfall(true); ui->glSpectrum->setDisplayMaxHold(true); ui->glSpectrum->setSsbSpectrum(true); - ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); + ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); diff --git a/plugins/channeltx/modwfm/wfmmodgui.cpp b/plugins/channeltx/modwfm/wfmmodgui.cpp index eb2715f0e..8f95b5694 100644 --- a/plugins/channeltx/modwfm/wfmmodgui.cpp +++ b/plugins/channeltx/modwfm/wfmmodgui.cpp @@ -308,7 +308,7 @@ WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa m_wfmMod = new WFMMod(m_deviceAPI); m_wfmMod->setMessageQueueToGUI(getInputMessageQueue()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); diff --git a/plugins/channeltx/udpsink/udpsinkgui.cpp b/plugins/channeltx/udpsink/udpsinkgui.cpp index 46d5a904b..36d86750a 100644 --- a/plugins/channeltx/udpsink/udpsinkgui.cpp +++ b/plugins/channeltx/udpsink/udpsinkgui.cpp @@ -134,8 +134,8 @@ UDPSinkGUI::UDPSinkGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* ui->glSpectrum->setDisplayMaxHold(true); m_spectrumVis->configure(m_spectrumVis->getInputMessageQueue(), 64, 10, FFTWindow::BlackmanHarris); - ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer()); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); //m_channelMarker = new ChannelMarker(this); m_channelMarker.setBandwidth(16000); diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 6c5ecd10d..86993c8df 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -54,6 +54,8 @@ #include #include +MainWindow *MainWindow::m_instance = 0; + MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), @@ -68,6 +70,7 @@ MainWindow::MainWindow(QWidget* parent) : { qDebug() << "MainWindow::MainWindow: start"; + m_instance = this; m_settings.setAudioDeviceInfo(&m_audioDeviceInfo); ui->setupUi(this); diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index 3137730b2..10ac04296 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -76,6 +76,7 @@ public: explicit MainWindow(QWidget* parent = 0); ~MainWindow(); + static MainWindow *getInstance() { return m_instance; } // Main Window is de facto a singleton so this just returns its reference MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; } @@ -100,6 +101,7 @@ private: QString tabName; }; + static MainWindow *m_instance; Ui::MainWindow* ui; AudioDeviceInfo m_audioDeviceInfo; MessageQueue m_inputMessageQueue;