DaemonSink (2)

This commit is contained in:
f4exb 2018-09-05 08:44:14 +02:00
parent 96e7d49fbe
commit dcd8f94931
11 changed files with 563 additions and 6 deletions

View File

@ -4,18 +4,18 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(daemonsink_SOURCES
daemonsink.cpp
# daemonsinkgui.cpp
daemonsinkgui.cpp
daemonsinksettings.cpp
daemonsinkthread.cpp
# daemonsinkplugin.cpp
daemonsinkplugin.cpp
)
set(daemonsink_HEADERS
daemonsink.h
# daemonsinkgui.h
daemonsinkgui.h
daemonsinksettings.h
daemonsinkthread.h
# daemonsinkplugin.h
daemonsinkplugin.h
)
set(daemonsink_FORMS

View File

@ -36,6 +36,7 @@
#include "daemonsink.h"
MESSAGE_CLASS_DEFINITION(DaemonSink::MsgConfigureDaemonSink, Message)
MESSAGE_CLASS_DEFINITION(DaemonSink::MsgSampleRateNotification, Message)
const QString DaemonSink::m_channelIdURI = "sdrangel.channel.daemonsink";
const QString DaemonSink::m_channelId = "DaemonSink";
@ -237,6 +238,12 @@ bool DaemonSink::handleMessage(const Message& cmd __attribute__((unused)))
setSampleRate(notif.getSampleRate());
}
if (m_guiMessageQueue)
{
MsgSampleRateNotification *msg = MsgSampleRateNotification::create(notif.getSampleRate());
m_guiMessageQueue->push(msg);
}
return true;
}
else if (DSPSignalNotification::match(cmd))

View File

@ -23,6 +23,7 @@
#ifndef INCLUDE_DAEMONSINK_H_
#define INCLUDE_DAEMONSINK_H_
#include <QObject>
#include <QMutex>
#include "cm256.h"
@ -64,6 +65,26 @@ public:
{ }
};
class MsgSampleRateNotification : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgSampleRateNotification* create(int sampleRate) {
return new MsgSampleRateNotification(sampleRate);
}
int getSampleRate() const { return m_sampleRate; }
private:
MsgSampleRateNotification(int sampleRate) :
Message(),
m_sampleRate(sampleRate)
{ }
int m_sampleRate;
};
DaemonSink(DeviceSourceAPI *deviceAPI);
virtual ~DaemonSink();
virtual void destroy() { delete this; }

View File

@ -0,0 +1,291 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "device/devicesinkapi.h"
#include "device/deviceuiset.h"
#include "gui/basicchannelsettingsdialog.h"
#include "mainwindow.h"
#include "daemonsink.h"
#include "ui_daemonsinkgui.h"
#include "daemonsinkgui.h"
DaemonSinkGUI* DaemonSinkGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *channelRx)
{
DaemonSinkGUI* gui = new DaemonSinkGUI(pluginAPI, deviceUISet, channelRx);
return gui;
}
void DaemonSinkGUI::destroy()
{
delete this;
}
void DaemonSinkGUI::setName(const QString& name)
{
setObjectName(name);
}
QString DaemonSinkGUI::getName() const
{
return objectName();
}
qint64 DaemonSinkGUI::getCenterFrequency() const {
return 0;
}
void DaemonSinkGUI::setCenterFrequency(qint64 centerFrequency __attribute__((unused)))
{
}
void DaemonSinkGUI::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
applySettings(true);
}
QByteArray DaemonSinkGUI::serialize() const
{
return m_settings.serialize();
}
bool DaemonSinkGUI::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
displaySettings();
applySettings(true);
return true;
} else {
resetToDefaults();
return false;
}
}
bool DaemonSinkGUI::handleMessage(const Message& message)
{
if (DaemonSink::MsgSampleRateNotification::match(message))
{
DaemonSink::MsgSampleRateNotification& notif = (DaemonSink::MsgSampleRateNotification&) message;
m_channelMarker.setBandwidth(notif.getSampleRate());
m_sampleRate = notif.getSampleRate();
return true;
}
else if (DaemonSink::MsgConfigureDaemonSink::match(message))
{
const DaemonSink::MsgConfigureDaemonSink& cfg = (DaemonSink::MsgConfigureDaemonSink&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else
{
return false;
}
}
DaemonSinkGUI::DaemonSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *channelrx, QWidget* parent) :
RollupWidget(parent),
ui(new Ui::DaemonSinkGUI),
m_pluginAPI(pluginAPI),
m_deviceUISet(deviceUISet),
m_sampleRate(0),
m_tickCount(0)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
m_daemonSink = (DaemonSink*) channelrx;
m_daemonSink->setMessageQueueToGUI(getInputMessageQueue());
m_channelMarker.blockSignals(true);
m_channelMarker.setColor(m_settings.m_rgbColor);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setTitle("Daemon source");
m_channelMarker.blockSignals(false);
m_channelMarker.setVisible(true); // activate signal on the last setting only
m_settings.setChannelMarker(&m_channelMarker);
m_deviceUISet->registerRxChannelInstance(DaemonSink::m_channelIdURI, this);
m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this);
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
connect(&(m_deviceUISet->m_deviceSinkAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick()));
m_time.start();
displaySettings();
applySettings(true);
}
DaemonSinkGUI::~DaemonSinkGUI()
{
m_deviceUISet->removeRxChannelInstance(this);
delete ui;
}
void DaemonSinkGUI::blockApplySettings(bool block)
{
m_doApplySettings = !block;
}
void DaemonSinkGUI::applySettings(bool force)
{
if (m_doApplySettings)
{
setTitleColor(m_channelMarker.getColor());
DaemonSink::MsgConfigureDaemonSink* message = DaemonSink::MsgConfigureDaemonSink::create(m_settings, force);
m_daemonSink->getInputMessageQueue()->push(message);
}
}
void DaemonSinkGUI::displaySettings()
{
m_channelMarker.blockSignals(true);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setTitle(m_settings.m_title);
m_channelMarker.setBandwidth(5000); // TODO
m_channelMarker.blockSignals(false);
m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
setTitleColor(m_settings.m_rgbColor);
setWindowTitle(m_channelMarker.getTitle());
blockApplySettings(true);
ui->dataAddress->setText(m_settings.m_dataAddress);
ui->dataPort->setText(tr("%1").arg(m_settings.m_dataPort));
blockApplySettings(false);
}
void DaemonSinkGUI::leaveEvent(QEvent*)
{
m_channelMarker.setHighlighted(false);
}
void DaemonSinkGUI::enterEvent(QEvent*)
{
m_channelMarker.setHighlighted(true);
}
void DaemonSinkGUI::handleSourceMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()) != 0)
{
if (handleMessage(*message))
{
delete message;
}
}
}
void DaemonSinkGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused)))
{
}
void DaemonSinkGUI::onMenuDialogCalled(const QPoint &p)
{
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
dialog.move(p);
dialog.exec();
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
m_settings.m_title = m_channelMarker.getTitle();
setWindowTitle(m_settings.m_title);
setTitleColor(m_settings.m_rgbColor);
applySettings();
}
void DaemonSinkGUI::on_dataAddress_returnPressed()
{
m_settings.m_dataAddress = ui->dataAddress->text();
applySettings();
}
void DaemonSinkGUI::on_dataPort_returnPressed()
{
bool dataOk;
int dataPort = ui->dataPort->text().toInt(&dataOk);
if((!dataOk) || (dataPort < 1024) || (dataPort > 65535))
{
return;
}
else
{
m_settings.m_dataPort = dataPort;
}
applySettings();
}
void DaemonSinkGUI::on_dataApplyButton_clicked(bool checked __attribute__((unused)))
{
m_settings.m_dataAddress = ui->dataAddress->text();
bool dataOk;
int udpDataPort = ui->dataPort->text().toInt(&dataOk);
if((dataOk) && (udpDataPort >= 1024) && (udpDataPort < 65535))
{
m_settings.m_dataPort = udpDataPort;
}
applySettings();
}
void DaemonSinkGUI::on_txDelay_valueChanged(int value)
{
m_settings.m_txDelay = value / 100.0;
ui->txDelayText->setText(tr("%1").arg(value));
updateTxDelayTooltip();
applySettings();
}
void DaemonSinkGUI::on_nbFECBlocks_valueChanged(int value)
{
m_settings.m_nbFECBlocks = value;
int nbOriginalBlocks = 128;
int nbFECBlocks = value;
QString s = QString::number(nbOriginalBlocks + nbFECBlocks, 'f', 0);
QString s1 = QString::number(nbFECBlocks, 'f', 0);
ui->nominalNbBlocksText->setText(tr("%1/%2").arg(s).arg(s1));
updateTxDelayTooltip();
applySettings();
}
void DaemonSinkGUI::updateTxDelayTooltip()
{
double delay = m_sampleRate == 0 ? 0.0 : ((127*127*m_settings.m_txDelay) / m_sampleRate)/(128 + m_settings.m_nbFECBlocks);
ui->txDelayText->setToolTip(tr("%1 us").arg(QString::number(delay*1e6, 'f', 0)));
}
void DaemonSinkGUI::tick()
{
if (++m_tickCount == 20) { // once per second
m_tickCount = 0;
}
}

View File

