From df996d611c8f12122452bd0acd367bb40637c624 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 24 May 2021 12:13:28 +0200 Subject: [PATCH] added missing files --- ws2812fx/integrationpluginws2812fx.cpp | 4 +- ws2812fx/nymealight.cpp | 31 ++++--- ws2812fx/nymealighttcpinterface.cpp | 118 +++++++++++++++++++++++++ ws2812fx/nymealighttcpinterface.h | 69 +++++++++++++++ 4 files changed, 204 insertions(+), 18 deletions(-) create mode 100644 ws2812fx/nymealighttcpinterface.cpp create mode 100644 ws2812fx/nymealighttcpinterface.h diff --git a/ws2812fx/integrationpluginws2812fx.cpp b/ws2812fx/integrationpluginws2812fx.cpp index 5451e035..9129da56 100644 --- a/ws2812fx/integrationpluginws2812fx.cpp +++ b/ws2812fx/integrationpluginws2812fx.cpp @@ -89,7 +89,7 @@ void IntegrationPluginWs2812fx::setupThing(ThingSetupInfo *info) info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("This serial port is already in use.")); return; } - NymeaLightSerialInterface *lightInterface = new NymeaLightSerialInterface(interface, thing); + NymeaLightSerialInterface *lightInterface = new NymeaLightSerialInterface(interface); light = new NymeaLight(lightInterface, this); lightInterface->setParent(light); @@ -106,7 +106,7 @@ void IntegrationPluginWs2812fx::setupThing(ThingSetupInfo *info) return; } - NymeaLightTcpInterface *lightInterface = new NymeaLightTcpInterface(QHostAddress(interface), thing); + NymeaLightTcpInterface *lightInterface = new NymeaLightTcpInterface(QHostAddress(interface)); light = new NymeaLight(lightInterface, this); lightInterface->setParent(light); } diff --git a/ws2812fx/nymealight.cpp b/ws2812fx/nymealight.cpp index 57286471..f6c70703 100644 --- a/ws2812fx/nymealight.cpp +++ b/ws2812fx/nymealight.cpp @@ -41,7 +41,7 @@ NymeaLight::NymeaLight(NymeaLightInterface *interface, QObject *parent) : connect(m_interface, &NymeaLightInterface::availableChanged, this, [=](bool available){ m_interfaceAvailable = available; if (m_interfaceAvailable) { - qCDebug(dcWs2812fx()) << "Nymea light interface is now available. Start polling status of the light controller..."; + qCDebug(dcWs2812fx()) << "NymeaLight: Interface is now available. Start polling status of the light controller..."; m_pollStatusRetryCount = 0; pollStatus(); } else { @@ -142,13 +142,13 @@ bool NymeaLight::available() const void NymeaLight::enable() { m_interface->open(); - qCDebug(dcWs2812fx()) << "Nymea light enabled"; + qCDebug(dcWs2812fx()) << "NymeaLight: Enabled"; } void NymeaLight::disable() { m_interface->close(); - qCDebug(dcWs2812fx()) << "Nymea light disabled"; + qCDebug(dcWs2812fx()) << "NymeaLight: Disabled"; } NymeaLightInterfaceReply *NymeaLight::createReply(const QByteArray &requestData) @@ -175,7 +175,7 @@ void NymeaLight::sendNextRequest() // TODO: if not available, finish all replies with unknown error m_currentReply = m_pendingRequests.dequeue(); - qCDebug(dcWs2812fx()) << "Sending request" << m_currentReply->command() << m_currentReply->requestId() << m_currentReply->requestData().toHex(); + qCDebug(dcWs2812fx()) << "NymeaLight: Sending request" << m_currentReply->command() << m_currentReply->requestId() << m_currentReply->requestData().toHex(); m_interface->sendData(m_currentReply->requestData()); m_currentReply->m_timer->start(); } @@ -186,21 +186,21 @@ void NymeaLight::pollStatus() NymeaLightInterfaceReply *reply = getStatus(); connect(reply, &NymeaLightInterfaceReply::finished, this, [=](){ if (reply->status() == NymeaLightInterface::StatusSuccess) { - qCDebug(dcWs2812fx()) << "Get status request finished successfully. The firmware is ready to operate."; + qCDebug(dcWs2812fx()) << "NymeaLight: Get status request finished successfully. The firmware is ready to operate."; m_ready = true; m_pollStatusRetryCount = 0; emit availableChanged(true); } else { m_pollStatusRetryCount++; if (m_pollStatusRetryCount >= m_pollStatusRetryLimit) { - qCWarning(dcWs2812fx()) << "Firmware did not respond to get status request after" << m_pollStatusRetryCount << "attempts. Giving up."; + qCWarning(dcWs2812fx()) << "NymeaLight: Firmware did not respond to get status request after" << m_pollStatusRetryCount << "attempts. Giving up."; m_ready = false; } else { if (!m_ready && m_interfaceAvailable) { - qCDebug(dcWs2812fx()) << "Get status request finished with error" << reply->status() << "Retry" << m_pollStatusRetryCount << "/" << m_pollStatusRetryLimit; + qCDebug(dcWs2812fx()) << "NymeaLight: Get status request finished with error" << reply->status() << "Retry" << m_pollStatusRetryCount << "/" << m_pollStatusRetryLimit; pollStatus(); } else { - qCDebug(dcWs2812fx()) << "Get status request finished with error, but that's ok since we received the ready notification." << reply->status(); + qCDebug(dcWs2812fx()) << "NymeaLight: Get status request finished with error, but that's ok since we received the ready notification." << reply->status(); } } } @@ -209,7 +209,7 @@ void NymeaLight::pollStatus() NymeaLightInterfaceReply *NymeaLight::getStatus() { - qCDebug(dcWs2812fx()) << "Request status of nymea light"; + qCDebug(dcWs2812fx()) << "NymeaLight: Request status of nymea light"; QByteArray requestData; QDataStream stream(&requestData, QIODevice::WriteOnly); stream << static_cast(NymeaLightInterface::CommandGetStatus); @@ -228,7 +228,7 @@ void NymeaLight::onDataReceived(const QByteArray &data) quint8 commandInt = static_cast((data.at(0))); quint8 requestId = static_cast(data.at(1)); - qCDebug(dcWs2812fx()) << "Recived data" << commandInt << requestId << data.toHex(); + qCDebug(dcWs2812fx()) << "NymeaLight: Received data" << commandInt << requestId << data.toHex(); // Check if command or notification if (commandInt < 0xF0) { @@ -242,15 +242,15 @@ void NymeaLight::onDataReceived(const QByteArray &data) m_currentReply->m_status = status; if (status != NymeaLightInterface::StatusSuccess) { - qCWarning(dcWs2812fx()) << "Request finished with error" << command << m_currentReply->requestId() << status; + qCWarning(dcWs2812fx()) << "NymeaLight: Request finished with error" << command << m_currentReply->requestId() << status; } else { - qCDebug(dcWs2812fx()) << "Request finished" << command << m_currentReply->requestId() << status; + qCDebug(dcWs2812fx()) << "NymeaLight: Request finished" << command << m_currentReply->requestId() << status; } emit m_currentReply->finished(); } } else { - qCWarning(dcWs2812fx()) << "Received unhandled command response data" << data.toHex(); + qCWarning(dcWs2812fx()) << "NymeaLight: Received unhandled command response data" << data.toHex(); } } else { NymeaLightInterface::Notification notification = static_cast(commandInt); @@ -261,13 +261,12 @@ void NymeaLight::onDataReceived(const QByteArray &data) emit availableChanged(true); break; case NymeaLightInterface::NotificationDebugMessage: - qCDebug(dcWs2812fx()) << "Firmware debug:" << QString::fromUtf8(data.right(data.length() - 2)); + qCDebug(dcWs2812fx()) << "NymeaLight: Firmware debug:" << QString::fromUtf8(data.right(data.length() - 2)); break; default: - qCWarning(dcWs2812fx()) << "Unhandled notification received" << data.toHex(); + qCWarning(dcWs2812fx()) << "NymeaLight: Unhandled notification received" << data.toHex(); break; } } - } diff --git a/ws2812fx/nymealighttcpinterface.cpp b/ws2812fx/nymealighttcpinterface.cpp new file mode 100644 index 00000000..ec2a263b --- /dev/null +++ b/ws2812fx/nymealighttcpinterface.cpp @@ -0,0 +1,118 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "nymealighttcpinterface.h" +#include "extern-plugininfo.h" + +#include + +NymeaLightTcpInterface::NymeaLightTcpInterface(const QHostAddress &address, QObject *parent) : + NymeaLightInterface(parent), + m_address(address) +{ + qCDebug(dcWs2812fx()) << "NymeaLightTcpInterface: Creating TCP connection" << m_address; + m_socket = new QTcpSocket(this); + + connect(m_socket, &QTcpSocket::stateChanged, this, &NymeaLightTcpInterface::onStateChanged); + connect(m_socket, &QTcpSocket::readyRead, this, &NymeaLightTcpInterface::onReadyRead); + connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); + + m_reconnectTimer = new QTimer(this); + m_reconnectTimer->setInterval(5000); + m_reconnectTimer->setSingleShot(false); + connect(m_reconnectTimer, &QTimer::timeout, this, [=](){ + if (m_socket->isOpen()) { + m_reconnectTimer->stop(); + } else { + open(); + } + }); +} + +bool NymeaLightTcpInterface::open() +{ + m_socket->connectToHost(m_address, 1080); + return true; +} + +void NymeaLightTcpInterface::close() +{ + m_socket->close(); +} + +bool NymeaLightTcpInterface::available() +{ + return m_socket->isOpen(); +} + +void NymeaLightTcpInterface::sendData(const QByteArray &data) +{ + m_socket->write(data); + m_socket->flush(); +} + +void NymeaLightTcpInterface::setAddress(const QHostAddress &address) +{ + m_address = address; +} + +QHostAddress NymeaLightTcpInterface::address() const +{ + return m_address; +} + +void NymeaLightTcpInterface::onReadyRead() +{ + QByteArray data; + + while (m_socket->canReadLine()) { + data = m_socket->readLine(); + + if (!m_buffer.isEmpty() && m_buffer.length() >= 3) { + emit dataReceived(m_buffer); + } + m_buffer.clear(); + } +} + +void NymeaLightTcpInterface::onStateChanged(QAbstractSocket::SocketState state) +{ + if (state == QAbstractSocket::SocketState::ConnectedState) { + emit availableChanged(true); + } else if (state == QAbstractSocket::SocketState::UnconnectedState) { + emit availableChanged(false); + m_reconnectTimer->start(); + } +} + +void NymeaLightTcpInterface::onError(QAbstractSocket::SocketError) +{ + qCWarning(dcWs2812fx()) << "NymeaLightTcpInterface: Tcp socket error" << m_socket->errorString(); +} diff --git a/ws2812fx/nymealighttcpinterface.h b/ws2812fx/nymealighttcpinterface.h new file mode 100644 index 00000000..318d2038 --- /dev/null +++ b/ws2812fx/nymealighttcpinterface.h @@ -0,0 +1,69 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef NYMEALIGHTTCPINTERFACE_H +#define NYMEALIGHTTCPINTERFACE_H + +#include +#include +#include +#include + +#include "nymealightinterface.h" + +class NymeaLightTcpInterface : public NymeaLightInterface +{ + Q_OBJECT +public: + explicit NymeaLightTcpInterface(const QHostAddress &address, QObject *parent = nullptr); + ~NymeaLightTcpInterface() override = default; + + bool open() override; + void close() override; + bool available() override; + void sendData(const QByteArray &data) override; + + void setAddress(const QHostAddress &address); + QHostAddress address() const; + +private: + + QHostAddress m_address; + QTimer *m_reconnectTimer = nullptr; + QTcpSocket *m_socket = nullptr; + QByteArray m_buffer; + +private slots: + void onReadyRead(); + void onStateChanged(QAbstractSocket::SocketState state); + void onError(QAbstractSocket::SocketError); +}; + +#endif // NYMEALIGHTTCPINTERFACE_H