From fb7ad3859a8699ac80589b7098deadc1a99028f6 Mon Sep 17 00:00:00 2001 From: Holden Date: Tue, 4 Jun 2024 00:15:46 -0400 Subject: [PATCH] Comms: Convert TCP to Signals/Slots --- src/Comms/LinkConfiguration.cc | 2 - src/Comms/TCPLink.cc | 228 +++++++++++++++------------------ src/Comms/TCPLink.h | 104 ++++++--------- 3 files changed, 142 insertions(+), 192 deletions(-) diff --git a/src/Comms/LinkConfiguration.cc b/src/Comms/LinkConfiguration.cc index d0724a13c9ff..dc9dec68d9a9 100644 --- a/src/Comms/LinkConfiguration.cc +++ b/src/Comms/LinkConfiguration.cc @@ -41,8 +41,6 @@ LinkConfiguration::LinkConfiguration(LinkConfiguration *copy, QObject *parent) { // qCDebug(AudioOutputLog) << Q_FUNC_INFO << this; - LinkConfiguration::copyFrom(copy); - Q_ASSERT(!m_name.isEmpty()); } diff --git a/src/Comms/TCPLink.cc b/src/Comms/TCPLink.cc index 6731f94d47d5..1017a6f07bea 100644 --- a/src/Comms/TCPLink.cc +++ b/src/Comms/TCPLink.cc @@ -9,190 +9,168 @@ #include "TCPLink.h" -#include +#include + #include -#include -TCPLink::TCPLink(SharedLinkConfigurationPtr& config) - : LinkInterface(config) - , _tcpConfig(qobject_cast(config.get())) - , _socket(nullptr) - , _socketIsConnected(false) +QGC_LOGGING_CATEGORY(TCPLinkLog, "qgc.comms.tcplink") + +TCPLink::TCPLink(SharedLinkConfigurationPtr &config, QObject *parent) + : LinkInterface(config, parent) + , _tcpConfig(qobject_cast(config.get())) + , _socket(new QTcpSocket(this)) { - Q_ASSERT(_tcpConfig); + // qCDebug(TCPLinkLog) << Q_FUNC_INFO << this; + + (void) QObject::connect(_socket, &QTcpSocket::connected, this, &TCPLink::connected, Qt::AutoConnection); + (void) QObject::connect(_socket, &QTcpSocket::disconnected, this, &TCPLink::disconnected, Qt::AutoConnection); + + (void) QObject::connect(_socket, &QTcpSocket::errorOccurred, this, [this](QTcpSocket::SocketError error) { + qCWarning(TCPLinkLog) << "TCP Link Error:" << error << _socket->errorString(); + emit communicationError(QStringLiteral("TCP Link Error"), QStringLiteral("Link: %1, %2.").arg(_tcpConfig->name(), _socket->errorString())); + }, Qt::AutoConnection); + + (void) QObject::connect(_socket, &QTcpSocket::stateChanged, this, [](QTcpSocket::SocketState state) { + qCDebug(TCPLinkLog) << "TCP State Changed:" << state; + }, Qt::AutoConnection); } TCPLink::~TCPLink() { - disconnect(); + TCPLink::disconnect(); + + // qCDebug(TCPLinkLog) << Q_FUNC_INFO << this; } -#ifdef TCPLINK_READWRITE_DEBUG -void TCPLink::_writeDebugBytes(const QByteArray data) +bool TCPLink::isConnected() const { - QString bytes; - QString ascii; - for (int i=0, size = data.size(); i 31 && data[i] < 127) - { - ascii.append(data[i]); - } - else - { - ascii.append(219); - } - } - qDebug() << "Sent" << size << "bytes to" << _tcpConfig->host() << ":" << _tcpConfig->port() << "data:"; - qDebug() << bytes; - qDebug() << "ASCII:" << ascii; + return ((_socket->state() != QAbstractSocket::SocketState::ConnectedState) && (_socket->state() != QAbstractSocket::SocketState::ConnectingState));; } -#endif -void TCPLink::_writeBytes(const QByteArray &data) +void TCPLink::disconnect() { -#ifdef TCPLINK_READWRITE_DEBUG - _writeDebugBytes(data); -#endif - - if (_socket) { - _socket->write(data); - emit bytesSent(this, data); - } + (void) QObject::disconnect(_socket, &QTcpSocket::readyRead, this, &TCPLink::_readBytes); + _socket->disconnectFromHost(); } -void TCPLink::_readBytes() +bool TCPLink::_connect() { - if (_socket) { - qint64 byteCount = _socket->bytesAvailable(); - if (byteCount) - { - QByteArray buffer; - buffer.resize(byteCount); - _socket->read(buffer.data(), buffer.size()); - emit bytesReceived(this, buffer); -#ifdef TCPLINK_READWRITE_DEBUG - writeDebugBytes(buffer.data(), buffer.size()); -#endif - } + if (isConnected()) { + return true; } + + (void) QObject::connect(_socket, &QTcpSocket::readyRead, this, &TCPLink::_readBytes, Qt::AutoConnection); + _socket->connectToHost(_tcpConfig->host(), _tcpConfig->port()); + + return true; } -void TCPLink::disconnect(void) +void TCPLink::_writeBytes(const QByteArray &bytes) { - if (_socket) { - // This prevents stale signal from calling the link after it has been deleted - QObject::disconnect(_socket, &QIODevice::readyRead, this, &TCPLink::_readBytes); - _socketIsConnected = false; - _socket->disconnectFromHost(); // Disconnect tcp - _socket->deleteLater(); // Make sure delete happens on correct thread - _socket = nullptr; - emit disconnected(); + if (!isConnected()) { + emit communicationError(QStringLiteral("TCP Link Error"), QStringLiteral("Link %1: %2.").arg(_tcpConfig->name(), QStringLiteral("Could Not Send Data - Link is Disconnected!"))); + return; } -} -bool TCPLink::_connect(void) -{ - if (_socket) { - qWarning() << "connect called while already connected"; - return true; + if (_socket->write(bytes) < 0) { + emit communicationError(QStringLiteral("TCP Link Error"), QStringLiteral("Link %1: %2.").arg(_tcpConfig->name(), QStringLiteral("Could Not Send Data - Write Failed!"))); + return; } - return _hardwareConnect(); + emit bytesSent(this, bytes); } -bool TCPLink::_hardwareConnect() +void TCPLink::_readBytes() { - Q_ASSERT(_socket == nullptr); - _socket = new QTcpSocket(); - QObject::connect(_socket, &QIODevice::readyRead, this, &TCPLink::_readBytes); - - QSignalSpy errorSpy(_socket, &QAbstractSocket::errorOccurred); - QObject::connect(_socket, &QAbstractSocket::errorOccurred, this, &TCPLink::_socketError); + if (!isConnected()) { + emit communicationError(QStringLiteral("TCP Link Error"), QStringLiteral("Link %1: %2.").arg(_tcpConfig->name(), QStringLiteral("Could Not Read Data - link is Disconnected!"))); + return; + } - _socket->connectToHost(_tcpConfig->host(), _tcpConfig->port()); + const qint64 byteCount = _socket->bytesAvailable(); + if (byteCount <= 0) { + emit communicationError(QStringLiteral("TCP Link Error"), QStringLiteral("Link %1: %2.").arg(_tcpConfig->name(), QStringLiteral("Could Not Read Data - No Data Available!"))); + return; + } - // Give the socket a second to connect to the other side otherwise error out - if (!_socket->waitForConnected(1000)) - { - // Whether a failed connection emits an error signal or not is platform specific. - // So in cases where it is not emitted, we emit one ourselves. - if (errorSpy.count() == 0) { - emit communicationError(tr("Link Error"), tr("Error on link %1. Connection failed").arg(m_config->name())); - } - delete _socket; - _socket = nullptr; - return false; + QByteArray buffer(byteCount, Qt::Initialization::Uninitialized); + if (_socket->read(buffer.data(), buffer.size()) < 0) { + emit communicationError(QStringLiteral("TCP Link Error"), QStringLiteral("Link %1: %2.").arg(_tcpConfig->name(), QStringLiteral("Could Not Read Data - Read Failed!"))); + return; } - _socketIsConnected = true; - emit connected(); - return true; + + emit bytesReceived(this, buffer); } -void TCPLink::_socketError(QAbstractSocket::SocketError socketError) +//////////////////////////////////////////////////////////////////// + +TCPConfiguration::TCPConfiguration(const QString &name, QObject *parent) + : LinkConfiguration(name, parent) { - Q_UNUSED(socketError); - emit communicationError(tr("Link Error"), tr("Error on link %1. Error on socket: %2.").arg(m_config->name()).arg(_socket->errorString())); + // qCDebug(TCPLinkLog) << Q_FUNC_INFO << this; } -/** - * @brief Check if connection is active. - * - * @return True if link is connected, false otherwise. - **/ -bool TCPLink::isConnected() const +TCPConfiguration::TCPConfiguration(TCPConfiguration *copy, QObject *parent) + : LinkConfiguration(copy, parent) + , _host(copy->host()) + , _port(copy->port()) { - return _socketIsConnected; -} + // qCDebug(TCPLinkLog) << Q_FUNC_INFO << this; -//-------------------------------------------------------------------------- -//-- TCPConfiguration + Q_CHECK_PTR(copy); -TCPConfiguration::TCPConfiguration(const QString& name) : LinkConfiguration(name) -{ - _port = QGC_TCP_PORT; - _host = QLatin1String("0.0.0.0"); + TCPConfiguration::copyFrom(copy); } -TCPConfiguration::TCPConfiguration(TCPConfiguration* source) : LinkConfiguration(source) +TCPConfiguration::~TCPConfiguration() { - _port = source->port(); - _host = source->host(); + // qCDebug(TCPLinkLog) << Q_FUNC_INFO << this; } -void TCPConfiguration::copyFrom(LinkConfiguration *source) +void TCPConfiguration::setHost(const QString &host) { - LinkConfiguration::copyFrom(source); - auto* usource = qobject_cast(source); - Q_ASSERT(usource != nullptr); - _port = usource->port(); - _host = usource->host(); + if (host != _host.toString()) { + _host.setAddress(host); + emit hostChanged(); + } } void TCPConfiguration::setPort(quint16 port) { - _port = port; + if (port != _port) { + _port = port; + emit portChanged(); + } } -void TCPConfiguration::setHost(const QString host) +void TCPConfiguration::copyFrom(LinkConfiguration *source) { - _host = host; + Q_CHECK_PTR(source); + LinkConfiguration::copyFrom(source); + + const TCPConfiguration* const tcpSource = qobject_cast(source); + Q_CHECK_PTR(tcpSource); + + setHost(tcpSource->host()); + setPort(tcpSource->port()); } -void TCPConfiguration::saveSettings(QSettings& settings, const QString& root) +void TCPConfiguration::loadSettings(QSettings &settings, const QString &root) { settings.beginGroup(root); - settings.setValue("port", (int)_port); - settings.setValue("host", _host); + + setHost(settings.value("host", host()).toString()); + setPort(static_cast(settings.value("port", port()).toUInt())); + settings.endGroup(); } -void TCPConfiguration::loadSettings(QSettings& settings, const QString& root) +void TCPConfiguration::saveSettings(QSettings &settings, const QString &root) { settings.beginGroup(root); - _port = (quint16)settings.value("port", QGC_TCP_PORT).toUInt(); - _host = settings.value("host", _host).toString(); + + settings.setValue("host", host()); + settings.setValue("port", port()); + settings.endGroup(); } diff --git a/src/Comms/TCPLink.h b/src/Comms/TCPLink.h index b5ee942c4bc9..213aaa7365fa 100644 --- a/src/Comms/TCPLink.h +++ b/src/Comms/TCPLink.h @@ -9,98 +9,72 @@ #pragma once - -#include "LinkInterface.h" -#include "LinkConfiguration.h" - +#include +#include #include -#include -#include +#include -//#define TCPLINK_READWRITE_DEBUG // Use to debug data reads/writes +#include "LinkConfiguration.h" +#include "LinkInterface.h" -class TCPLinkTest; -class LinkManager; class QTcpSocket; -#define QGC_TCP_PORT 5760 +Q_DECLARE_LOGGING_CATEGORY(TCPLinkLog) class TCPConfiguration : public LinkConfiguration { Q_OBJECT -public: - - Q_PROPERTY(quint16 port READ port WRITE setPort NOTIFY portChanged) Q_PROPERTY(QString host READ host WRITE setHost NOTIFY hostChanged) + Q_PROPERTY(quint16 port READ port WRITE setPort NOTIFY portChanged) - TCPConfiguration(const QString& name); - TCPConfiguration(TCPConfiguration* source); - - quint16 port (void) const { return _port; } - QString host (void) const { return _host; } - void setPort (quint16 port); - void setHost (const QString host); - - //LinkConfiguration overrides - LinkType type (void) override { return LinkConfiguration::TypeTcp; } - void copyFrom (LinkConfiguration* source) override; - void loadSettings (QSettings& settings, const QString& root) override; - void saveSettings (QSettings& settings, const QString& root) override; - QString settingsURL (void) override { return "TcpSettings.qml"; } - QString settingsTitle (void) override { return tr("TCP Link Settings"); } +public: + explicit TCPConfiguration(const QString &name, QObject *parent = nullptr); + explicit TCPConfiguration(TCPConfiguration *copy, QObject *parent = nullptr); + virtual ~TCPConfiguration(); + + QString host() const { return _host.toString(); } + void setHost(const QString &host); + quint16 port() const { return _port; } + void setPort(quint16 port); + + LinkType type() override { return LinkConfiguration::TypeTcp; } + void copyFrom(LinkConfiguration *source) override; + void loadSettings(QSettings &settings, const QString &root) override; + void saveSettings(QSettings &settings, const QString &root) override; + QString settingsURL() override { return QStringLiteral("TcpSettings.qml"); } + QString settingsTitle() override { return QStringLiteral("TCP Link Settings"); } signals: - void portChanged(void); - void hostChanged(void); + void hostChanged(); + void portChanged(); private: - QString _host; - quint16 _port; + QHostAddress _host; + quint16 _port = 5760; }; +//////////////////////////////////////////////////////////////////// + class TCPLink : public LinkInterface { Q_OBJECT public: - TCPLink(SharedLinkConfigurationPtr& config); + explicit TCPLink(SharedLinkConfigurationPtr &config, QObject *parent = nullptr); virtual ~TCPLink(); - QTcpSocket* getSocket (void) { return _socket; } - void signalBytesWritten (void); - - // LinkInterface overrides - bool isConnected(void) const override; - void disconnect (void) override; + void run() override {}; + bool isConnected() const override; + void disconnect() override; private slots: - void _socketError (QAbstractSocket::SocketError socketError); - void _readBytes (void); - - // LinkInterface overrides - void _writeBytes(const QByteArray &data) override; + void _writeBytes(const QByteArray &bytes) override; + void _readBytes(); private: - // LinkInterface overrides - bool _connect(void) override; - - bool _hardwareConnect (void); -#ifdef TCPLINK_READWRITE_DEBUG - void _writeDebugBytes (const QByteArray data); -#endif - - TCPConfiguration* _tcpConfig; - QTcpSocket* _socket; - bool _socketIsConnected; - - quint64 _bitsSentTotal; - quint64 _bitsSentCurrent; - quint64 _bitsSentMax; - quint64 _bitsReceivedTotal; - quint64 _bitsReceivedCurrent; - quint64 _bitsReceivedMax; - quint64 _connectionStartTime; - QMutex _statisticsMutex; -}; + bool _connect() override; + const TCPConfiguration *_tcpConfig = nullptr; + QTcpSocket *_socket = nullptr; +};