From 2b1ddc72084e946701102d87ec73f86c571640cd Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 26 Aug 2020 18:52:36 +0200 Subject: [PATCH] Remote Input: added option to join a multicast group. Implements #611 --- .../samplesource/remoteinput/remoteinput.cpp | 10 ++- .../remoteinput/remoteinputgui.cpp | 51 ++++++++----- .../samplesource/remoteinput/remoteinputgui.h | 2 + .../remoteinput/remoteinputgui.ui | 62 ++++++++++++++- .../remoteinput/remoteinputsettings.cpp | 6 ++ .../remoteinput/remoteinputsettings.h | 2 + .../remoteinput/remoteinputudphandler.cpp | 76 ++++++++++++++++--- .../remoteinput/remoteinputudphandler.h | 39 +++++++++- 8 files changed, 216 insertions(+), 32 deletions(-) diff --git a/plugins/samplesource/remoteinput/remoteinput.cpp b/plugins/samplesource/remoteinput/remoteinput.cpp index e5a306617..f19a6c31e 100644 --- a/plugins/samplesource/remoteinput/remoteinput.cpp +++ b/plugins/samplesource/remoteinput/remoteinput.cpp @@ -242,8 +242,14 @@ void RemoteInput::applySettings(const RemoteInputSettings& settings, bool force) settings.m_iqCorrection ? "true" : "false"); } - m_remoteInputUDPHandler->configureUDPLink(settings.m_dataAddress, settings.m_dataPort); - m_remoteInputUDPHandler->getRemoteAddress(remoteAddress); + if ((m_settings.m_dataAddress != settings.m_dataAddress) || + (m_settings.m_dataPort != settings.m_dataPort) || + (m_settings.m_multicastAddress != settings.m_multicastAddress) || + (m_settings.m_multicastJoin != settings.m_multicastJoin) || force) + { + m_remoteInputUDPHandler->configureUDPLink(settings.m_dataAddress, settings.m_dataPort, settings.m_multicastAddress, settings.m_multicastJoin); + m_remoteInputUDPHandler->getRemoteAddress(remoteAddress); + } mutexLocker.unlock(); diff --git a/plugins/samplesource/remoteinput/remoteinputgui.cpp b/plugins/samplesource/remoteinput/remoteinputgui.cpp index 5f44d7011..78ffd14f9 100644 --- a/plugins/samplesource/remoteinput/remoteinputgui.cpp +++ b/plugins/samplesource/remoteinput/remoteinputgui.cpp @@ -304,6 +304,11 @@ void RemoteInputGui::displaySettings() ui->apiPort->setText(tr("%1").arg(m_settings.m_apiPort)); ui->dataPort->setText(tr("%1").arg(m_settings.m_dataPort)); ui->dataAddress->setText(m_settings.m_dataAddress); + ui->multicastAddress->setText(m_settings.m_multicastAddress); + ui->multicastJoin->setChecked(m_settings.m_multicastJoin); + + ui->dataApplyButton->setEnabled(false); + ui->dataApplyButton->setStyleSheet("QPushButton { background:rgb(79,79,79); }"); ui->dcOffset->setChecked(m_settings.m_dcBlock); ui->iqImbalance->setChecked(m_settings.m_iqCorrection); @@ -339,14 +344,9 @@ void RemoteInputGui::on_apiApplyButton_clicked(bool checked) void RemoteInputGui::on_dataApplyButton_clicked(bool checked) { (void) checked; - 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; - } + ui->dataApplyButton->setEnabled(false); + ui->dataApplyButton->setStyleSheet("QPushButton { background:rgb(79,79,79); }"); sendSettings(); } @@ -365,23 +365,38 @@ void RemoteInputGui::on_apiAddress_returnPressed() void RemoteInputGui::on_dataAddress_returnPressed() { m_settings.m_dataAddress = ui->dataAddress->text(); - sendSettings(); + ui->dataApplyButton->setEnabled(true); + ui->dataApplyButton->setStyleSheet("QPushButton { background-color : green; }"); } void RemoteInputGui::on_dataPort_returnPressed() { - bool dataOk; - int udpDataPort = ui->dataPort->text().toInt(&dataOk); + bool ok; + quint16 udpPort = ui->dataPort->text().toInt(&ok); - if((!dataOk) || (udpDataPort < 1024) || (udpDataPort > 65535)) - { - return; - } - else - { - m_settings.m_dataPort = udpDataPort; - sendSettings(); + if ((!ok) || (udpPort < 1024)) { + udpPort = 9998; } + + m_settings.m_dataPort = udpPort; + ui->dataPort->setText(tr("%1").arg(m_settings.m_dataPort)); + + ui->dataApplyButton->setEnabled(true); + ui->dataApplyButton->setStyleSheet("QPushButton { background-color : green; }"); +} + +void RemoteInputGui::on_multicastAddress_returnPressed() +{ + m_settings.m_multicastAddress = ui->multicastAddress->text(); + ui->dataApplyButton->setEnabled(true); + ui->dataApplyButton->setStyleSheet("QPushButton { background-color : green; }"); +} + +void RemoteInputGui::on_multicastJoin_toggled(bool checked) +{ + m_settings.m_multicastJoin = checked; + ui->dataApplyButton->setEnabled(true); + ui->dataApplyButton->setStyleSheet("QPushButton { background-color : green; }"); } void RemoteInputGui::on_apiPort_returnPressed() diff --git a/plugins/samplesource/remoteinput/remoteinputgui.h b/plugins/samplesource/remoteinput/remoteinputgui.h index 129bbf687..a3072de02 100644 --- a/plugins/samplesource/remoteinput/remoteinputgui.h +++ b/plugins/samplesource/remoteinput/remoteinputgui.h @@ -129,6 +129,8 @@ private slots: void on_apiPort_returnPressed(); void on_dataAddress_returnPressed(); void on_dataPort_returnPressed(); + void on_multicastAddress_returnPressed(); + void on_multicastJoin_toggled(bool checked); void on_startStop_toggled(bool checked); void on_eventCountsReset_clicked(bool checked); void updateHardware(); diff --git a/plugins/samplesource/remoteinput/remoteinputgui.ui b/plugins/samplesource/remoteinput/remoteinputgui.ui index 0cfc7220c..305de464e 100644 --- a/plugins/samplesource/remoteinput/remoteinputgui.ui +++ b/plugins/samplesource/remoteinput/remoteinputgui.ui @@ -686,6 +686,9 @@ 16777215 + + Set API link + Set @@ -723,7 +726,7 @@ - Local data connection IPv4 address + Local network interface IPv4 address 000.000.000.000 @@ -758,7 +761,7 @@ - Local data connection port + Local data port 00000 @@ -792,6 +795,9 @@ 16777215 + + Set data link + Set @@ -799,6 +805,58 @@ + + + + + + Join or leave multicast group + + + Mcast + + + + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Multicast group address + + + 000.000.000.000 + + + 0.0.0.0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/plugins/samplesource/remoteinput/remoteinputsettings.cpp b/plugins/samplesource/remoteinput/remoteinputsettings.cpp index 5336389df..1e3a72065 100644 --- a/plugins/samplesource/remoteinput/remoteinputsettings.cpp +++ b/plugins/samplesource/remoteinput/remoteinputsettings.cpp @@ -29,6 +29,8 @@ void RemoteInputSettings::resetToDefaults() m_apiPort = 9091; m_dataAddress = "127.0.0.1"; m_dataPort = 9090; + m_multicastAddress = "224.0.0.1"; + m_multicastJoin = false; m_dcBlock = false; m_iqCorrection = false; m_useReverseAPI = false; @@ -41,6 +43,8 @@ QByteArray RemoteInputSettings::serialize() const { SimpleSerializer s(1); + s.writeString(3, m_multicastAddress); + s.writeBool(4, m_multicastJoin); s.writeString(5, m_apiAddress); s.writeU32(6, m_apiPort); s.writeU32(7, m_dataPort); @@ -69,6 +73,8 @@ bool RemoteInputSettings::deserialize(const QByteArray& data) { quint32 uintval; + d.readString(3, &m_multicastAddress, "224.0.0.1"); + d.readBool(4, &m_multicastJoin, false); d.readString(5, &m_apiAddress, "127.0.0.1"); d.readU32(6, &uintval, 9090); m_apiPort = uintval % (1<<16); diff --git a/plugins/samplesource/remoteinput/remoteinputsettings.h b/plugins/samplesource/remoteinput/remoteinputsettings.h index bc11d5b8e..60cec764d 100644 --- a/plugins/samplesource/remoteinput/remoteinputsettings.h +++ b/plugins/samplesource/remoteinput/remoteinputsettings.h @@ -26,6 +26,8 @@ struct RemoteInputSettings { quint16 m_apiPort; QString m_dataAddress; quint16 m_dataPort; + QString m_multicastAddress; + bool m_multicastJoin; bool m_dcBlock; bool m_iqCorrection; bool m_useReverseAPI; diff --git a/plugins/samplesource/remoteinput/remoteinputudphandler.cpp b/plugins/samplesource/remoteinput/remoteinputudphandler.cpp index d5aba1186..38abf1c8c 100644 --- a/plugins/samplesource/remoteinput/remoteinputudphandler.cpp +++ b/plugins/samplesource/remoteinput/remoteinputudphandler.cpp @@ -27,6 +27,7 @@ #include "remoteinput.h" MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgReportSampleRateChange, Message) +MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgUDPAddressAndPort, Message) RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceAPI *deviceAPI) : m_deviceAPI(deviceAPI), @@ -38,6 +39,8 @@ RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceA m_dataAddress(QHostAddress::LocalHost), m_remoteAddress(QHostAddress::LocalHost), m_dataPort(9090), + m_multicastAddress(QStringLiteral("224.0.0.1")), + m_multicast(false), m_dataConnected(false), m_udpBuf(0), m_udpReadBytes(0), @@ -68,6 +71,8 @@ RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceA m_throttlems = m_masterTimer.interval(); #endif m_rateDivider = 1000 / m_throttlems; + + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleMessages())); } RemoteInputUDPHandler::~RemoteInputUDPHandler() @@ -90,24 +95,31 @@ void RemoteInputUDPHandler::start() return; } - if (!m_dataSocket) - { + if (!m_dataSocket) { m_dataSocket = new QUdpSocket(this); } if (!m_dataConnected) { - connect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); //, Qt::QueuedConnection); - - if (m_dataSocket->bind(m_dataAddress, m_dataPort)) + if (m_dataSocket->bind(m_multicast ? QHostAddress::AnyIPv4 : m_dataAddress, m_dataPort, QUdpSocket::ShareAddress)) { qDebug("RemoteInputUDPHandler::start: bind data socket to %s:%d", m_dataAddress.toString().toStdString().c_str(), m_dataPort); + + if (m_multicast) + { + if (m_dataSocket->joinMulticastGroup(m_multicastAddress)) { + qDebug("RemoteInputUDPHandler::start: joined multicast group %s", qPrintable(m_multicastAddress.toString())); + } else { + qDebug("RemoteInputUDPHandler::start: failed joining multicast group %s", qPrintable(m_multicastAddress.toString())); + } + } + + connect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); //, Qt::QueuedConnection); m_dataConnected = true; } else { qWarning("RemoteInputUDPHandler::start: cannot bind data port %d", m_dataPort); - disconnect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); m_dataConnected = false; } } @@ -143,17 +155,37 @@ void RemoteInputUDPHandler::stop() m_running = false; } -void RemoteInputUDPHandler::configureUDPLink(const QString& address, quint16 port) +void RemoteInputUDPHandler::configureUDPLink(const QString& address, quint16 port, const QString& multicastAddress, bool multicastJoin) { - qDebug("RemoteInputUDPHandler::configureUDPLink: %s:%d", address.toStdString().c_str(), port); + Message* msg = MsgUDPAddressAndPort::create(address, port, multicastAddress, multicastJoin); + m_inputMessageQueue.push(msg); +} + +void RemoteInputUDPHandler::applyUDPLink(const QString& address, quint16 port, const QString& multicastAddress, bool multicastJoin) +{ + qDebug() << "RemoteInputUDPHandler::applyUDPLink: " + << " address: " << address + << " port: " << port + << " multicastAddress: " << multicastAddress + << " multicastJoin: " << multicastJoin; + bool addressOK = m_dataAddress.setAddress(address); if (!addressOK) { - qWarning("RemoteInputUDPHandler::configureUDPLink: invalid address %s. Set to localhost.", address.toStdString().c_str()); + qWarning("RemoteInputUDPHandler::applyUDPLink: invalid address %s. Set to localhost.", address.toStdString().c_str()); m_dataAddress = QHostAddress::LocalHost; } + m_multicast = multicastJoin; + addressOK = m_multicastAddress.setAddress(multicastAddress); + + if (!addressOK) + { + qWarning("RemoteInputUDPHandler::applyUDPLink: invalid multicast address %s. disabling multicast.", address.toStdString().c_str()); + m_multicast = false; + } + m_dataPort = port; stop(); start(); @@ -389,3 +421,29 @@ void RemoteInputUDPHandler::tick() } } } + +void RemoteInputUDPHandler::handleMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != 0) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +bool RemoteInputUDPHandler::handleMessage(const Message& cmd) +{ + if (RemoteInputUDPHandler::MsgUDPAddressAndPort::match(cmd)) + { + RemoteInputUDPHandler::MsgUDPAddressAndPort& notif = (RemoteInputUDPHandler::MsgUDPAddressAndPort&) cmd; + applyUDPLink(notif.getAddress(), notif.getPort(), notif.getMulticastAddress(), notif.getMulticastJoin()); + return true; + } + else + { + return false; + } +} diff --git a/plugins/samplesource/remoteinput/remoteinputudphandler.h b/plugins/samplesource/remoteinput/remoteinputudphandler.h index 53425fc68..4e498dd21 100644 --- a/plugins/samplesource/remoteinput/remoteinputudphandler.h +++ b/plugins/samplesource/remoteinput/remoteinputudphandler.h @@ -24,6 +24,7 @@ #include #include +#include "util/messagequeue.h" #include "remoteinputbuffer.h" #define REMOTEINPUT_THROTTLE_MS 50 @@ -63,7 +64,7 @@ public: void setMessageQueueToGUI(MessageQueue *queue) { m_messageQueueToGUI = queue; } void start(); void stop(); - void configureUDPLink(const QString& address, quint16 port); + void configureUDPLink(const QString& address, quint16 port, const QString& multicastAddress, bool multicastJoin); void getRemoteAddress(QString& s) const { s = m_remoteAddress.toString(); } int getNbOriginalBlocks() const { return RemoteNbOrginalBlocks; } bool isStreaming() const { return m_masterTimerConnected; } @@ -77,6 +78,35 @@ public slots: void dataReadyRead(); private: + class MsgUDPAddressAndPort : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const QString& getAddress() const { return m_address; } + quint16 getPort() const { return m_port; } + const QString& getMulticastAddress() const { return m_multicastAddress; } + bool getMulticastJoin() const { return m_multicastJoin; } + + static MsgUDPAddressAndPort* create(const QString& address, quint16 port, const QString& multicastAddress, bool multicastJoin) + { + return new MsgUDPAddressAndPort(address, port, multicastAddress, multicastJoin); + } + + private: + QString m_address; + quint16 m_port; + QString m_multicastAddress; + bool m_multicastJoin; + + MsgUDPAddressAndPort(const QString& address, quint16 port, const QString& multicastAddress, bool multicastJoin) : + Message(), + m_address(address), + m_port(port), + m_multicastAddress(multicastAddress), + m_multicastJoin(multicastJoin) + { } + }; + DeviceAPI *m_deviceAPI; const QTimer& m_masterTimer; bool m_masterTimerConnected; @@ -87,6 +117,8 @@ private: QHostAddress m_dataAddress; QHostAddress m_remoteAddress; quint16 m_dataPort; + QHostAddress m_multicastAddress; + bool m_multicast; bool m_dataConnected; char *m_udpBuf; qint64 m_udpReadBytes; @@ -109,13 +141,18 @@ private: bool m_throttleToggle; bool m_autoCorrBuffer; + MessageQueue m_inputMessageQueue; + void connectTimer(); void disconnectTimer(); void processData(); void adjustNbDecoderSlots(const RemoteMetaDataFEC& metaData); + void applyUDPLink(const QString& address, quint16 port, const QString& multicastAddress, bool muticastJoin); + bool handleMessage(const Message& message); private slots: void tick(); + void handleMessages(); };