From 40ce1667c673aad19adacec9a69974ee33ee4f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 30 Sep 2020 10:48:25 +0200 Subject: [PATCH] Continue with uart protocol --- libnymea-zigbee/backends/nxp/interface/nxp.h | 14 +++- .../nxp/interface/zigbeeinterfacenxp.cpp | 1 + .../nxp/zigbeebridgecontrollernxp.cpp | 72 +++++++++++++++++-- .../backends/nxp/zigbeebridgecontrollernxp.h | 6 +- .../backends/nxp/zigbeenetworknxp.cpp | 15 ++-- 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/libnymea-zigbee/backends/nxp/interface/nxp.h b/libnymea-zigbee/backends/nxp/interface/nxp.h index 0683f52..624a7c6 100644 --- a/libnymea-zigbee/backends/nxp/interface/nxp.h +++ b/libnymea-zigbee/backends/nxp/interface/nxp.h @@ -9,7 +9,8 @@ class Nxp public: enum Command { CommandGetVersion = 0x00, - CommandGetDeviceState = 0x01 + CommandGetDeviceState = 0x01, + CommandSoftReset = 0x02 }; Q_ENUM(Command) @@ -27,6 +28,17 @@ public: }; Q_ENUM(Status) + enum LogLevel { + LogLevelEmergency = 0x00, + LogLevelAlert = 0x01, + LogLevelCritical = 0x02, + LogLevelError = 0x03, + LogLevelWarning = 0x04, + LogLevelNotice = 0x05, + LogLevelInfo = 0x06, + LogLevelDebug = 0x07 + }; + Q_ENUM(LogLevel) }; #endif // NXP_H diff --git a/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxp.cpp b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxp.cpp index bf319cf..9bc115c 100644 --- a/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxp.cpp +++ b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxp.cpp @@ -163,6 +163,7 @@ void ZigbeeInterfaceNxp::onReadyRead() // Read each byte until we get END byte, then unescape the package for (int i = 0; i < data.length(); i++) { quint8 byte = static_cast(data.at(i)); + qCDebug(dcZigbeeInterfaceTraffic()) << ZigbeeUtils::convertByteToHexString(byte); if (byte == ProtocolByteEnd) { // If there is no data...continue since it might be a starting END byte if (m_dataBuffer.isEmpty()) diff --git a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp index 7437638..f2d9bc7 100644 --- a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp +++ b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp @@ -1,5 +1,6 @@ #include "zigbeebridgecontrollernxp.h" #include "loggingcategory.h" +#include "zigbeeutils.h" #include @@ -22,19 +23,31 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestVersion() QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Nxp::CommandGetVersion); - stream << static_cast(m_sequenceNumber); + stream << static_cast(m_sequenceNumber++); stream << static_cast(0); // Frame length - m_sequenceNumber++; - return createReply(Nxp::CommandGetVersion, "Request controller version", message, this); + return createReply(Nxp::CommandGetVersion, m_sequenceNumber, "Request controller version", message, this); } -ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::createReply(Nxp::Command command, const QString &requestName, const QByteArray &requestData, QObject *parent) +ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestSoftResetController() +{ + QByteArray message; + QDataStream stream(&message, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(Nxp::CommandSoftReset); + stream << static_cast(m_sequenceNumber++); + stream << static_cast(0); // Frame length + + return createReply(Nxp::CommandSoftReset, m_sequenceNumber, "Request soft reset controller", message, this); +} + +ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::createReply(Nxp::Command command, quint8 sequenceNumber, const QString &requestName, const QByteArray &requestData, QObject *parent) { // Create the reply ZigbeeInterfaceNxpReply *reply = new ZigbeeInterfaceNxpReply(command, parent); reply->m_requestName = requestName; reply->m_requestData = requestData; + reply->m_sequenceNumber = sequenceNumber; // Make sure we clean up on timeout connect(reply, &ZigbeeInterfaceNxpReply::timeout, this, [reply](){ @@ -46,8 +59,8 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::createReply(Nxp::Command com reply->deleteLater(); }); + m_pendingReplies.insert(sequenceNumber, reply); m_interface->sendPackage(requestData); - return reply; } @@ -59,7 +72,54 @@ void ZigbeeBridgeControllerNxp::onInterfaceAvailableChanged(bool available) void ZigbeeBridgeControllerNxp::onInterfacePackageReceived(const QByteArray &package) { - qCDebug(dcZigbeeController()) << "Interface package received" << package; + QDataStream stream(package); + stream.setByteOrder(QDataStream::LittleEndian); + quint8 commandInt = 0; quint8 sequenceNumber = 0; + stream >> commandInt >> sequenceNumber; + + // Note: commands >= 0x7D are notifications + if (commandInt >= 0x7D) { + quint16 payloadLength = 0; + stream >> payloadLength; + QByteArray data = package.mid(4, payloadLength); + if (package.length() < payloadLength + 4) { + qCWarning(dcZigbeeController()) << "Invalid package length received" << ZigbeeUtils::convertByteArrayToHexString(package) << payloadLength; + return; + } + Nxp::Notification notification = static_cast(commandInt); + //qCDebug(dcZigbeeController()) << "Interface notification received" << notification << "SQN:" << sequenceNumber << ZigbeeUtils::convertByteArrayToHexString(data); + if (notification == Nxp::NotificationDebugMessage) { + if (data.isEmpty()) { + qCWarning(dcZigbeeController()) << "Received empty debug log notification"; + return; + } + Nxp::LogLevel logLevel = static_cast(data.at(0)); + qCDebug(dcZigbeeController()) << "DEBUG" << logLevel << qUtf8Printable(data.right(data.length() - 1)); + } + + emit interfaceNotificationReceived(notification, data); + } else { + quint8 statusInt = 0; quint16 payloadLength = 0; + stream >> statusInt >> payloadLength; + if (package.length() < payloadLength + 5) { + qCWarning(dcZigbeeController()) << "Invalid package length received" << ZigbeeUtils::convertByteArrayToHexString(package) << payloadLength; + return; + } + QByteArray data = package.mid(5, payloadLength); + Nxp::Command command = static_cast(commandInt); + Nxp::Status status = static_cast(statusInt); + qCDebug(dcZigbeeController()) << "Interface response received" << command << "SQN:" << sequenceNumber << status << ZigbeeUtils::convertByteArrayToHexString(data); + if (m_pendingReplies.keys().contains(sequenceNumber)) { + ZigbeeInterfaceNxpReply * reply = m_pendingReplies.take(sequenceNumber); + if (reply->command() == command) { + reply->m_status = status; + reply->m_responseData = data; + } else { + qCWarning(dcZigbeeController()) << "Received interface response for a pending sequence number but the command does not match the request." << command << reply->command(); + } + reply->finished(); + } + } } bool ZigbeeBridgeControllerNxp::enable(const QString &serialPort, qint32 baudrate) diff --git a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h index c198818..7640470 100644 --- a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h +++ b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h @@ -23,14 +23,18 @@ public: // Controllere requests ZigbeeInterfaceNxpReply *requestVersion(); + ZigbeeInterfaceNxpReply *requestSoftResetController(); signals: + void interfaceNotificationReceived(Nxp::Notification notification, const QByteArray &data); private: ZigbeeInterfaceNxp *m_interface = nullptr; quint8 m_sequenceNumber = 0; - ZigbeeInterfaceNxpReply *createReply(Nxp::Command command, const QString &requestName, const QByteArray &requestData, QObject *parent); + QHash m_pendingReplies; + ZigbeeInterfaceNxpReply *createReply(Nxp::Command command, quint8 sequenceNumber, const QString &requestName, const QByteArray &requestData, QObject *parent); + private slots: void onInterfaceAvailableChanged(bool available); diff --git a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp index 89410cc..eaec43a 100644 --- a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp +++ b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp @@ -38,10 +38,12 @@ void ZigbeeNetworkNxp::onControllerAvailableChanged(bool available) qCDebug(dcZigbeeNetwork()) << "Controller is" << (available ? "now available" : "not available any more"); if (available) { - ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion(); - connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [](){ - qCDebug(dcZigbeeNetwork()) << "Version reply finished"; - }); + reset(); + +// ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion(); +// connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [](){ +// qCDebug(dcZigbeeNetwork()) << "Version reply finished"; +// }); } } @@ -75,7 +77,10 @@ void ZigbeeNetworkNxp::stopNetwork() void ZigbeeNetworkNxp::reset() { - + ZigbeeInterfaceNxpReply *reply = m_controller->requestSoftResetController(); + connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [](){ + qCDebug(dcZigbeeNetwork()) << "Soft reset reply finished"; + }); } void ZigbeeNetworkNxp::factoryResetNetwork()