From 96422ff19f88ea3b6f99fbc2f883fd2ee8c035f0 Mon Sep 17 00:00:00 2001 From: srcejon Date: Tue, 8 Oct 2024 17:20:18 +0100 Subject: [PATCH] RemoteTCPSink: Report server init errors via GUI. Send protocol to public list. RemoteTCPInput: Add wss protocol support. --- .../channelrx/remotetcpsink/CMakeLists.txt | 2 - plugins/channelrx/remotetcpsink/readme.md | 5 +- .../channelrx/remotetcpsink/remotetcpsink.cpp | 9 ++ .../channelrx/remotetcpsink/remotetcpsink.h | 21 +++ .../remotetcpsink/remotetcpsinkgui.cpp | 8 + .../remotetcpsink/remotetcpsinkgui.ui | 50 ++++--- .../remotetcpsink/remotetcpsinksink.cpp | 71 +++++++-- .../remotetcpsink/remotetcpsinksink.h | 2 +- .../remotetcpinput/CMakeLists.txt | 1 + plugins/samplesource/remotetcpinput/readme.md | 8 +- .../remotetcpinput/remotetcpinput.cpp | 12 +- .../remotetcpinput/remotetcpinputgui.cpp | 32 ++-- .../remotetcpinput/remotetcpinputgui.ui | 120 +++++++++------ .../remotetcpinput/remotetcpinputsettings.h | 2 +- .../remotetcpinputtcphandler.cpp | 140 +++++++++--------- .../remotetcpinput/remotetcpinputtcphandler.h | 9 +- sdrbase/CMakeLists.txt | 2 + sdrbase/util/sdrangelserverlist.cpp | 3 + sdrbase/util/sdrangelserverlist.h | 1 + .../remotetcpsink => sdrbase/util}/socket.cpp | 35 ++++- .../remotetcpsink => sdrbase/util}/socket.h | 14 +- 21 files changed, 356 insertions(+), 191 deletions(-) rename {plugins/channelrx/remotetcpsink => sdrbase/util}/socket.cpp (85%) rename {plugins/channelrx/remotetcpsink => sdrbase/util}/socket.h (88%) diff --git a/plugins/channelrx/remotetcpsink/CMakeLists.txt b/plugins/channelrx/remotetcpsink/CMakeLists.txt index 4d1884a49..a5750a799 100644 --- a/plugins/channelrx/remotetcpsink/CMakeLists.txt +++ b/plugins/channelrx/remotetcpsink/CMakeLists.txt @@ -7,7 +7,6 @@ set(remotetcpsink_SOURCES remotetcpsinksettings.cpp remotetcpsinkwebapiadapter.cpp remotetcpsinkplugin.cpp - socket.cpp ) set(remotetcpsink_HEADERS @@ -18,7 +17,6 @@ set(remotetcpsink_HEADERS remotetcpsinkwebapiadapter.h remotetcpsinkplugin.h remotetcpprotocol.h - socket.h ) include_directories( diff --git a/plugins/channelrx/remotetcpsink/readme.md b/plugins/channelrx/remotetcpsink/readme.md index 1c10da99f..d8371111d 100644 --- a/plugins/channelrx/remotetcpsink/readme.md +++ b/plugins/channelrx/remotetcpsink/readme.md @@ -6,7 +6,7 @@ The Remote TCP Sink Channel plugin sends I/Q samples from the baseband via TCP/I The client application could be SDRangel using the [Remote TCP Input](../../samplesource/remotetcpinput/readme.md) plugin or an rtl_tcp compatible application. This means that applications using rtl_tcp protocol can connect to the wide variety of SDRs supported by SDRangel. -While the plugin supports the RTL0 protocol for compatibility with older applications, the newer SDRA protocol supports the following additional features: +While the plugin supports rtl_tcp's RTL0 protocol for compatibility with older applications, the newer SDRA protocol supports the following additional features: - Different bit depths (8, 16, 24 or 32), - Additional settings, such as decimation, frequency offset and channel gain, @@ -14,7 +14,8 @@ While the plugin supports the RTL0 protocol for compatibility with older applica - IQ compression, using FLAC or zlib, to reduce network bandwidth, - IQ squelch, to reduce network bandwidth when no signal is being received, - Real-time forwarding of device/antenna position and direction to client, -- Text messaging between clients and server. +- Text messaging between clients and server, +- Use of either TCP or WSS (WebSocket Secure Protocol). The Remote TCP Sink can support multiple clients connected simultaneously, with a user-defined maximum client limit. Clients can also have a time limit applied. diff --git a/plugins/channelrx/remotetcpsink/remotetcpsink.cpp b/plugins/channelrx/remotetcpsink/remotetcpsink.cpp index bd9a5084e..ce7f120df 100644 --- a/plugins/channelrx/remotetcpsink/remotetcpsink.cpp +++ b/plugins/channelrx/remotetcpsink/remotetcpsink.cpp @@ -45,6 +45,7 @@ MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgReportConnection, Message) MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgReportDisconnect, Message) MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgReportBW, Message) MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgSendMessage, Message) +MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgError, Message) const char* const RemoteTCPSink::m_channelIdURI = "sdrangel.channel.remotetcpsink"; const char* const RemoteTCPSink::m_channelId = "RemoteTCPSink"; @@ -713,9 +714,17 @@ void RemoteTCPSink::updatePublicListing() QString device = MainCore::instance()->getDevice(getDeviceSetIndex())->getHardwareId(); + QString protocol; + if (m_settings.m_protocol == RemoteTCPSinkSettings::SDRA_WSS) { + protocol = "SDRangel wss"; + } else { + protocol = "SDRangel"; + } + QJsonObject json; json.insert("address", m_settings.m_publicAddress); json.insert("port", m_settings.m_publicPort); + json.insert("protocol", protocol); json.insert("minFrequency", m_settings.m_minFrequency); json.insert("maxFrequency", m_settings.m_maxFrequency); json.insert("maxSampleRate", m_settings.m_maxSampleRate); diff --git a/plugins/channelrx/remotetcpsink/remotetcpsink.h b/plugins/channelrx/remotetcpsink/remotetcpsink.h index f36923dd7..b9f491ce7 100644 --- a/plugins/channelrx/remotetcpsink/remotetcpsink.h +++ b/plugins/channelrx/remotetcpsink/remotetcpsink.h @@ -183,6 +183,27 @@ public: { } }; + class MsgError : public Message { + MESSAGE_CLASS_DECLARATION + + public: + + const QString& getError() const { return m_error; } + + static MsgError *create(const QString& error) + { + return new MsgError(error); + } + + private: + QString m_error; + + MsgError(const QString& error) : + Message(), + m_error(error) + { } + }; + RemoteTCPSink(DeviceAPI *deviceAPI); virtual ~RemoteTCPSink(); virtual void destroy() { delete this; } diff --git a/plugins/channelrx/remotetcpsink/remotetcpsinkgui.cpp b/plugins/channelrx/remotetcpsink/remotetcpsinkgui.cpp index 09fabb870..c8f3af621 100644 --- a/plugins/channelrx/remotetcpsink/remotetcpsinkgui.cpp +++ b/plugins/channelrx/remotetcpsink/remotetcpsinkgui.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "device/deviceuiset.h" #include "gui/basicchannelsettingsdialog.h" @@ -276,6 +277,13 @@ bool RemoteTCPSinkGUI::handleMessage(const Message& message) return true; } + else if (RemoteTCPSink::MsgError::match(message)) + { + RemoteTCPSink::MsgError& msg = (RemoteTCPSink::MsgError&) message; + QString error = msg.getError(); + QMessageBox::warning(this, "RemoteTCPSink", error, QMessageBox::Ok); + return true; + } else { return false; diff --git a/plugins/channelrx/remotetcpsink/remotetcpsinkgui.ui b/plugins/channelrx/remotetcpsink/remotetcpsinkgui.ui index 72308406e..afbeba69d 100644 --- a/plugins/channelrx/remotetcpsink/remotetcpsinkgui.ui +++ b/plugins/channelrx/remotetcpsink/remotetcpsinkgui.ui @@ -11,7 +11,7 @@ - + 0 0 @@ -108,7 +108,7 @@ PointingHandCursor - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus Channel frequency shift from center in Hz @@ -125,7 +125,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -177,7 +177,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -193,13 +193,13 @@ Channel power - Qt::RightToLeft + Qt::LayoutDirection::RightToLeft 0.0 - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -263,7 +263,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -301,7 +301,7 @@ -150 - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -315,7 +315,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -335,7 +335,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -366,7 +366,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -381,7 +381,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -435,7 +435,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -497,7 +497,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -549,7 +549,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -587,12 +587,12 @@ - SDRA + SDRangel - SDRA wss + SDRangel wss @@ -628,7 +628,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -658,7 +658,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -696,6 +696,12 @@ Values are averaged over the last 10 seconds 191 + + + 0 + 0 + + Messages @@ -759,6 +765,12 @@ Values are averaged over the last 10 seconds 191 + + + 0 + 0 + + Connection Log diff --git a/plugins/channelrx/remotetcpsink/remotetcpsinksink.cpp b/plugins/channelrx/remotetcpsink/remotetcpsinksink.cpp index 7e46e3729..f3f8fc2dd 100644 --- a/plugins/channelrx/remotetcpsink/remotetcpsinksink.cpp +++ b/plugins/channelrx/remotetcpsink/remotetcpsinksink.cpp @@ -380,10 +380,10 @@ void RemoteTCPSinkSink::processOneSample(Complex &ci) if (ret == Z_STREAM_END) { deflateReset(&m_zStream); } else if (ret != Z_OK) { - qDebug() << "Failed to deflate" << ret; + qDebug() << "RemoteTCPSinkSink::processOneSample: Failed to deflate" << ret; } if (m_zStream.avail_in != 0) { - qDebug() << "Warning: Data still in input buffer"; + qDebug() << "RemoteTCPSinkSink::processOneSample: Data still in input buffer"; } int compressedBytes = m_zOutBuf.size() - m_zStream.avail_out; @@ -497,6 +497,7 @@ void RemoteTCPSinkSink::applySettings(const RemoteTCPSinkSettings& settings, con } if ((settingsKeys.contains("compressionLevel") && (settings.m_compressionLevel != m_settings.m_compressionLevel)) + || (settingsKeys.contains("compression") && (settings.m_compression != m_settings.m_compression)) || (settingsKeys.contains("sampleBits") && (settings.m_sampleBits != m_settings.m_sampleBits)) || (settingsKeys.contains("blockSize") && (settings.m_blockSize != m_settings.m_blockSize)) || (settingsKeys.contains("channelSampleRate") && (settings.m_channelSampleRate != m_settings.m_channelSampleRate)) @@ -506,6 +507,7 @@ void RemoteTCPSinkSink::applySettings(const RemoteTCPSinkSettings& settings, con } if ((settingsKeys.contains("compressionLevel") && (settings.m_compressionLevel != m_settings.m_compressionLevel)) + || (settingsKeys.contains("compression") && (settings.m_compression != m_settings.m_compression)) || force) { initZLib = true; @@ -670,15 +672,46 @@ void RemoteTCPSinkSink::startServer() if (m_settings.m_protocol == RemoteTCPSinkSettings::SDRA_WSS) { #ifndef QT_NO_OPENSSL - m_webSocketServer = new QWebSocketServer(QStringLiteral("Remote TCP Sink"), - QWebSocketServer::SecureMode, - this); QSslConfiguration sslConfiguration; qDebug() << "RemoteTCPSinkSink::startServer: SSL config: " << m_settings.m_certificate << m_settings.m_key; + if (m_settings.m_certificate.isEmpty()) + { + QString msg = "RemoteTCPSink requires an SSL certificate in order to use wss protocol"; + qWarning() << msg; + if (m_messageQueueToGUI) { + m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg)); + } + return; + } + if (m_settings.m_certificate.isEmpty()) + { + QString msg = "RemoteTCPSink requires an SSL key in order to use wss protocol"; + qWarning() << msg; + if (m_messageQueueToGUI) { + m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg)); + } + return; + } QFile certFile(m_settings.m_certificate); + if (!certFile.open(QIODevice::ReadOnly)) + { + QString msg = QString("RemoteTCPSink failed to open certificate %1: %2").arg(m_settings.m_certificate).arg(certFile.errorString()); + qWarning() << msg; + if (m_messageQueueToGUI) { + m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg)); + } + return; + } QFile keyFile(m_settings.m_key); - certFile.open(QIODevice::ReadOnly); - keyFile.open(QIODevice::ReadOnly); + if (!keyFile.open(QIODevice::ReadOnly)) + { + QString msg = QString("RemoteTCPSink failed to open key %1: %2").arg(m_settings.m_key).arg(keyFile.errorString()); + qWarning() << msg; + if (m_messageQueueToGUI) { + m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg)); + } + return; + } QSslCertificate certificate(&certFile, QSsl::Pem); QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem); certFile.close(); @@ -686,6 +719,10 @@ void RemoteTCPSinkSink::startServer() sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); sslConfiguration.setLocalCertificate(certificate); sslConfiguration.setPrivateKey(sslKey); + + m_webSocketServer = new QWebSocketServer(QStringLiteral("Remote TCP Sink"), + QWebSocketServer::SecureMode, + this); m_webSocketServer->setSslConfiguration(sslConfiguration); QHostAddress address(m_settings.m_dataAddress); @@ -695,8 +732,11 @@ void RemoteTCPSinkSink::startServer() #endif if (!m_webSocketServer->listen(address, m_settings.m_dataPort)) { - qCritical() << "RemoteTCPSink failed to listen on" << m_settings.m_dataAddress << "port" << m_settings.m_dataPort; - // FIXME: Report to GUI? + QString msg = QString("RemoteTCPSink failed to listen on %1 port %2: %3").arg(m_settings.m_dataAddress).arg(m_settings.m_dataPort).arg(m_webSocketServer->errorString()); + qWarning() << msg; + if (m_messageQueueToGUI) { + m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg)); + } } else { @@ -705,7 +745,11 @@ void RemoteTCPSinkSink::startServer() connect(m_webSocketServer, &QWebSocketServer::sslErrors, this, &RemoteTCPSinkSink::onSslErrors); } #else - qWarning("RemoteTCPSinkSink::startServer: SSL is not supported"); + QString msg = "RemoteTCPSink unable to use wss protocol as SSL is not supported"; + qWarning() << msg; + if (m_messageQueueToGUI) { + m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg)); + } #endif } else @@ -713,8 +757,11 @@ void RemoteTCPSinkSink::startServer() m_server = new QTcpServer(this); if (!m_server->listen(QHostAddress(m_settings.m_dataAddress), m_settings.m_dataPort)) { - qCritical() << "RemoteTCPSink failed to listen on" << m_settings.m_dataAddress << "port" << m_settings.m_dataPort; - // FIXME: Report to GUI? + QString msg = QString("RemoteTCPSink failed to listen on %1 port %2: %3").arg(m_settings.m_dataAddress).arg(m_settings.m_dataPort).arg(m_webSocketServer->errorString()); + qWarning() << msg; + if (m_messageQueueToGUI) { + m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg)); + } } else { diff --git a/plugins/channelrx/remotetcpsink/remotetcpsinksink.h b/plugins/channelrx/remotetcpsink/remotetcpsinksink.h index dd5f34739..9972565ab 100644 --- a/plugins/channelrx/remotetcpsink/remotetcpsinksink.h +++ b/plugins/channelrx/remotetcpsink/remotetcpsinksink.h @@ -40,7 +40,7 @@ #include "remotetcpsinksettings.h" #include "remotetcpprotocol.h" -#include "socket.h" +#include "util/socket.h" class DeviceSampleSource; diff --git a/plugins/samplesource/remotetcpinput/CMakeLists.txt b/plugins/samplesource/remotetcpinput/CMakeLists.txt index b7f2693b4..644c5c144 100644 --- a/plugins/samplesource/remotetcpinput/CMakeLists.txt +++ b/plugins/samplesource/remotetcpinput/CMakeLists.txt @@ -57,6 +57,7 @@ endif() target_link_libraries(${TARGET_NAME} PRIVATE Qt::Core + Qt::WebSockets ${TARGET_LIB} sdrbase ${TARGET_LIB_GUI} diff --git a/plugins/samplesource/remotetcpinput/readme.md b/plugins/samplesource/remotetcpinput/readme.md index 9158dfd40..48f929ebb 100644 --- a/plugins/samplesource/remotetcpinput/readme.md +++ b/plugins/samplesource/remotetcpinput/readme.md @@ -93,7 +93,7 @@ When unchecked, the channel sample rate can be set to any value. Specifies number of bits per I/Q sample transmitted via TCP/IP. -When the protocol is RTL0, only 8-bits are supported. SDRA and Spy Server protocol supports 8, 16, 24 and 32-bit samples. +When the protocol is RTL0, only 8-bits are supported. SDRangel and Spy Server protocol supports 8, 16, 24 and 32-bit samples.

19: Server IP address

@@ -105,14 +105,16 @@ TCP port on the server to connect to.

21: Protocol

-Selects protocol to use. Set to SDRangel for rtl_tcp, rsp_tcp or SDRangel's own protocol. Alternative, Spy Server can be selected to connect to Spy Servers. +Selects protocol to use. Set to SDRangel for rtl_tcp, rsp_tcp or SDRangel's own protocol. +Set to SDRangel wss to use SDRangel's protocol over WebSocket Secure. +Alternatively, Spy Server can be selected to connect to Spy Servers.

23: Connection settings

Determines which settings are used when connecting. When checked, settings in the RemoteTCPInput GUI are written to the remote device upon connection. -When unchecked, if the remote server is using the SDRA protocol, the RemoteTCPInput GUI will be updated with the current settings from the remote device. +When unchecked, if the remote server is using the SDRangel protocol, the RemoteTCPInput GUI will be updated with the current settings from the remote device. If the remote server is using the RTL0 protocol, the GUI will not be updated, which may mean the two are inconsistent.

24: Pre-fill

diff --git a/plugins/samplesource/remotetcpinput/remotetcpinput.cpp b/plugins/samplesource/remotetcpinput/remotetcpinput.cpp index 72a0f7522..ce54ddeb4 100644 --- a/plugins/samplesource/remotetcpinput/remotetcpinput.cpp +++ b/plugins/samplesource/remotetcpinput/remotetcpinput.cpp @@ -96,7 +96,7 @@ void RemoteTCPInput::destroy() void RemoteTCPInput::init() { - qDebug() << "*************** RemoteTCPInput::init"; + qDebug() << "RemoteTCPInput::init"; applySettings(m_settings, QList(), true); } @@ -109,7 +109,6 @@ bool RemoteTCPInput::start() } m_remoteInputTCPPHandler->reset(); m_remoteInputTCPPHandler->start(); - qDebug() << "************ RemoteTCPInput::start" << m_settings.m_dataAddress; m_remoteInputTCPPHandler->getInputMessageQueue()->push(RemoteTCPInputTCPHandler::MsgConfigureTcpHandler::create(m_settings, QList(), true)); m_thread.start(); m_running = true; @@ -122,19 +121,14 @@ void RemoteTCPInput::stop() if (!m_running) { // For wasm, important not to call m_remoteInputTCPPHandler->stop() twice // as mutex can deadlock when this object is being deleted - qDebug() << "RemoteTCPInput::stop - Not running"; return; } m_remoteInputTCPPHandler->stop(); - qDebug() << "RemoteTCPInput::stop1"; m_thread.quit(); - qDebug() << "RemoteTCPInput::stop2"; #ifndef __EMSCRIPTEN__ - qDebug() << "RemoteTCPInput::stop3"; m_thread.wait(); #endif m_running = false; - qDebug() << "RemoteTCPInput::stopped"; } QByteArray RemoteTCPInput::serialize() const @@ -151,9 +145,6 @@ bool RemoteTCPInput::deserialize(const QByteArray& data) m_settings.resetToDefaults(); success = false; } - - qDebug() << "************** RemoteTCPInput::deserialize" << m_settings.m_dataAddress; - MsgConfigureRemoteTCPInput* message = MsgConfigureRemoteTCPInput::create(m_settings, QList(), true); m_inputMessageQueue.push(message); @@ -230,7 +221,6 @@ bool RemoteTCPInput::handleMessage(const Message& message) { qDebug() << "RemoteTCPInput::handleMessage:" << message.getIdentifier(); MsgConfigureRemoteTCPInput& conf = (MsgConfigureRemoteTCPInput&) message; - qDebug() << "*********** RemoteTCPInput::handleMessage MsgConfigureRemoteTCPInput" << m_settings.m_dataAddress; applySettings(conf.getSettings(), conf.getSettingsKeys(), conf.getForce()); return true; } diff --git a/plugins/samplesource/remotetcpinput/remotetcpinputgui.cpp b/plugins/samplesource/remotetcpinput/remotetcpinputgui.cpp index 27fed839d..ea52cbf89 100644 --- a/plugins/samplesource/remotetcpinput/remotetcpinputgui.cpp +++ b/plugins/samplesource/remotetcpinput/remotetcpinputgui.cpp @@ -117,7 +117,7 @@ void RemoteTCPInputGui::destroy() void RemoteTCPInputGui::resetToDefaults() { - qDebug() << "*************** RemoteTCPInputGui::resetToDefaults"; + qDebug() << "RemoteTCPInputGui::resetToDefaults"; m_settings.resetToDefaults(); displaySettings(); m_forceSettings = true; @@ -158,7 +158,6 @@ bool RemoteTCPInputGui::handleMessage(const Message& message) } else { m_settings.applySettings(cfg.getSettingsKeys(), cfg.getSettings()); } - qDebug() << "********* RemoteTCPInputGui::handleMessage MsgConfigureRemoteTCPInput" << m_settings.m_dataAddress; blockApplySettings(true); displaySettings(); @@ -304,16 +303,7 @@ bool RemoteTCPInputGui::handleMessage(const Message& message) { const RemoteTCPInputTCPHandler::MsgReportConnection& report = (RemoteTCPInputTCPHandler::MsgReportConnection&) message; qDebug() << "RemoteTCPInputGui::handleMessage: MsgReportConnection connected: " << report.getConnected(); - if (report.getConnected()) - { - m_connectionError = false; - //ui->startStop->setStyleSheet("QToolButton { background-color : green; }"); - } - else - { - m_connectionError = true; - //ui->startStop->setStyleSheet("QToolButton { background-color : red; }"); - } + m_connectionError = !report.getConnected(); updateStatus(); return true; } @@ -921,14 +911,18 @@ void RemoteTCPInputGui::on_squelchGate_valueChanged(double value) void RemoteTCPInputGui::on_dataAddress_editingFinished() { - m_settings.m_dataAddress = ui->dataAddress->currentText(); - m_settingsKeys.append("dataAddress"); - m_settings.m_addressList.clear(); - for (int i = 0; i < ui->dataAddress->count(); i++) { - m_settings.m_addressList.append(ui->dataAddress->itemText(i)); + QString text = ui->dataAddress->currentText(); + if (text != m_settings.m_dataAddress) + { + m_settings.m_dataAddress = text; + m_settingsKeys.append("dataAddress"); + m_settings.m_addressList.clear(); + for (int i = 0; i < ui->dataAddress->count(); i++) { + m_settings.m_addressList.append(ui->dataAddress->itemText(i)); + } + m_settingsKeys.append("addressList"); + sendSettings(); } - m_settingsKeys.append("addressList"); - sendSettings(); } void RemoteTCPInputGui::on_dataAddress_currentIndexChanged(int index) diff --git a/plugins/samplesource/remotetcpinput/remotetcpinputgui.ui b/plugins/samplesource/remotetcpinput/remotetcpinputgui.ui index c90b15ced..75e7f180b 100644 --- a/plugins/samplesource/remotetcpinput/remotetcpinputgui.ui +++ b/plugins/samplesource/remotetcpinput/remotetcpinputgui.ui @@ -89,7 +89,7 @@ 00000k
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
@@ -100,7 +100,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -134,7 +134,7 @@ PointingHandCursor - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus Center frequency in kHz @@ -153,14 +153,14 @@ kHz - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - Qt::Horizontal + Qt::Orientation::Horizontal @@ -199,7 +199,7 @@ 1 - Qt::Horizontal + Qt::Orientation::Horizontal @@ -215,7 +215,7 @@ 0 - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -224,7 +224,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -253,7 +253,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -288,7 +288,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -342,7 +342,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -415,7 +415,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -459,14 +459,14 @@ 40.0dB - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::Vertical + Qt::Orientation::Vertical @@ -500,7 +500,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -534,7 +534,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -559,7 +559,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -609,7 +609,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -624,7 +624,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -669,7 +669,7 @@ PointingHandCursor - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus Channel shift frequency from center in Hz @@ -686,7 +686,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -804,7 +804,7 @@ Use to ensure full dynamic range of 8-bit data is used. - Qt::Horizontal + Qt::Orientation::Horizontal @@ -866,7 +866,7 @@ Use to ensure full dynamic range of 8-bit data is used. - Qt::Horizontal + Qt::Orientation::Horizontal @@ -921,7 +921,7 @@ Use to ensure full dynamic range of 8-bit data is used. - Qt::Vertical + Qt::Orientation::Vertical @@ -959,7 +959,7 @@ Use to ensure full dynamic range of 8-bit data is used. -150 - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -973,7 +973,7 @@ Use to ensure full dynamic range of 8-bit data is used. - Qt::Vertical + Qt::Orientation::Vertical @@ -993,14 +993,14 @@ Use to ensure full dynamic range of 8-bit data is used. - Qt::Vertical + Qt::Orientation::Vertical - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1022,13 +1022,13 @@ Use to ensure full dynamic range of 8-bit data is used. Channel power - Qt::RightToLeft + Qt::LayoutDirection::RightToLeft 0.0 - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -1044,7 +1044,7 @@ Use to ensure full dynamic range of 8-bit data is used. - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1065,6 +1065,12 @@ Use to ensure full dynamic range of 8-bit data is used. + + + 0 + 0 + + 120 @@ -1110,7 +1116,7 @@ Use to ensure full dynamic range of 8-bit data is used. - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1124,7 +1130,7 @@ Use to ensure full dynamic range of 8-bit data is used. - 92 + 110 0 @@ -1136,6 +1142,11 @@ Use to ensure full dynamic range of 8-bit data is used. SDRangel + + + SDRangel wss + + Spy Server @@ -1200,7 +1211,7 @@ When unchecked, if remote device is using SDRA protocol, local settings are upda - Qt::Vertical + Qt::Orientation::Vertical @@ -1263,14 +1274,14 @@ When unchecked, if remote device is using SDRA protocol, local settings are upda 10.00s - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::Vertical + Qt::Orientation::Vertical @@ -1328,7 +1339,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1390,7 +1401,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b Messages - QListView::Static + QListView::Movement::Static @@ -1399,7 +1410,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1427,7 +1438,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b 500 - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1504,7 +1515,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1520,7 +1531,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b - Qt::Vertical + Qt::Orientation::Vertical @@ -1547,18 +1558,18 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
gui/valuedialz.h
1 - - ValueDial - QWidget -
gui/valuedial.h
- 1 -
LevelMeterSignalDB QWidget
gui/levelmeter.h
1
+ + ValueDial + QWidget +
gui/valuedial.h
+ 1 +
PeriodDial QWidget @@ -1583,10 +1594,23 @@ This should typically be empty. If full, your CPU cannot keep up and data will b channelGain decimation sampleBits + squelchEnabled + squelch dataAddress + dataPort protocol overrideRemoteSettings preFill + sendMessage + txAddress + txMessage + messages + replayOffset + replayNow + replayPlus + replayMinus + replayLoop + replaySave diff --git a/plugins/samplesource/remotetcpinput/remotetcpinputsettings.h b/plugins/samplesource/remotetcpinput/remotetcpinputsettings.h index c209532c0..bb4606fbb 100644 --- a/plugins/samplesource/remotetcpinput/remotetcpinputsettings.h +++ b/plugins/samplesource/remotetcpinput/remotetcpinputsettings.h @@ -53,7 +53,7 @@ struct RemoteTCPInputSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; QStringList m_addressList; // List of dataAddresses that have been used in the past - QString m_protocol; // "SDRangel" or "Spy Server" + QString m_protocol; // "SDRangel", "SDRangel wss" or "Spy Server" float m_replayOffset; //!< Replay offset in seconds float m_replayLength; //!< Replay buffer size in seconds float m_replayStep; //!< Replay forward/back step size in seconds diff --git a/plugins/samplesource/remotetcpinput/remotetcpinputtcphandler.cpp b/plugins/samplesource/remotetcpinput/remotetcpinputtcphandler.cpp index b2eb03293..fdecae7ba 100644 --- a/plugins/samplesource/remotetcpinput/remotetcpinputtcphandler.cpp +++ b/plugins/samplesource/remotetcpinput/remotetcpinputtcphandler.cpp @@ -18,6 +18,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include #include "device/deviceapi.h" @@ -36,6 +37,8 @@ RemoteTCPInputTCPHandler::RemoteTCPInputTCPHandler(SampleSinkFifo *sampleFifo, D m_deviceAPI(deviceAPI), m_running(false), m_dataSocket(nullptr), + m_tcpSocket(nullptr), + m_webSocket(nullptr), m_tcpBuf(nullptr), m_sampleFifo(sampleFifo), m_replayBuffer(replayBuffer), @@ -82,9 +85,7 @@ RemoteTCPInputTCPHandler::~RemoteTCPInputTCPHandler() if (m_converterBuffer) { delete[] m_converterBuffer; } - qDebug() << "RemoteTCPInputTCPHandler::~RemoteTCPInputTCPHandler cleanup"; cleanup(); - qDebug() << "RemoteTCPInputTCPHandler::~RemoteTCPInputTCPHandler done"; } void RemoteTCPInputTCPHandler::reset() @@ -114,7 +115,6 @@ void RemoteTCPInputTCPHandler::start() void RemoteTCPInputTCPHandler::stop() { - qDebug("RemoteTCPInputTCPHandler::stop locking"); QMutexLocker mutexLocker(&m_mutex); qDebug("RemoteTCPInputTCPHandler::stop"); @@ -142,24 +142,40 @@ void RemoteTCPInputTCPHandler::finished() cleanup(); disconnect(thread(), SIGNAL(finished()), this, SLOT(finished())); m_running = false; - qDebug("RemoteTCPInputTCPHandler::finished done"); } -void RemoteTCPInputTCPHandler::connectToHost(const QString& address, quint16 port) +void RemoteTCPInputTCPHandler::connectToHost(const QString& address, quint16 port, const QString& protocol) { - qDebug("RemoteTCPInputTCPHandler::connectToHost: connect to %s:%d", address.toStdString().c_str(), port); - m_dataSocket = new QTcpSocket(this); + qDebug("RemoteTCPInputTCPHandler::connectToHost: connect to %s %s:%d", protocol.toStdString().c_str(), address.toStdString().c_str(), port); m_fillBuffer = true; m_readMetaData = false; - connect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); - connect(m_dataSocket, SIGNAL(connected()), this, SLOT(connected())); - connect(m_dataSocket, SIGNAL(disconnected()), this, SLOT(disconnected())); -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) - connect(m_dataSocket, QOverload::of(&QAbstractSocket::error), this, &RemoteTCPInputTCPHandler::errorOccurred); -#else - connect(m_dataSocket, &QAbstractSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred); + if (protocol == "SDRangel wss") + { + m_webSocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this); + connect(m_webSocket, &QWebSocket::binaryFrameReceived, this, &RemoteTCPInputTCPHandler::dataReadyRead); + connect(m_webSocket, &QWebSocket::connected, this, &RemoteTCPInputTCPHandler::connected); + connect(m_webSocket, &QWebSocket::disconnected, this, &RemoteTCPInputTCPHandler::disconnected); +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + connect(m_webSocket, &QWebSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred); #endif - m_dataSocket->connectToHost(address, port); + connect(m_webSocket, &QWebSocket::sslErrors, this, &RemoteTCPInputTCPHandler::sslErrors); + m_webSocket->open(QUrl(QString("wss://%1:%2").arg(address).arg(port))); + m_dataSocket = new WebSocket(m_webSocket); + } + else + { + m_tcpSocket = new QTcpSocket(this); + connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); + connect(m_tcpSocket, SIGNAL(connected()), this, SLOT(connected())); + connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected())); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + connect(m_tcpSocket, QOverload::of(&QAbstractSocket::error), this, &RemoteTCPInputTCPHandler::errorOccurred); +#else + connect(m_tcpSocket, &QAbstractSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred); +#endif + m_tcpSocket->connectToHost(address, port); + m_dataSocket = new TCPSocket(m_tcpSocket); + } } /*void RemoteTCPInputTCPHandler::disconnectFromHost() @@ -187,22 +203,45 @@ void RemoteTCPInputTCPHandler::cleanup() FLAC__stream_decoder_delete(m_decoder); m_decoder = nullptr; } + if (m_webSocket) + { + qDebug() << "RemoteTCPInputTCPHandler::cleanup: Closing and deleting web socket"; + disconnect(m_webSocket, &QWebSocket::binaryFrameReceived, this, &RemoteTCPInputTCPHandler::dataReadyRead); + disconnect(m_webSocket, &QWebSocket::connected, this, &RemoteTCPInputTCPHandler::connected); + disconnect(m_webSocket, &QWebSocket::disconnected, this, &RemoteTCPInputTCPHandler::disconnected); +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + disconnect(m_webSocket, &QWebSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred); +#endif + } + if (m_tcpSocket) + { + qDebug() << "RemoteTCPInputTCPHandler::cleanup: Closing and deleting TCP socket"; + // Disconnect disconnected, so don't get called recursively + disconnect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); + disconnect(m_tcpSocket, SIGNAL(connected()), this, SLOT(connected())); + disconnect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected())); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + disconnect(m_tcpSocket, QOverload::of(&QAbstractSocket::error), this, &RemoteTCPInputTCPHandler::errorOccurred); +#else + disconnect(m_tcpSocket, &QAbstractSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred); +#endif + } if (m_dataSocket) { - qDebug() << "RemoteTCPInputTCPHandler::cleanup: Closing and deleting socket"; - // Disconnect disconnected, so don't get called recursively - disconnect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); - disconnect(m_dataSocket, SIGNAL(connected()), this, SLOT(connected())); - disconnect(m_dataSocket, SIGNAL(disconnected()), this, SLOT(disconnected())); -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) - disconnect(m_dataSocket, QOverload::of(&QAbstractSocket::error), this, &RemoteTCPInputTCPHandler::errorOccurred); -#else - disconnect(m_dataSocket, &QAbstractSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred); -#endif m_dataSocket->close(); m_dataSocket->deleteLater(); m_dataSocket = nullptr; } + if (m_webSocket) + { + m_webSocket->deleteLater(); + m_webSocket = nullptr; + } + if (m_tcpSocket) + { + m_tcpSocket->deleteLater(); + m_tcpSocket = nullptr; + } } // Clear input buffer when settings change that invalidate the data in it @@ -620,7 +659,7 @@ void RemoteTCPInputTCPHandler::applySettings(const RemoteTCPInputSettings& setti { //disconnectFromHost(); cleanup(); - connectToHost(settings.m_dataAddress, settings.m_dataPort); + connectToHost(settings.m_dataAddress, settings.m_dataPort, settings.m_protocol); } if (force) { @@ -651,35 +690,6 @@ static void flacErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDe return handler->flacError(decoder, status); } -/*FLAC__StreamDecoderReadStatus RemoteTCPInputTCPHandler::flacRead(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes) -{ - if (m_dataSocket) - { - qint64 bytesRequested = *bytes; - qint64 bytesRead = std::min(bytesRequested, m_compressedData.size()); - - //bytesRead = m_dataSocket->read((char *) buffer, bytesRequested); - - memcpy(buffer, m_compressedData.constData(), bytesRead); - - qDebug() << "flacRead" << bytesRequested << bytesRead; - - if (bytesRead != -1) - { - *bytes = (size_t) bytesRead; - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - } - else - { - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - } - } - else - { - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - } -}*/ - FLAC__StreamDecoderReadStatus RemoteTCPInputTCPHandler::flacRead(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes) { (void) decoder; @@ -690,7 +700,6 @@ FLAC__StreamDecoderReadStatus RemoteTCPInputTCPHandler::flacRead(const FLAC__Str memcpy(buffer, m_compressedData.constData(), bytesRead); m_compressedData.remove(0, bytesRead); - //qDebug() << "RemoteTCPInputTCPHandler::flacRead bytesRequested" << bytesRequested << "bytesRead" << bytesRead; if (bytesRead == 0) { qDebug() << "RemoteTCPInputTCPHandler::flacRead: Decoder will hang if we can't return data"; @@ -821,7 +830,6 @@ FLAC__StreamDecoderWriteStatus RemoteTCPInputTCPHandler::flacWrite(const FLAC__S m_uncompressedFrames++; int nbSamples = frame->header.blocksize; -//qDebug() << "RemoteTCPInputTCPHandler::flacWrite m_uncompressedFrames" << m_uncompressedFrames << "nbSamples" << nbSamples; if (nbSamples > (int) m_converterBufferNbSamples) { if (m_converterBuffer) { @@ -1011,20 +1019,13 @@ void RemoteTCPInputTCPHandler::connected() } // Start calls to processData m_timer.start(); - - /*if (m_dataSocket->bytesAvailable()) { - qDebug() << "Data is already available"; - dataReadyRead(); - } else { - qDebug() << "No data available"; - }*/ } void RemoteTCPInputTCPHandler::reconnect() { QMutexLocker mutexLocker(&m_mutex); if (!m_dataSocket) { - connectToHost(m_settings.m_dataAddress, m_settings.m_dataPort); + connectToHost(m_settings.m_dataAddress, m_settings.m_dataPort, m_settings.m_protocol); } } @@ -1071,6 +1072,12 @@ void RemoteTCPInputTCPHandler::errorOccurred(QAbstractSocket::SocketError socket } } +void RemoteTCPInputTCPHandler::sslErrors(const QList &errors) +{ + qDebug() << "RemoteTCPInputTCPHandler::sslErrors: " << errors; + m_webSocket->ignoreSslErrors(); // FIXME: Add a setting whether to do this? +} + void RemoteTCPInputTCPHandler::dataReadyRead() { QMutexLocker mutexLocker(&m_mutex); @@ -1753,7 +1760,6 @@ void RemoteTCPInputTCPHandler::processCommands() m_compressedData.resize(s + m_commandLength); qint64 bytesRead = m_dataSocket->read(&m_compressedData.data()[s], m_commandLength); m_compressedFrames++; - //qDebug() << "*************************** RemoteTCPProtocol::dataIQFLAC m_compressedData.size()" << m_compressedData.size() << "m_compressedFrames" << m_compressedFrames << "m_uncompressedFrames" << m_uncompressedFrames; if (bytesRead == m_commandLength) { // FLAC encoder writes out 4 (fLaC), 38 (STREAMINFO), 51 (?) byte headers, that are transmitted as one command block, @@ -1940,7 +1946,7 @@ void RemoteTCPInputTCPHandler::processData() { QMutexLocker mutexLocker(&m_mutex); - if (m_dataSocket && (m_dataSocket->state() == QAbstractSocket::ConnectedState)) + if (m_dataSocket && m_dataSocket->isConnected()) { int sampleRate = m_settings.m_channelSampleRate; int bytesPerIQPair = m_iqOnly ? (2 * m_settings.m_sampleBits / 8) : (2 * sizeof(Sample)); diff --git a/plugins/samplesource/remotetcpinput/remotetcpinputtcphandler.h b/plugins/samplesource/remotetcpinput/remotetcpinputtcphandler.h index f1b990ca2..192873f43 100644 --- a/plugins/samplesource/remotetcpinput/remotetcpinputtcphandler.h +++ b/plugins/samplesource/remotetcpinput/remotetcpinputtcphandler.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,7 @@ #include "util/messagequeue.h" #include "util/movingaverage.h" +#include "util/socket.h" #include "dsp/replaybuffer.h" #include "remotetcpinputsettings.h" #include "../../channelrx/remotetcpsink/remotetcpprotocol.h" @@ -185,6 +187,7 @@ public slots: void connected(); void disconnected(); void errorOccurred(QAbstractSocket::SocketError socketError); + void sslErrors(const QList &errors); private: @@ -200,7 +203,9 @@ private: DeviceAPI *m_deviceAPI; bool m_running; - QTcpSocket *m_dataSocket; + Socket *m_dataSocket; + QTcpSocket *m_tcpSocket; + QWebSocket *m_webSocket; char *m_tcpBuf; SampleSinkFifo *m_sampleFifo; ReplayBuffer *m_replayBuffer; @@ -253,7 +258,7 @@ private: MovingAverageUtil m_movingAverage; bool handleMessage(const Message& message); - void connectToHost(const QString& address, quint16 port); + void connectToHost(const QString& address, quint16 port, const QString& protocol); //void disconnectFromHost(); void cleanup(); void clearBuffer(); diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index bb6989995..bc66651f6 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -269,6 +269,7 @@ set(sdrbase_SOURCES util/sdrangelserverlist.cpp util/simpleserializer.cpp util/serialutil.cpp + util/socket.cpp util/solardynamicsobservatory.cpp util/sondehub.cpp #util/spinlock.cpp @@ -530,6 +531,7 @@ set(sdrbase_HEADERS util/sdrangelserverlist.h util/simpleserializer.h util/serialutil.h + util/socket.h util/solardynamicsobservatory.h util/sondehub.h #util/spinlock.h diff --git a/sdrbase/util/sdrangelserverlist.cpp b/sdrbase/util/sdrangelserverlist.cpp index 7a3bf8933..eed5e9cd6 100644 --- a/sdrbase/util/sdrangelserverlist.cpp +++ b/sdrbase/util/sdrangelserverlist.cpp @@ -114,6 +114,9 @@ void SDRangelServerList::handleJSON(const QString& url, const QByteArray& bytes) if (serverObj.contains(QStringLiteral("port"))) { sdr.m_port = serverObj.value(QStringLiteral("port")).toInt(); } + if (serverObj.contains(QStringLiteral("protocol"))) { + sdr.m_protocol = serverObj.value(QStringLiteral("protocol")).toString(); + } if (serverObj.contains(QStringLiteral("minFrequency"))) { sdr.m_minFrequency = serverObj.value(QStringLiteral("minFrequency")).toInt(); } diff --git a/sdrbase/util/sdrangelserverlist.h b/sdrbase/util/sdrangelserverlist.h index e563e1338..9cb08b483 100644 --- a/sdrbase/util/sdrangelserverlist.h +++ b/sdrbase/util/sdrangelserverlist.h @@ -37,6 +37,7 @@ public: struct SDRangelServer { QString m_address; quint16 m_port; + QString m_protocol; qint64 m_minFrequency; qint64 m_maxFrequency; int m_maxSampleRate; diff --git a/plugins/channelrx/remotetcpsink/socket.cpp b/sdrbase/util/socket.cpp similarity index 85% rename from plugins/channelrx/remotetcpsink/socket.cpp rename to sdrbase/util/socket.cpp index 694f2503f..300a04e6f 100644 --- a/plugins/channelrx/remotetcpsink/socket.cpp +++ b/sdrbase/util/socket.cpp @@ -49,6 +49,13 @@ qint64 TCPSocket::read(char *data, qint64 length) return socket->read(data, length); } +QByteArray TCPSocket::readAll() +{ + QTcpSocket *socket = qobject_cast(m_socket); + + return socket->readAll(); +} + void TCPSocket::close() { QTcpSocket *socket = qobject_cast(m_socket); @@ -84,6 +91,13 @@ quint16 TCPSocket::peerPort() return socket->peerPort(); } +bool TCPSocket::isConnected() +{ + QTcpSocket *socket = qobject_cast(m_socket); + + return socket->state() == QAbstractSocket::ConnectedState; +} + WebSocket::WebSocket(QWebSocket *socket) : Socket(socket) { @@ -126,11 +140,23 @@ qint64 WebSocket::read(char *data, qint64 length) return length; } +QByteArray WebSocket::readAll() +{ + QByteArray b = m_rxBuffer; + + m_rxBuffer.clear(); + + return b; +} + void WebSocket::close() { QWebSocket *socket = qobject_cast(m_socket); - socket->close(); + // Will crash if we call close on unopened socket + if (socket->state() != QAbstractSocket::UnconnectedState) { + socket->close(); + } } qint64 WebSocket::bytesAvailable() @@ -158,3 +184,10 @@ quint16 WebSocket::peerPort() return socket->peerPort(); } + +bool WebSocket::isConnected() +{ + QWebSocket *socket = qobject_cast(m_socket); + + return socket->state() == QAbstractSocket::ConnectedState; +} diff --git a/plugins/channelrx/remotetcpsink/socket.h b/sdrbase/util/socket.h similarity index 88% rename from plugins/channelrx/remotetcpsink/socket.h rename to sdrbase/util/socket.h index 48ddc3540..4e15b6d8b 100644 --- a/plugins/channelrx/remotetcpsink/socket.h +++ b/sdrbase/util/socket.h @@ -21,8 +21,10 @@ #include #include +#include "export.h" + // Class to allow easy use of either QTCPSocket or QWebSocket -class Socket : public QObject { +class SDRBASE_API Socket : public QObject { Q_OBJECT protected: Socket(QObject *socket, QObject *parent=nullptr); @@ -33,9 +35,11 @@ public: virtual void flush() = 0; virtual qint64 read(char *data, qint64 length) = 0; virtual qint64 bytesAvailable() = 0; + virtual QByteArray readAll() = 0; virtual void close() = 0; virtual QHostAddress peerAddress() = 0; virtual quint16 peerPort() = 0; + virtual bool isConnected() = 0; QObject *socket() { return m_socket; } @@ -45,7 +49,7 @@ protected: }; -class TCPSocket : public Socket { +class SDRBASE_API TCPSocket : public Socket { Q_OBJECT public: @@ -55,13 +59,15 @@ public: void flush() override; qint64 read(char *data, qint64 length) override; qint64 bytesAvailable() override; + QByteArray readAll() override; void close() override; QHostAddress peerAddress() override; quint16 peerPort() override; + bool isConnected() override; }; -class WebSocket : public Socket { +class SDRBASE_API WebSocket : public Socket { Q_OBJECT public: @@ -71,9 +77,11 @@ public: void flush() override; qint64 read(char *data, qint64 length) override; qint64 bytesAvailable() override; + QByteArray readAll() override; void close() override; QHostAddress peerAddress() override; quint16 peerPort() override; + bool isConnected() override; private slots: