1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-05-24 11:12:27 -04:00

Remote Input: added option to join a multicast group. Implements #611

This commit is contained in:
f4exb 2020-08-26 18:52:36 +02:00
parent 6a78932130
commit 2b1ddc7208
8 changed files with 216 additions and 32 deletions

View File

@ -242,8 +242,14 @@ void RemoteInput::applySettings(const RemoteInputSettings& settings, bool force)
settings.m_iqCorrection ? "true" : "false"); settings.m_iqCorrection ? "true" : "false");
} }
m_remoteInputUDPHandler->configureUDPLink(settings.m_dataAddress, settings.m_dataPort); 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); m_remoteInputUDPHandler->getRemoteAddress(remoteAddress);
}
mutexLocker.unlock(); mutexLocker.unlock();

View File

@ -304,6 +304,11 @@ void RemoteInputGui::displaySettings()
ui->apiPort->setText(tr("%1").arg(m_settings.m_apiPort)); ui->apiPort->setText(tr("%1").arg(m_settings.m_apiPort));
ui->dataPort->setText(tr("%1").arg(m_settings.m_dataPort)); ui->dataPort->setText(tr("%1").arg(m_settings.m_dataPort));
ui->dataAddress->setText(m_settings.m_dataAddress); 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->dcOffset->setChecked(m_settings.m_dcBlock);
ui->iqImbalance->setChecked(m_settings.m_iqCorrection); 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 RemoteInputGui::on_dataApplyButton_clicked(bool checked)
{ {
(void) checked; (void) checked;
m_settings.m_dataAddress = ui->dataAddress->text();
bool dataOk; ui->dataApplyButton->setEnabled(false);
int udpDataPort = ui->dataPort->text().toInt(&dataOk); ui->dataApplyButton->setStyleSheet("QPushButton { background:rgb(79,79,79); }");
if((dataOk) && (udpDataPort >= 1024) && (udpDataPort < 65535)) {
m_settings.m_dataPort = udpDataPort;
}
sendSettings(); sendSettings();
} }
@ -365,23 +365,38 @@ void RemoteInputGui::on_apiAddress_returnPressed()
void RemoteInputGui::on_dataAddress_returnPressed() void RemoteInputGui::on_dataAddress_returnPressed()
{ {
m_settings.m_dataAddress = ui->dataAddress->text(); m_settings.m_dataAddress = ui->dataAddress->text();
sendSettings(); ui->dataApplyButton->setEnabled(true);
ui->dataApplyButton->setStyleSheet("QPushButton { background-color : green; }");
} }
void RemoteInputGui::on_dataPort_returnPressed() void RemoteInputGui::on_dataPort_returnPressed()
{ {
bool dataOk; bool ok;
int udpDataPort = ui->dataPort->text().toInt(&dataOk); quint16 udpPort = ui->dataPort->text().toInt(&ok);
if((!dataOk) || (udpDataPort < 1024) || (udpDataPort > 65535)) if ((!ok) || (udpPort < 1024)) {
{ udpPort = 9998;
return;
}
else
{
m_settings.m_dataPort = udpDataPort;
sendSettings();
} }
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() void RemoteInputGui::on_apiPort_returnPressed()

View File

@ -129,6 +129,8 @@ private slots:
void on_apiPort_returnPressed(); void on_apiPort_returnPressed();
void on_dataAddress_returnPressed(); void on_dataAddress_returnPressed();
void on_dataPort_returnPressed(); void on_dataPort_returnPressed();
void on_multicastAddress_returnPressed();
void on_multicastJoin_toggled(bool checked);
void on_startStop_toggled(bool checked); void on_startStop_toggled(bool checked);
void on_eventCountsReset_clicked(bool checked); void on_eventCountsReset_clicked(bool checked);
void updateHardware(); void updateHardware();

View File

@ -686,6 +686,9 @@
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
<property name="toolTip">
<string>Set API link</string>
</property>
<property name="text"> <property name="text">
<string>Set</string> <string>Set</string>
</property> </property>
@ -723,7 +726,7 @@
</size> </size>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Local data connection IPv4 address</string> <string>Local network interface IPv4 address</string>
</property> </property>
<property name="inputMask"> <property name="inputMask">
<string>000.000.000.000</string> <string>000.000.000.000</string>
@ -758,7 +761,7 @@
</size> </size>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Local data connection port</string> <string>Local data port</string>
</property> </property>
<property name="inputMask"> <property name="inputMask">
<string>00000</string> <string>00000</string>
@ -792,6 +795,9 @@
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
<property name="toolTip">
<string>Set data link</string>
</property>
<property name="text"> <property name="text">
<string>Set</string> <string>Set</string>
</property> </property>
@ -799,6 +805,58 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="mcastLayout">
<item>
<widget class="ButtonSwitch" name="multicastJoin">
<property name="toolTip">
<string>Join or leave multicast group</string>
</property>
<property name="text">
<string>Mcast</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="multicastAddress">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Multicast group address</string>
</property>
<property name="inputMask">
<string>000.000.000.000</string>
</property>
<property name="text">
<string>0.0.0.0</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="statusLayout"> <layout class="QHBoxLayout" name="statusLayout">
<item> <item>

View File

@ -29,6 +29,8 @@ void RemoteInputSettings::resetToDefaults()
m_apiPort = 9091; m_apiPort = 9091;
m_dataAddress = "127.0.0.1"; m_dataAddress = "127.0.0.1";
m_dataPort = 9090; m_dataPort = 9090;
m_multicastAddress = "224.0.0.1";
m_multicastJoin = false;
m_dcBlock = false; m_dcBlock = false;
m_iqCorrection = false; m_iqCorrection = false;
m_useReverseAPI = false; m_useReverseAPI = false;
@ -41,6 +43,8 @@ QByteArray RemoteInputSettings::serialize() const
{ {
SimpleSerializer s(1); SimpleSerializer s(1);
s.writeString(3, m_multicastAddress);
s.writeBool(4, m_multicastJoin);
s.writeString(5, m_apiAddress); s.writeString(5, m_apiAddress);
s.writeU32(6, m_apiPort); s.writeU32(6, m_apiPort);
s.writeU32(7, m_dataPort); s.writeU32(7, m_dataPort);
@ -69,6 +73,8 @@ bool RemoteInputSettings::deserialize(const QByteArray& data)
{ {
quint32 uintval; 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.readString(5, &m_apiAddress, "127.0.0.1");
d.readU32(6, &uintval, 9090); d.readU32(6, &uintval, 9090);
m_apiPort = uintval % (1<<16); m_apiPort = uintval % (1<<16);

View File

@ -26,6 +26,8 @@ struct RemoteInputSettings {
quint16 m_apiPort; quint16 m_apiPort;
QString m_dataAddress; QString m_dataAddress;
quint16 m_dataPort; quint16 m_dataPort;
QString m_multicastAddress;
bool m_multicastJoin;
bool m_dcBlock; bool m_dcBlock;
bool m_iqCorrection; bool m_iqCorrection;
bool m_useReverseAPI; bool m_useReverseAPI;

View File

@ -27,6 +27,7 @@
#include "remoteinput.h" #include "remoteinput.h"
MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgReportSampleRateChange, Message) MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgReportSampleRateChange, Message)
MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgUDPAddressAndPort, Message)
RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceAPI *deviceAPI) : RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
@ -38,6 +39,8 @@ RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceA
m_dataAddress(QHostAddress::LocalHost), m_dataAddress(QHostAddress::LocalHost),
m_remoteAddress(QHostAddress::LocalHost), m_remoteAddress(QHostAddress::LocalHost),
m_dataPort(9090), m_dataPort(9090),
m_multicastAddress(QStringLiteral("224.0.0.1")),
m_multicast(false),
m_dataConnected(false), m_dataConnected(false),
m_udpBuf(0), m_udpBuf(0),
m_udpReadBytes(0), m_udpReadBytes(0),
@ -68,6 +71,8 @@ RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceA
m_throttlems = m_masterTimer.interval(); m_throttlems = m_masterTimer.interval();
#endif #endif
m_rateDivider = 1000 / m_throttlems; m_rateDivider = 1000 / m_throttlems;
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleMessages()));
} }
RemoteInputUDPHandler::~RemoteInputUDPHandler() RemoteInputUDPHandler::~RemoteInputUDPHandler()
@ -90,24 +95,31 @@ void RemoteInputUDPHandler::start()
return; return;
} }
if (!m_dataSocket) if (!m_dataSocket) {
{
m_dataSocket = new QUdpSocket(this); m_dataSocket = new QUdpSocket(this);
} }
if (!m_dataConnected) if (!m_dataConnected)
{ {
connect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); //, Qt::QueuedConnection); if (m_dataSocket->bind(m_multicast ? QHostAddress::AnyIPv4 : m_dataAddress, m_dataPort, QUdpSocket::ShareAddress))
if (m_dataSocket->bind(m_dataAddress, m_dataPort))
{ {
qDebug("RemoteInputUDPHandler::start: bind data socket to %s:%d", m_dataAddress.toString().toStdString().c_str(), m_dataPort); 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; m_dataConnected = true;
} }
else else
{ {
qWarning("RemoteInputUDPHandler::start: cannot bind data port %d", m_dataPort); qWarning("RemoteInputUDPHandler::start: cannot bind data port %d", m_dataPort);
disconnect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead()));
m_dataConnected = false; m_dataConnected = false;
} }
} }
@ -143,17 +155,37 @@ void RemoteInputUDPHandler::stop()
m_running = false; 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); bool addressOK = m_dataAddress.setAddress(address);
if (!addressOK) 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_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; m_dataPort = port;
stop(); stop();
start(); 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;
}
}

