5#include <QtCore/QThread>
6#include <QtCore/QTimer>
7#include <QtNetwork/QHostInfo>
8#include <QtNetwork/QTcpSocket>
13 constexpr int CONNECT_TIMEOUT_MS = 3000;
14 constexpr int TYPE_OF_SERVICE = 32;
22 qCDebug(TCPLinkLog) <<
this;
30 qCDebug(TCPLinkLog) <<
this;
35 qCDebug(TCPLinkLog) <<
this;
40 const QString cleanHost =
host.trimmed();
41 if (cleanHost != _host) {
57 const TCPConfiguration* tcpSource = qobject_cast<const TCPConfiguration*>(source);
59 qCWarning(TCPLinkLog) <<
"Invalid source configuration type";
71 settings.beginGroup(root);
73 setHost(settings.value(QStringLiteral(
"host"),
host()).toString());
74 setPort(
static_cast<quint16
>(settings.value(QStringLiteral(
"port"),
port()).toUInt()));
81 settings.beginGroup(root);
83 settings.setValue(QStringLiteral(
"host"),
host());
84 settings.setValue(QStringLiteral(
"port"),
port());
95 qCDebug(TCPLinkLog) <<
this;
102 qCDebug(TCPLinkLog) <<
this;
114 _socket =
new QTcpSocket(
this);
117 _socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
118 _socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
119 _socket->setSocketOption(QAbstractSocket::TypeOfServiceOption, TYPE_OF_SERVICE);
121 (void) connect(_socket, &QTcpSocket::connected,
this, &TCPWorker::_onSocketConnected);
122 (void) connect(_socket, &QTcpSocket::disconnected,
this, &TCPWorker::_onSocketDisconnected);
123 (void) connect(_socket, &QTcpSocket::readyRead,
this, &TCPWorker::_onSocketReadyRead);
124 (void) connect(_socket, &QTcpSocket::errorOccurred,
this, &TCPWorker::_onSocketErrorOccurred);
126 if (TCPLinkLog().isDebugEnabled()) {
129 (void) connect(_socket, &QTcpSocket::stateChanged,
this, [](QTcpSocket::SocketState state) {
130 qCDebug(TCPLinkLog) <<
"TCP State Changed:" << state;
133 (void) connect(_socket, &QTcpSocket::hostFound,
this, [
this]() {
134 qCDebug(TCPLinkLog) <<
"TCP Host Found" << _socket->peerName() << _socket->peerAddress() << _socket->peerPort();
142 qCWarning(TCPLinkLog) <<
"Already connected to" << _config->
host() <<
":" << _config->
port();
146 if (_config->
host().isEmpty()) {
147 emit
errorOccurred(tr(
"Connection Failed: Host address is empty"));
151 _errorEmitted =
false;
153 qCDebug(TCPLinkLog) <<
"Attempting to connect to host:" << _config->
host() <<
"port:" << _config->
port();
154 _socket->connectToHost(_config->
host(), _config->
port());
156 if (!_socket->waitForConnected(CONNECT_TIMEOUT_MS)) {
157 qCWarning(TCPLinkLog) <<
"Connection to" << _config->
host() <<
":" << _config->
port() <<
"failed:" << _socket->errorString();
159 if (!_errorEmitted.exchange(
true)) {
160 emit
errorOccurred(tr(
"Connection Failed: %1").arg(_socket->errorString()));
163 _onSocketDisconnected();
165 qCDebug(TCPLinkLog) <<
"Successfully connected to host:" << _config->
host() <<
"port:" << _config->
port();
172 qCDebug(TCPLinkLog) <<
"Already disconnected from host:" << _config->
host() <<
"port:" << _config->
port();
176 qCDebug(TCPLinkLog) <<
"Attempting to disconnect from host:" << _config->
host() <<
"port:" << _config->
port();
178 _socket->disconnectFromHost();
180 if (_socket->state() != QAbstractSocket::UnconnectedState) {
181 _socket->waitForDisconnected(1000);
187 if (data.isEmpty()) {
197 qint64 totalBytesWritten = 0;
198 while (totalBytesWritten < data.size()) {
199 const qint64 bytesWritten = _socket->write(data.constData() + totalBytesWritten, data.size() - totalBytesWritten);
200 if (bytesWritten == -1) {
201 emit
errorOccurred(tr(
"Could Not Send Data - Write Failed: %1").arg(_socket->errorString()));
203 }
else if (bytesWritten == 0) {
204 emit
errorOccurred(tr(
"Could Not Send Data - Write Returned 0 Bytes"));
207 totalBytesWritten += bytesWritten;
210 emit
dataSent(data.first(totalBytesWritten));
213void TCPWorker::_onSocketConnected()
215 qCDebug(TCPLinkLog) <<
"Socket connected:" << _config->
host() << _config->
port();
217 _errorEmitted =
false;
221void TCPWorker::_onSocketDisconnected()
223 qCDebug(TCPLinkLog) <<
"Socket disconnected:" << _config->
host() << _config->
port();
224 _isConnected =
false;
225 _errorEmitted =
false;
229void TCPWorker::_onSocketReadyRead()
231 const QByteArray data = _socket->readAll();
232 if (!data.isEmpty()) {
237void TCPWorker::_onSocketBytesWritten(qint64 bytes)
239 qCDebug(TCPLinkLog) << _config->
host() <<
"Wrote" << bytes <<
"bytes";
242void TCPWorker::_onSocketErrorOccurred(QAbstractSocket::SocketError socketError)
244 const QString
errorString = _socket->errorString();
245 qCWarning(TCPLinkLog) <<
"Socket error:" << socketError <<
errorString;
247 if (!_errorEmitted.exchange(
true)) {
258 , _workerThread(new QThread(this))
260 qCDebug(TCPLinkLog) <<
this;
262 _workerThread->setObjectName(QStringLiteral(
"TCP_%1").arg(_tcpConfig->
name()));
264 _worker->moveToThread(_workerThread);
267 (void) connect(_workerThread, &QThread::finished, _worker, &QObject::deleteLater);
269 (void) connect(_worker, &
TCPWorker::connected,
this, &TCPLink::_onConnected, Qt::QueuedConnection);
273 (void) connect(_worker, &
TCPWorker::dataSent,
this, &TCPLink::_onDataSent, Qt::QueuedConnection);
275 _workerThread->start();
284 (void) QMetaObject::invokeMethod(_worker,
"disconnectFromHost", Qt::QueuedConnection);
290 qCDebug(TCPLinkLog) <<
this;
298bool TCPLink::_connect()
300 return QMetaObject::invokeMethod(_worker,
"connectToHost", Qt::QueuedConnection);
306 (void) QMetaObject::invokeMethod(_worker,
"disconnectFromHost", Qt::QueuedConnection);
310void TCPLink::_onConnected()
312 _disconnectedEmitted =
false;
316void TCPLink::_onDisconnected()
318 if (!_disconnectedEmitted.exchange(
true)) {
323void TCPLink::_onErrorOccurred(
const QString &
errorString)
325 qCWarning(TCPLinkLog) <<
"Communication error:" <<
errorString;
329void TCPLink::_onDataReceived(
const QByteArray &data)
334void TCPLink::_onDataSent(
const QByteArray &data)
339void TCPLink::_writeBytes(
const QByteArray& bytes)
341 (void) QMetaObject::invokeMethod(_worker,
"writeData", Qt::QueuedConnection, Q_ARG(QByteArray, bytes));
std::shared_ptr< LinkConfiguration > SharedLinkConfigurationPtr
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Interface holding link specific settings.
virtual void copyFrom(const LinkConfiguration *source)
The link interface defines the interface for all links used to communicate with the ground station ap...
void bytesReceived(LinkInterface *link, const QByteArray &data)
void _shutdownWorkerThread(QThread *thread, const QLoggingCategory &category, bool allowTerminate=true)
void communicationError(const QString &title, const QString &error)
void bytesSent(LinkInterface *link, const QByteArray &data)
~TCPConfiguration() override
void setPort(quint16 port)
void loadSettings(QSettings &settings, const QString &root) override
void setHost(const QString &host)
void saveSettings(QSettings &settings, const QString &root) const override
TCPConfiguration(const QString &name, QObject *parent=nullptr)
void copyFrom(const LinkConfiguration *source) override
bool isConnected() const override
void disconnect() override
bool isSecureConnection() const override
TCPLink(SharedLinkConfigurationPtr &config, QObject *parent=nullptr)
void disconnectFromHost()
void errorOccurred(const QString &errorString)
void dataReceived(const QByteArray &data)
void dataSent(const QByteArray &data)
void writeData(const QByteArray &data)
TCPWorker(const TCPConfiguration *config, QObject *parent=nullptr)
bool isNetworkEthernet()
Check if current network connection is Ethernet.