@ -0,0 +1,97 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKGUI_H_
#define PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKGUI_H_
#include <QObject>
#include <QTime>
#include "plugin/plugininstancegui.h"
#include "dsp/channelmarker.h"
#include "gui/rollupwidget.h"
#include "util/messagequeue.h"
#include "daemonsinksettings.h"
class PluginAPI;
class DeviceUISet;
class DaemonSink;
class BasebandSampleSink;
namespace Ui {
class DaemonSinkGUI;
}
class DaemonSinkGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT
public:
static DaemonSinkGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel);
virtual void destroy();
void setName(const QString& name);
QString getName() const;
virtual qint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message);
private:
Ui::DaemonSinkGUI* ui;
PluginAPI* m_pluginAPI;
DeviceUISet* m_deviceUISet;
ChannelMarker m_channelMarker;
DaemonSinkSettings m_settings;
int m_sampleRate;
quint64 m_deviceCenterFrequency; //!< Center frequency in device
bool m_doApplySettings;
DaemonSink* m_daemonSink;
MessageQueue m_inputMessageQueue;
QTime m_time;
uint32_t m_tickCount;
explicit DaemonSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
virtual ~DaemonSinkGUI();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void updateTxDelayTooltip();
void leaveEvent(QEvent*);
void enterEvent(QEvent*);
private slots:
void handleSourceMessages();
void on_dataAddress_returnPressed();
void on_dataPort_returnPressed();
void on_dataApplyButton_clicked(bool checked);
void on_nbFECBlocks_valueChanged(int value);
void on_txDelay_valueChanged(int value);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void tick();
};
#endif /* PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKGUI_H_ */

View File

@ -139,7 +139,7 @@
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<widget class="QPushButton" name="dataApplyButton">
<property name="maximumSize">
<size>
<width>30</width>

View File

@ -0,0 +1,81 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "daemonsinkplugin.h"
#include <QtPlugin>
#include "plugin/pluginapi.h"
#ifndef SERVER_MODE
#include "daemonsinkgui.h"
#endif
#include "daemonsink.h"
const PluginDescriptor DaemonSinkPlugin::m_pluginDescriptor = {
QString("Daemon Channel Sink"),
QString("4.1.0"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
DaemonSinkPlugin::DaemonSinkPlugin(QObject* parent) :
QObject(parent),
m_pluginAPI(0)
{
}
const PluginDescriptor& DaemonSinkPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void DaemonSinkPlugin::initPlugin(PluginAPI* pluginAPI)
{
m_pluginAPI = pluginAPI;
// register TCP Channel Source
m_pluginAPI->registerRxChannel(DaemonSink::m_channelIdURI, DaemonSink::m_channelId, this);
}
#ifdef SERVER_MODE
PluginInstanceGUI* DaemonSinkPlugin::createRxChannelGUI(
DeviceUISet *deviceUISet __attribute__((unused)),
BasebandSampleSink *rxChannel __attribute__((unused)))
{
return 0;
}
#else
PluginInstanceGUI* DaemonSinkPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel)
{
return DaemonSinkGUI::create(m_pluginAPI, deviceUISet, rxChannel);
}
#endif
BasebandSampleSink* DaemonSinkPlugin::createRxChannelBS(DeviceSourceAPI *deviceAPI)
{
return new DaemonSink(deviceAPI);
}
ChannelSinkAPI* DaemonSinkPlugin::createRxChannelCS(DeviceSourceAPI *deviceAPI)
{
return new DaemonSink(deviceAPI);
}

View File

@ -0,0 +1,48 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKPLUGIN_H_
#define PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKPLUGIN_H_
#include <QObject>
#include "plugin/plugininterface.h"
class DeviceUISet;
class BasebandSampleSink;
class DaemonSinkPlugin : public QObject, PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "sdrangel.demod.daemonsink")
public:
explicit DaemonSinkPlugin(QObject* parent = 0);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual PluginInstanceGUI* createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel);
virtual BasebandSampleSink* createRxChannelBS(DeviceSourceAPI *deviceAPI);
virtual ChannelSinkAPI* createRxChannelCS(DeviceSourceAPI *deviceAPI);
private:
static const PluginDescriptor m_pluginDescriptor;
PluginAPI* m_pluginAPI;
};
#endif /* PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKPLUGIN_H_ */

View File

@ -20,6 +20,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "daemonsinksettings.h"
@ -44,6 +46,8 @@ QByteArray DaemonSinkSettings::serialize() const
s.writeU32(2, m_txDelay);
s.writeString(3, m_dataAddress);
s.writeU32(4, m_dataPort);
s.writeU32(5, m_rgbColor);
s.writeString(6, m_title);
return s.final();
}
@ -81,6 +85,9 @@ bool DaemonSinkSettings::deserialize(const QByteArray& data)
m_dataPort = 9090;
}
d.readU32(5, &m_rgbColor, QColor(0, 255, 255).rgb());
d.readString(6, &m_title, "Daemon sink");
return true;
}
else

View File

@ -33,9 +33,14 @@ struct DaemonSinkSettings
uint32_t m_txDelay;
QString m_dataAddress;
uint16_t m_dataPort;
quint32 m_rgbColor;
QString m_title;
Serializable *m_channelMarker;
DaemonSinkSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};

View File

@ -71,7 +71,7 @@ bool DaemonSrcSettings::deserialize(const QByteArray& data)
}
d.readU32(3, &m_rgbColor, QColor(0, 255, 255).rgb());
d.readString(4, &m_title, "AM Modulator");
d.readString(4, &m_title, "Daemon source");
return true;
}