View File

@ -24,6 +24,7 @@
#include <QMutex> #include <QMutex>
#include <QElapsedTimer> #include <QElapsedTimer>
#include "util/messagequeue.h"
#include "remoteinputbuffer.h" #include "remoteinputbuffer.h"
#define REMOTEINPUT_THROTTLE_MS 50 #define REMOTEINPUT_THROTTLE_MS 50
@ -63,7 +64,7 @@ public:
void setMessageQueueToGUI(MessageQueue *queue) { m_messageQueueToGUI = queue; } void setMessageQueueToGUI(MessageQueue *queue) { m_messageQueueToGUI = queue; }
void start(); void start();
void stop(); 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(); } void getRemoteAddress(QString& s) const { s = m_remoteAddress.toString(); }
int getNbOriginalBlocks() const { return RemoteNbOrginalBlocks; } int getNbOriginalBlocks() const { return RemoteNbOrginalBlocks; }
bool isStreaming() const { return m_masterTimerConnected; } bool isStreaming() const { return m_masterTimerConnected; }
@ -77,6 +78,35 @@ public slots:
void dataReadyRead(); void dataReadyRead();
private: 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; DeviceAPI *m_deviceAPI;
const QTimer& m_masterTimer; const QTimer& m_masterTimer;
bool m_masterTimerConnected; bool m_masterTimerConnected;
@ -87,6 +117,8 @@ private:
QHostAddress m_dataAddress; QHostAddress m_dataAddress;
QHostAddress m_remoteAddress; QHostAddress m_remoteAddress;
quint16 m_dataPort; quint16 m_dataPort;
QHostAddress m_multicastAddress;
bool m_multicast;
bool m_dataConnected; bool m_dataConnected;
char *m_udpBuf; char *m_udpBuf;
qint64 m_udpReadBytes; qint64 m_udpReadBytes;
@ -109,13 +141,18 @@ private:
bool m_throttleToggle; bool m_throttleToggle;
bool m_autoCorrBuffer; bool m_autoCorrBuffer;
MessageQueue m_inputMessageQueue;
void connectTimer(); void connectTimer();
void disconnectTimer(); void disconnectTimer();
void processData(); void processData();
void adjustNbDecoderSlots(const RemoteMetaDataFEC& metaData); void adjustNbDecoderSlots(const RemoteMetaDataFEC& metaData);
void applyUDPLink(const QString& address, quint16 port, const QString& multicastAddress, bool muticastJoin);
bool handleMessage(const Message& message);
private slots: private slots:
void tick(); void tick();
void handleMessages();
}; };