From 330f9e23323f9c854b5968fc1068fb122f351f11 Mon Sep 17 00:00:00 2001 From: nymea Date: Tue, 13 Aug 2019 17:02:50 +0200 Subject: [PATCH 1/2] Refactured the tcp output, extended Readme --- tcpcommander/README.md | 33 ++++- tcpcommander/deviceplugintcpcommander.cpp | 137 +++++++-------------- tcpcommander/deviceplugintcpcommander.h | 17 ++- tcpcommander/deviceplugintcpcommander.json | 46 ++----- tcpcommander/tcpcommander.pro | 3 +- tcpcommander/tcpserver.cpp | 27 ++-- tcpcommander/tcpserver.h | 18 +-- tcpcommander/tcpsocket.cpp | 93 ++++++++++++++ tcpcommander/tcpsocket.h | 39 ++++++ 9 files changed, 253 insertions(+), 160 deletions(-) create mode 100644 tcpcommander/tcpsocket.cpp create mode 100644 tcpcommander/tcpsocket.h diff --git a/tcpcommander/README.md b/tcpcommander/README.md index 033f8eb7..aca4a88d 100644 --- a/tcpcommander/README.md +++ b/tcpcommander/README.md @@ -1,3 +1,34 @@ # TCP commander -This plugin is a generic approach to allow sending and receiving custom TCP packages in a network. +This plugin is a generic approach to allow sending and receiving custom TCP packages. + +> Note: This plugin is ment to be combined with a rule. + +## TCP output + +The TCP output opens a TCP connection to the given host IPv4 address and port everytime the output trigger gets activated. As soon +as the command has been executed the socket will close again. The connected state is only stated as connected +as long as the connection is active. + +## TCP input + +The TCP input creates a TCP server on the given port. + +Be aware that only a single connection can be established simultaneously. The connected state is active as long as +a client is connected. It is up to the client to deside how long the connection stays active. + +## Example + +If you create a TCP Input on port 2323 and with the command `"Light 1 ON"`, following command will trigger an event in nymea and allows you to connect this event with a rule. + +> Note: In this example nymea is running on `localhost` + + $ echo "Light 1 ON" | nc localhost 2323 + OK + +If you create a TCP output on port 2324 and IP address 127.0.0.1, send in nymea the command `"Light 1 is ON"` and Netcat (nc) will receive and display your command. + +> Note: the command is running on `localhost` + + $ while :; do nc -l -p 2324; sleep 1; done + Light 1 is ON diff --git a/tcpcommander/deviceplugintcpcommander.cpp b/tcpcommander/deviceplugintcpcommander.cpp index e420a40a..5177079a 100644 --- a/tcpcommander/deviceplugintcpcommander.cpp +++ b/tcpcommander/deviceplugintcpcommander.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2017 Bernhard Trinnes * + * Copyright (C) 2019 Bernhard Trinnes * * * * This file is part of nymea. * * * @@ -26,14 +26,27 @@ DevicePluginTcpCommander::DevicePluginTcpCommander() { } + Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device) { if (device->deviceClassId() == tcpOutputDeviceClassId) { - QTcpSocket *tcpSocket = new QTcpSocket(this); + + quint16 port = device->paramValue(tcpOutputDevicePortParamTypeId).toUInt(); + QHostAddress address= QHostAddress(device->paramValue(tcpOutputDeviceIpv4addressParamTypeId).toString()); + TcpSocket *tcpSocket = new TcpSocket(address, port, this); m_tcpSockets.insert(tcpSocket, device); - connect(tcpSocket, &QTcpSocket::connected, this, &DevicePluginTcpCommander::onTcpSocketConnected); - connect(tcpSocket, &QTcpSocket::disconnected, this, &DevicePluginTcpCommander::onTcpSocketDisconnected); - connect(tcpSocket, &QTcpSocket::bytesWritten, this, &DevicePluginTcpCommander::onTcpSocketBytesWritten); + connect(tcpSocket, &TcpSocket::connectionChanged, this, &DevicePluginTcpCommander::onTcpSocketConnectionChanged); + connect(tcpSocket, &TcpSocket::commandSent, this, &DevicePluginTcpCommander::onTcpSocketCommandSent); + connect(tcpSocket, &TcpSocket::connectionTestFinished, this, [this, device] (bool status) { + + if (status) { + emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess); + } else { + emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure); + } + }); + tcpSocket->connectionTest(); + // Test the socket, if a socket can be established the setup process was successfull return Device::DeviceSetupStatusAsync; } @@ -43,8 +56,8 @@ Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device) if (tcpServer->isValid()) { m_tcpServer.insert(tcpServer, device); - connect(tcpServer, &TcpServer::connected, this, &DevicePluginTcpCommander::onTcpServerConnected); - connect(tcpServer, &TcpServer::disconnected, this, &DevicePluginTcpCommander::onTcpServerDisconnected); + connect(tcpServer, &TcpServer::connectionChanged, this, &DevicePluginTcpCommander::onTcpServerConnectionChanged); + connect(tcpServer, &TcpServer::commandReceived, this, &DevicePluginTcpCommander::onTcpServerCommandReceived); return Device::DeviceSetupStatusSuccess; } else { tcpServer->deleteLater(); @@ -60,11 +73,11 @@ Device::DeviceError DevicePluginTcpCommander::executeAction(Device *device, cons if (device->deviceClassId() == tcpOutputDeviceClassId) { if (action.actionTypeId() == tcpOutputTriggerActionTypeId) { - int port = device->paramValue(tcpOutputDevicePortParamTypeId).toInt(); - QHostAddress address= QHostAddress(device->paramValue(tcpOutputDeviceIpv4addressParamTypeId).toString()); - QTcpSocket *tcpSocket = m_tcpSockets.key(device); - tcpSocket->connectToHost(address, port); - return Device::DeviceErrorNoError; + TcpSocket *tcpSocket = m_tcpSockets.key(device); + QByteArray data = action.param(tcpOutputTriggerActionOutputDataAreaParamTypeId).value().toByteArray(); + tcpSocket->sendCommand(data); + m_pendingActions.insert(action.id(), device->id()); + return Device::DeviceErrorAsync; } return Device::DeviceErrorActionTypeNotFound; } @@ -76,11 +89,11 @@ void DevicePluginTcpCommander::deviceRemoved(Device *device) { if(device->deviceClassId() == tcpOutputDeviceClassId){ - QTcpSocket *tcpSocket = m_tcpSockets.key(device); + TcpSocket *tcpSocket = m_tcpSockets.key(device); m_tcpSockets.remove(tcpSocket); tcpSocket->deleteLater(); - }else if(device->deviceClassId() == tcpInputDeviceClassId){ + } else if(device->deviceClassId() == tcpInputDeviceClassId){ TcpServer *tcpServer = m_tcpServer.key(device); m_tcpServer.remove(tcpServer); @@ -89,105 +102,49 @@ void DevicePluginTcpCommander::deviceRemoved(Device *device) } -void DevicePluginTcpCommander::onTcpSocketConnected() +void DevicePluginTcpCommander::onTcpSocketConnectionChanged(bool connected) { - QTcpSocket *tcpSocket = static_cast(sender()); + TcpSocket *tcpSocket = static_cast(sender()); Device *device = m_tcpSockets.value(tcpSocket); if (device->deviceClassId() == tcpOutputDeviceClassId) { - if (!device->setupComplete()) { - qDebug(dcTCPCommander()) << device->name() << "Setup finished" ; - emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess); - } else { - QByteArray data = device->paramValue(tcpOutputTriggerActionOutputDataAreaParamTypeId).toByteArray(); - tcpSocket->write(data); - } - device->setStateValue(tcpOutputConnectedStateTypeId, true); - } - if (device->deviceClassId() == tcpInputDeviceClassId) { - if (!device->setupComplete()) { - qDebug(dcTCPCommander()) << device->name() << "Setup finished" ; - emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess); - } - device->setStateValue(tcpInputConnectedStateTypeId, true); + device->setStateValue(tcpOutputConnectedStateTypeId, connected); } } - -void DevicePluginTcpCommander::onTcpSocketDisconnected() +void DevicePluginTcpCommander::onTcpSocketCommandSent(bool successfull) { - QTcpSocket *tcpSocket = static_cast(sender()); + TcpSocket *tcpSocket = static_cast(sender()); Device *device = m_tcpSockets.value(tcpSocket); - if (device->deviceClassId() == tcpInputDeviceClassId) { - device->setStateValue(tcpInputConnectedStateTypeId, false); - } else if (device->deviceClassId() == tcpOutputDeviceClassId) { - device->setStateValue(tcpOutputConnectedStateTypeId, false); + + ActionId action = m_pendingActions.key(device->id()); + m_pendingActions.remove(action); + if (successfull) { + emit actionExecutionFinished(action, Device::DeviceErrorNoError); + } else { + emit actionExecutionFinished(action, Device::DeviceErrorHardwareNotAvailable); } } -void DevicePluginTcpCommander::onTcpSocketBytesWritten() -{ - QTcpSocket *tcpSocket = static_cast(sender()); - tcpSocket->close(); -} - -void DevicePluginTcpCommander::onTcpServerConnected() +void DevicePluginTcpCommander::onTcpServerConnectionChanged(bool connected) { TcpServer *tcpServer = static_cast(sender()); Device *device = m_tcpServer.value(tcpServer); qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client connected" ; if (device->deviceClassId() == tcpInputDeviceClassId) { - device->setStateValue(tcpInputConnectedStateTypeId, true); - } else if (device->deviceClassId() == tcpOutputDeviceClassId) { - device->setStateValue(tcpOutputConnectedStateTypeId, true); - } - - connect(tcpServer, &TcpServer::textMessageReceived, this, &DevicePluginTcpCommander::onTcpServerTextMessageReceived); - //send signal device Setup was successful -} - - -void DevicePluginTcpCommander::onTcpServerDisconnected() -{ - TcpServer *tcpServer = static_cast(sender()); - Device *device = m_tcpServer.value(tcpServer); - qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client disconnected" ; - if (device->deviceClassId() == tcpInputDeviceClassId) { - device->setStateValue(tcpInputConnectedStateTypeId, false); - } else if (device->deviceClassId() == tcpOutputDeviceClassId) { - device->setStateValue(tcpOutputConnectedStateTypeId, false); + device->setStateValue(tcpInputConnectedStateTypeId, connected); } } -void DevicePluginTcpCommander::onTcpServerTextMessageReceived(QByteArray data) +void DevicePluginTcpCommander::onTcpServerCommandReceived(QByteArray data) { TcpServer *tcpServer = static_cast(sender()); Device *device = m_tcpServer.value(tcpServer); qDebug(dcTCPCommander()) << device->name() << "Message received" << data; - device->setStateValue(tcpInputDataReceivedStateTypeId, data); - if (device->paramValue(tcpInputDeviceComparisionParamTypeId).toString() == "Is exactly") { - qDebug(dcTCPCommander()) << "is exactly"; - if (data == device->paramValue(tcpInputDeviceInputDataParamTypeId)) { - qDebug(dcTCPCommander()) << "comparison successful"; - emitEvent(Event(tcpInputTriggeredEventTypeId, device->id())); - } - - } else if (device->paramValue(tcpInputDeviceComparisionParamTypeId).toString() == "Contains") { - if (data.contains(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray())) { - emitEvent(Event(tcpInputTriggeredEventTypeId, device->id())); - } - - } else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Contains not") { - if (!data.contains(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray())) - emitEvent(Event(tcpInputTriggeredEventTypeId, device->id())); - - } else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Starts with") { - if (data.startsWith(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray())) - emitEvent(Event(tcpInputTriggeredEventTypeId, device->id())); - - } else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Ends with") { - if (data.endsWith(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray())) - emitEvent(Event(tcpInputTriggeredEventTypeId, device->id())); - } + Event event = Event(tcpInputTriggeredEventTypeId, device->id()); + ParamList params; + params.append(Param(tcpInputTriggeredEventDataParamTypeId, data)); + event.setParams(params); + emitEvent(event); } diff --git a/tcpcommander/deviceplugintcpcommander.h b/tcpcommander/deviceplugintcpcommander.h index d189b0d7..addc713c 100644 --- a/tcpcommander/deviceplugintcpcommander.h +++ b/tcpcommander/deviceplugintcpcommander.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2017 Bernhard Trinnes * + * Copyright (C) 2019 Bernhard Trinnes * * * * This file is part of nymea. * * * @@ -23,6 +23,7 @@ #include "devices/deviceplugin.h" #include "tcpserver.h" +#include "tcpsocket.h" class DevicePluginTcpCommander : public DevicePlugin { @@ -41,18 +42,16 @@ public: Device::DeviceError executeAction(Device *device, const Action &action) override; private: - QHash m_tcpSockets; + QHash m_tcpSockets; QHash m_tcpServer; + QHash m_pendingActions; private slots: - void onTcpSocketConnected(); - void onTcpSocketDisconnected(); - void onTcpSocketBytesWritten(); - - void onTcpServerConnected(); - void onTcpServerDisconnected(); - void onTcpServerTextMessageReceived(QByteArray message); + void onTcpSocketConnectionChanged(bool connected); + void onTcpSocketCommandSent(bool successfulle); + void onTcpServerConnectionChanged(bool connected); + void onTcpServerCommandReceived(QByteArray message); }; #endif // DEVICEPLUGINTCPCOMMANDER_H diff --git a/tcpcommander/deviceplugintcpcommander.json b/tcpcommander/deviceplugintcpcommander.json index 8648c8e9..de37a53a 100644 --- a/tcpcommander/deviceplugintcpcommander.json +++ b/tcpcommander/deviceplugintcpcommander.json @@ -4,9 +4,9 @@ "id": "741b7b0a-0c9c-4c93-be99-0d0bcf5a4643", "vendors": [ { - "name": "tcpCommander", - "displayName": "TCP Commander", - "id": "9181278e-7812-4a3e-a9ce-f00f3f8b8afd", + "name": "nymea", + "displayName": "nymea", + "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6", "deviceClasses": [ { "id": "c67d059f-694f-47cb-8e1d-9e3e6d014c1a", @@ -35,10 +35,10 @@ { "id": "725b541a-9e0c-4634-81eb-e415c0b8f025", "name": "connected", - "displayName": "connected", + "displayName": "Connected", "type": "bool", "defaultValue": false, - "displayNameEvent": "connection status changed" + "displayNameEvent": "Connection status changed" } ], "actionTypes": [ @@ -71,53 +71,23 @@ "displayName": "Port", "type": "int", "defaultValue": "22" - }, - { - "id": "d99f55c7-0e14-45ee-b0f0-33f2d1d2e674", - "name": "comparision", - "displayName": "Data Comparison", - "type": "QString", - "allowedValues": [ - "Is exactly", - "Contains", - "Contains not", - "Starts with", - "Ends with" - ], - "defaultValue": "Exactly" - }, - { - "id": "23051bdf-3f50-41fa-abde-bc4fe0bcc4fc", - "name": "inputData", - "displayName": "Command", - "type": "QString", - "inputType": "TextArea", - "defaultValue": "" } ], "stateTypes": [ { "id": "a2eb1619-261c-45ee-9587-6b5994633ad0", "name": "connected", - "displayName": "connected", + "displayName": "Connected", "type": "bool", "defaultValue": false, - "displayNameEvent": "connection status changed" - }, - { - "id": "b98fdacc-59d7-41c4-b790-1fdca50dfb22", - "name": "dataReceived", - "displayName": "Data Received", - "type": "QString", - "defaultValue": "", - "displayNameEvent": "Data received" + "displayNameEvent": "Connection status changed" } ], "eventTypes": [ { "id": "6d7c6df6-cb61-4d9e-b0d7-37c43911ca4b", "name": "triggered", - "displayName": "Command Received", + "displayName": "Data recieved", "paramTypes": [ { "id": "97d7ee8c-d9db-40b4-9855-4ceecd64c411", diff --git a/tcpcommander/tcpcommander.pro b/tcpcommander/tcpcommander.pro index 2a37d360..19e7d2b4 100644 --- a/tcpcommander/tcpcommander.pro +++ b/tcpcommander/tcpcommander.pro @@ -7,8 +7,9 @@ TARGET = $$qtLibraryTarget(nymea_deviceplugintcpcommander) SOURCES += \ deviceplugintcpcommander.cpp \ tcpserver.cpp \ + tcpsocket.cpp HEADERS += \ deviceplugintcpcommander.h \ tcpserver.h \ - + tcpsocket.h diff --git a/tcpcommander/tcpserver.cpp b/tcpcommander/tcpserver.cpp index 20399ec3..017a9f07 100644 --- a/tcpcommander/tcpserver.cpp +++ b/tcpcommander/tcpserver.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2017 Bernhard Trinnes * + * Copyright (C) 2019 Bernhard Trinnes * * * * This file is part of nymea. * * * @@ -23,28 +23,27 @@ #include -TcpServer::TcpServer(const QHostAddress address, const int &port, QObject *parent) : +TcpServer::TcpServer(const QHostAddress address, const quint16 &port, QObject *parent) : QObject(parent) { m_tcpServer = new QTcpServer(this); connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection); qDebug(dcTCPCommander()) << "TCP Server on Port: " << port << "Address: " << address.toString(); if (!m_tcpServer->listen(address, port)) { - qDebug(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString(); + qWarning(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString(); return; } } -TcpServer::TcpServer(const int &port, QObject *parent) : +TcpServer::TcpServer(const quint16 &port, QObject *parent) : QObject(parent) { - m_tcpServer = new QTcpServer(this); connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection); qDebug(dcTCPCommander()) << "TCP Server on Port: " << port; if (!m_tcpServer->listen(QHostAddress::Any, port)) { - qDebug(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString(); + qWarning(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString(); return; } } @@ -72,14 +71,13 @@ void TcpServer::newConnection() { qDebug(dcTCPCommander()) << "TCP Server new Connection request"; m_socket = m_tcpServer->nextPendingConnection(); - m_socket->write("Hello client"); m_socket->flush(); - emit connected(); + emit connectionChanged(true); connect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected); connect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData); // Note: error signal will be interpreted as function, not as signal in C++11 - //connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); + connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); } @@ -89,13 +87,18 @@ void TcpServer::onDisconnected() disconnect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected); disconnect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData); m_socket->deleteLater(); - emit disconnected(); + emit connectionChanged(false); } void TcpServer::readData() { QByteArray data = m_socket->readAll(); qDebug(dcTCPCommander()) << "TCP Server data received: " << data; - emit textMessageReceived(data); - + m_socket->write("OK\n"); + emit commandReceived(data); +} + +void TcpServer::onError(QAbstractSocket::SocketError error) +{ + qWarning(dcTCPCommander()) << "Socket Error" << m_socket->errorString() << error; } diff --git a/tcpcommander/tcpserver.h b/tcpcommander/tcpserver.h index 9d8a3af5..2deec527 100644 --- a/tcpcommander/tcpserver.h +++ b/tcpcommander/tcpserver.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2017 Bernhard Trinnes * + * Copyright (C) 2019 Bernhard Trinnes * * * * This file is part of nymea. * * * @@ -29,8 +29,8 @@ class TcpServer : public QObject { Q_OBJECT public: - explicit TcpServer(const QHostAddress address, const int &port, QObject *parent); - explicit TcpServer(const int &port, QObject *parent = 0); + explicit TcpServer(const QHostAddress address, const quint16 &port, QObject *parent = nullptr); + explicit TcpServer(const quint16 &port, QObject *parent = nullptr); ~TcpServer(); bool isValid(); @@ -42,19 +42,19 @@ public: private: - QTcpServer *m_tcpServer; - QTcpSocket *m_socket; + QTcpServer *m_tcpServer = nullptr; + QTcpSocket *m_socket = nullptr; signals: void newPendingConnection(); - void textMessageReceived(QByteArray message); - void connected(); - void disconnected(); + void commandReceived(QByteArray message); + void connectionChanged(bool connected); -public slots: +private slots: void newConnection(); void onDisconnected(); void readData(); + void onError(QAbstractSocket::SocketError error); }; #endif // TCPSERVER_H diff --git a/tcpcommander/tcpsocket.cpp b/tcpcommander/tcpsocket.cpp new file mode 100644 index 00000000..ffe967f5 --- /dev/null +++ b/tcpcommander/tcpsocket.cpp @@ -0,0 +1,93 @@ +#include "tcpsocket.h" +#include "extern-plugininfo.h" + +TcpSocket::TcpSocket(const QHostAddress address, const quint16 &port, QObject *parent) : + QObject(parent), + m_port(port), + m_address(address) +{ + m_tcpSocket = new QTcpSocket(this); + connect(m_tcpSocket, &QTcpSocket::connected, this, &TcpSocket::onConnected); + connect(m_tcpSocket, &QTcpSocket::disconnected, this, &TcpSocket::onDisconnected); + connect(m_tcpSocket, &QTcpSocket::bytesWritten, this, &TcpSocket::onBytesWritten); + connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onTcpSocketError(QAbstractSocket::SocketError))); +} + +void TcpSocket::sendCommand(QByteArray command) +{ + if (m_pendingCommands.isEmpty()) { + m_pendingCommands.append(command); + m_tcpSocket->abort(); + m_tcpSocket->connectToHost(m_address, m_port); + } else { + m_pendingCommands.append(command); + } +} + +void TcpSocket::connectionTest() +{ + QTcpSocket *testSocket = new QTcpSocket(this); + connect(testSocket, &QTcpSocket::connected, this,[this, testSocket] { + emit connectionTestFinished(true); + testSocket->deleteLater(); + }); + connect(testSocket, QOverload::of(&QAbstractSocket::error), this, [this, testSocket] { + emit connectionTestFinished(false); + testSocket->deleteLater(); + }); + testSocket->connectToHost(m_address, m_port); +} + +void TcpSocket::onConnected() +{ + qDebug(dcTCPCommander()) << "Socket connected" ; + if (!m_pendingCommands.isEmpty()) { + QByteArray data = m_pendingCommands.takeLast(); + qDebug(dcTCPCommander()) << "Writing data:" << data; + m_tcpSocket->write(data + "\n"); + } else { + m_tcpSocket->disconnectFromHost(); + } + emit connectionChanged(true); +} + +void TcpSocket::onDisconnected() +{ + qDebug(dcTCPCommander()) << "Socket disconnected" ; + emit connectionChanged(false); +} + + +void TcpSocket::onBytesWritten() +{ + emit commandSent(true); + if (!m_pendingCommands.isEmpty()){ + m_tcpSocket->write(m_pendingCommands.takeFirst()); + } else { + m_tcpSocket->close(); + } +} + +void TcpSocket::onError(QAbstractSocket::SocketError error) +{ + qWarning(dcTCPCommander()) << "Socket Error" << m_tcpSocket->errorString(); + + switch (error) { + case QAbstractSocket::RemoteHostClosedError: + break; + case QAbstractSocket::HostNotFoundError: + break; + case QAbstractSocket::ConnectionRefusedError: + break; + default: + ; + } + emit commandSent(false); + emit connectionChanged(false); + + m_pendingCommands.clear(); //undefined socket state needs to clear command buffer. + + if (m_tcpSocket->isOpen()) { + m_tcpSocket->disconnectFromHost(); + } +} diff --git a/tcpcommander/tcpsocket.h b/tcpcommander/tcpsocket.h new file mode 100644 index 00000000..9b4cd0b3 --- /dev/null +++ b/tcpcommander/tcpsocket.h @@ -0,0 +1,39 @@ +#ifndef TCPSOCKET_H +#define TCPSOCKET_H + +#include +#include +#include + +class TcpSocket : public QObject +{ + Q_OBJECT +public: + explicit TcpSocket(const QHostAddress address, const quint16 &port, QObject *parent = nullptr); + void sendCommand(QByteArray command); + + void connectionTest(); + +private: + QTcpSocket *m_tcpSocket = nullptr; + + quint16 m_port; + QHostAddress m_address; + + QList m_pendingCommands; + +signals: + void connectionChanged(bool connected); + void commandSent(bool successfull); + void connectionTestFinished(bool successfull); + +private slots: + + void onConnected(); + void onDisconnected(); + void onBytesWritten(); + void onError(QAbstractSocket::SocketError error); + +}; + +#endif // TCPSOCKET_H From 048ec5525013e5e29e463a3a8d3bdd909ae49709 Mon Sep 17 00:00:00 2001 From: nymea Date: Sun, 15 Sep 2019 11:04:14 +0200 Subject: [PATCH 2/2] made it work with Qt 5.6 --- tcpcommander/tcpsocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcpcommander/tcpsocket.cpp b/tcpcommander/tcpsocket.cpp index ffe967f5..f87e7054 100644 --- a/tcpcommander/tcpsocket.cpp +++ b/tcpcommander/tcpsocket.cpp @@ -31,7 +31,7 @@ void TcpSocket::connectionTest() emit connectionTestFinished(true); testSocket->deleteLater(); }); - connect(testSocket, QOverload::of(&QAbstractSocket::error), this, [this, testSocket] { + connect(testSocket, static_cast(&QTcpSocket::error), this, [this, testSocket] { emit connectionTestFinished(false); testSocket->deleteLater(); });