Skip to content

Commit

Permalink
Comms: Convert TCP to Signals/Slots
Browse files Browse the repository at this point in the history
  • Loading branch information
HTRamsey committed Aug 19, 2024
1 parent d29ff61 commit 02ad6b6
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 194 deletions.
223 changes: 93 additions & 130 deletions src/Comms/TCPLink.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,196 +9,159 @@

#include "TCPLink.h"
#include "DeviceInfo.h"
#include "QGCLoggingCategory.h"

#include <QtCore/QList>
#include <QtNetwork/QTcpSocket>
#include <QtTest/QSignalSpy>

TCPLink::TCPLink(SharedLinkConfigurationPtr& config)
: LinkInterface(config)
, _tcpConfig(qobject_cast<TCPConfiguration*>(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<const TCPConfiguration*>(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);

#ifdef QT_DEBUG
(void) QObject::connect(_socket, &QTcpSocket::stateChanged, this, [](QTcpSocket::SocketState state) {
qCDebug(TCPLinkLog) << "TCP State Changed:" << state;
}, Qt::AutoConnection);
#endif
}

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<size; i++)
{
unsigned char v = data[i];
bytes.append(QString::asprintf("%02x ", v));
if (data[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(_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)
bool TCPLink::isSecureConnection()
{
Q_UNUSED(socketError);
emit communicationError(tr("Link Error"), tr("Error on link %1. Error on socket: %2.").arg(_config->name()).arg(_socket->errorString()));
return QGCDeviceInfo::isNetworkWired();
}

/**
* @brief Check if connection is active.
*
* @return True if link is connected, false otherwise.
**/
bool TCPLink::isConnected() const
////////////////////////////////////////////////////////////////////

TCPConfiguration::TCPConfiguration(const QString &name, QObject *parent)
: LinkConfiguration(name, parent)
{
return _socketIsConnected;
// qCDebug(TCPLinkLog) << Q_FUNC_INFO << this;
}

bool TCPLink::isSecureConnection()
TCPConfiguration::TCPConfiguration(TCPConfiguration *copy, QObject *parent)
: LinkConfiguration(copy, parent)
, _host(copy->host())
, _port(copy->port())
{
return QGCDeviceInfo::isNetworkWired();
}
// 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");
LinkConfiguration::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)
{
Q_CHECK_PTR(source);
LinkConfiguration::copyFrom(source);
auto* usource = qobject_cast<TCPConfiguration*>(source);
Q_ASSERT(usource != nullptr);
_port = usource->port();
_host = usource->host();
}

void TCPConfiguration::setPort(quint16 port)
{
_port = port;
}
const TCPConfiguration* const tcpSource = qobject_cast<const TCPConfiguration*>(source);
Q_CHECK_PTR(tcpSource);

void TCPConfiguration::setHost(const QString host)
{
_host = host;
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<quint16>(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();
}
Loading

0 comments on commit 02ad6b6

Please sign in to comment.