From 118cdedc6a37324e3524c66bb558cf222818e087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 8 Apr 2020 21:34:05 +0200 Subject: [PATCH] Implement first ZDO call --- README.md | 9 +- .../interface/zigbeeinterfacedeconz.cpp | 2 +- .../interface/zigbeeinterfacedeconzreply.cpp | 12 +- .../interface/zigbeeinterfacedeconzreply.h | 9 +- .../deconz/zigbeebridgecontrollerdeconz.cpp | 274 +++++++++++------- .../deconz/zigbeebridgecontrollerdeconz.h | 47 ++- .../deconz/zigbeenetworkdeconz.cpp | 182 +++++++++--- libnymea-zigbee/deconz/zigbeenetworkdeconz.h | 16 +- libnymea-zigbee/deconz/zigbeenodedeconz.cpp | 43 ++- libnymea-zigbee/deconz/zigbeenodedeconz.h | 7 +- libnymea-zigbee/libnymea-zigbee.pro | 2 - libnymea-zigbee/nxp/zigbeenetworknxp.cpp | 7 + libnymea-zigbee/nxp/zigbeenetworknxp.h | 3 + libnymea-zigbee/zigbeedeviceobject.cpp | 33 --- libnymea-zigbee/zigbeedeviceobject.h | 43 --- libnymea-zigbee/zigbeedeviceprofile.cpp | 25 ++ libnymea-zigbee/zigbeedeviceprofile.h | 17 +- libnymea-zigbee/zigbeenetwork.cpp | 23 ++ libnymea-zigbee/zigbeenetwork.h | 9 + libnymea-zigbee/zigbeenetworkreply.cpp | 5 + libnymea-zigbee/zigbeenetworkreply.h | 6 + libnymea-zigbee/zigbeenode.h | 28 +- 22 files changed, 543 insertions(+), 259 deletions(-) delete mode 100644 libnymea-zigbee/zigbeedeviceobject.cpp delete mode 100644 libnymea-zigbee/zigbeedeviceobject.h diff --git a/README.md b/README.md index 093553e..f8bb9cc 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,16 @@ This repository contains the nymea-zigbee library and tools. # Supported hardware -Currently the only supported hardware is from NXP, but the tool will be designed to support also other hardware modules. +Depending on your available hardware following gateway modules are supported ## NXP + * JN5168 (SoM) * JN5169 (USB Stick) +## deCONZ + +* ConBee +* RaspBee +* ConBee II +* RaspBee II diff --git a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.cpp b/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.cpp index bb25933..fcc8230 100644 --- a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.cpp +++ b/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.cpp @@ -224,7 +224,7 @@ void ZigbeeInterfaceDeconz::sendPackage(const QByteArray &package) qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteArrayToHexString(data); } - m_serialPort->flush(); + //m_serialPort->flush(); } bool ZigbeeInterfaceDeconz::enable(const QString &serialPort, qint32 baudrate) diff --git a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.cpp b/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.cpp index 38daea3..3274938 100644 --- a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.cpp +++ b/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.cpp @@ -60,8 +60,18 @@ void ZigbeeInterfaceDeconzReply::abort() ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent) : QObject(parent), + m_timer(new QTimer(this)), m_command(command), m_sequenceNumber(sequenceNumber) { - + m_timer->setInterval(2000); + m_timer->setSingleShot(true); + connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceDeconzReply::onTimeout); +} + +void ZigbeeInterfaceDeconzReply::onTimeout() +{ + m_timeout = true; + emit timeout(); + emit finished(); } diff --git a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.h b/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.h index 1b267e9..204fbe7 100644 --- a/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.h +++ b/libnymea-zigbee/deconz/interface/zigbeeinterfacedeconzreply.h @@ -29,6 +29,7 @@ #define ZIGBEEINTERFACEDECONZREPLY_H #include +#include #include "deconz.h" @@ -47,12 +48,14 @@ public: // Response content Deconz::StatusCode statusCode() const; + bool timeout() const; bool aborted() const; void abort(); private: explicit ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent = nullptr); - + QTimer *m_timer = nullptr; + bool m_timeout = false; bool m_aborted = false; // Request content @@ -63,7 +66,11 @@ private: Deconz::StatusCode m_statusCode = Deconz::StatusCodeError; QByteArray m_responseData; +private slots: + void onTimeout(); + signals: + void timeout(); void finished(); }; diff --git a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp index 0e3302e..6163b81 100644 --- a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp +++ b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp @@ -28,6 +28,7 @@ #include "zigbeebridgecontrollerdeconz.h" #include "loggingcategory.h" #include "zigbeeutils.h" +#include "zigbeedeviceprofile.h" #include @@ -219,7 +220,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestQuerySendDataCo return createReply(Deconz::CommandApsDataConfirm, sequenceNumber, this); } -ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius) +ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius) { quint8 sequenceNumber = generateSequenceNumber(); qCDebug(dcZigbeeController()) << "Request enqueue send data to group" << ZigbeeUtils::convertUint16ToHexString(groupAddress) @@ -240,13 +241,13 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData stream << static_cast(sequenceNumber); stream << static_cast(0); // Reserverd stream << static_cast(7 + payloadLength); // Frame length - stream << static_cast(payloadLength); + stream << payloadLength; stream << requestId; stream << static_cast(0); // Flags stream << static_cast(Zigbee::DestinationAddressModeGroup); stream << groupAddress << destinationEndpoint; - stream << static_cast(profileId); - stream << static_cast(clusterId); + stream << profileId; + stream << clusterId; stream << sourceEndpoint; stream << static_cast(asdu.length()); for (int i = 0; i < asdu.length(); i++) { @@ -260,7 +261,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); } -ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius) +ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius) { quint8 sequenceNumber = generateSequenceNumber(); qCDebug(dcZigbeeController()) << "Request enqueue send data to short address" << ZigbeeUtils::convertUint16ToHexString(shortAddress) @@ -281,13 +282,13 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData stream << static_cast(sequenceNumber); stream << static_cast(0); // Reserverd stream << static_cast(7 + payloadLength); // Frame length - stream << static_cast(payloadLength); + stream << payloadLength; stream << requestId; stream << static_cast(0); // Flags stream << static_cast(Zigbee::DestinationAddressModeShortAddress); stream << shortAddress << destinationEndpoint; - stream << static_cast(profileId); - stream << static_cast(clusterId); + stream << profileId; + stream << clusterId; stream << sourceEndpoint; stream << static_cast(asdu.length()); for (int i = 0; i < asdu.length(); i++) { @@ -301,7 +302,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); } -ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius) +ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius) { quint8 sequenceNumber = generateSequenceNumber(); qCDebug(dcZigbeeController()) << "Request enqueue send data to IEEE address" << ieeeAddress.toString() @@ -322,13 +323,13 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData stream << static_cast(sequenceNumber); stream << static_cast(0); // Reserverd stream << static_cast(7 + payloadLength); // Frame length - stream << static_cast(payloadLength); + stream << payloadLength; stream << requestId; stream << static_cast(0); // Flags stream << static_cast(Zigbee::DestinationAddressModeIeeeAddress); stream << ieeeAddress.toUInt64() << destinationEndpoint; - stream << static_cast(profileId); - stream << static_cast(clusterId); + stream << profileId; + stream << clusterId; stream << sourceEndpoint; stream << static_cast(asdu.length()); for (int i = 0; i < asdu.length(); i++) { @@ -342,6 +343,30 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); } +ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(const ZigbeeNetworkRequest &request) +{ + ZigbeeInterfaceDeconzReply *interfaceReply = nullptr; + switch (request.destinationAddressMode()) { + case Zigbee::DestinationAddressModeGroup: + interfaceReply = requestEnqueueSendDataGroup(request.requestId(), request.destinationShortAddress(), + request.destinationEndpoint(), request.profileId(), request.clusterId(), + request.sourceEndpoint(), request.asdu(), request.radius()); + break; + case Zigbee::DestinationAddressModeShortAddress: + interfaceReply = requestEnqueueSendDataShortAddress(request.requestId(), request.destinationShortAddress(), + request.destinationEndpoint(), request.profileId(), request.clusterId(), + request.sourceEndpoint(), request.asdu(), request.radius()); + break; + case Zigbee::DestinationAddressModeIeeeAddress: + interfaceReply = requestEnqueueSendDataIeeeAddress(request.requestId(), request.destinationIeeeAddress(), + request.destinationEndpoint(), request.profileId(), request.clusterId(), + request.sourceEndpoint(), request.asdu(), request.radius()); + break; + } + + return interfaceReply; +} + quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber() { return m_sequenceNumber++; @@ -358,6 +383,9 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Co // Add it to the pending list m_pendingReplies.insert(sequenceNumber, reply); + // Fixme: start the timer once actually sent to the interface + reply->m_timer->start(); + return reply; } @@ -712,6 +740,38 @@ DeconzDeviceState ZigbeeBridgeControllerDeconz::parseDeviceStateFlag(quint8 devi return state; } +void ZigbeeBridgeControllerDeconz::readDataIndication() +{ + ZigbeeInterfaceDeconzReply *reply = requestReadReceivedDataIndication(); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not read data indication." << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + // ASP data indication received, process the content + qCDebug(dcZigbeeController()) << "Reading data indication finished successfully"; + processDataIndication(reply->responseData()); + }); +} + +void ZigbeeBridgeControllerDeconz::readDataConfirm() +{ + ZigbeeInterfaceDeconzReply *reply = requestQuerySendDataConfirm(); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not read data confirm." << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + // ASP data indication received, process the content + qCDebug(dcZigbeeController()) << "Reading data confirm finished successfully"; + processDataConfirm(reply->responseData()); + }); +} + void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceState) { qCDebug(dcZigbeeController()) << deviceState; @@ -732,36 +792,16 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt if (m_networkState != Deconz::NetworkStateConnected) return; + // Note: read a data indication before a confirmation since the confirmation arrives after a related indication normally + // Check if we have to read a data indication message if (deviceState.aspDataIndication) { - ZigbeeInterfaceDeconzReply *reply = requestReadReceivedDataIndication(); - connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ - if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not read data indication." << reply->statusCode(); - // FIXME: set an appropriate error - return; - } - - // ASP data indication received, process the content - qCDebug(dcZigbeeController()) << "Reading data indication finished successfully"; - processDataIndication(reply->responseData()); - }); + readDataIndication(); } // Check if we have a response to read for a request if (deviceState.aspDataConfirm) { - ZigbeeInterfaceDeconzReply *reply = requestQuerySendDataConfirm(); - connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ - if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not read data indication." << reply->statusCode(); - // FIXME: set an appropriate error - return; - } - - // ASP data indication received, process the content - qCDebug(dcZigbeeController()) << "Reading data confirm finished successfully"; - processDataConfirm(reply->responseData()); - }); + readDataConfirm(); } } @@ -771,104 +811,76 @@ void ZigbeeBridgeControllerDeconz::processDataIndication(const QByteArray &data) // ASP data indication QDataStream stream(data); stream.setByteOrder(QDataStream::LittleEndian); - quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 destinationAddressModeFlag = 0; - quint16 destinationShortAddress = 0; quint64 destinationIeeeAddress = 0; quint8 destinationEndpoint = 0; - quint8 sourceAddressModeFlag = 0; quint16 sourceShortAddress = 0; quint64 sourceIeeeAddress = 0; quint8 sourceEndpoint = 0; - quint16 profileId = 0; quint16 clusterId = 0; quint16 asduLength = 0; QByteArray asdu; quint8 reserved = 0; - quint8 lqi = 0; qint8 rssi = 0; + quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 reserved = 0; quint16 asduLength = 0; - stream >> payloadLenght >> deviceStateFlag >> destinationAddressModeFlag; - Zigbee::DestinationAddressMode destinationAddressMode = static_cast(destinationAddressModeFlag); + DeconzApsDataIndication indication; + stream >> payloadLenght >> deviceStateFlag; + stream >> indication.destinationAddressMode; + Zigbee::DestinationAddressMode destinationAddressMode = static_cast(indication.destinationAddressMode); if (destinationAddressMode == Zigbee::DestinationAddressModeGroup || destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) - stream >> destinationShortAddress; + stream >> indication.destinationShortAddress; if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) - stream >> destinationIeeeAddress; + stream >> indication.destinationIeeeAddress; - stream >> destinationEndpoint >> sourceAddressModeFlag; + stream >> indication.destinationEndpoint >> indication.sourceAddressMode; - Zigbee::SourceAddressMode sourceAddressMode = static_cast(sourceAddressModeFlag); + Zigbee::SourceAddressMode sourceAddressMode = static_cast(indication.sourceAddressMode); if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) - stream >> sourceShortAddress; + stream >> indication.sourceShortAddress; if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) - stream >> sourceIeeeAddress; - - stream >> sourceEndpoint >> profileId >> clusterId >> asduLength; + stream >> indication.sourceIeeeAddress; + stream >> indication.sourceEndpoint >> indication.profileId >> indication.clusterId >> asduLength; // Fill asdu data for (int i = 0; i < asduLength; i++) { quint8 byte = 0; stream >> byte; - asdu.append(static_cast(byte)); + indication.asdu.append(static_cast(byte)); } - stream >> reserved >> reserved >> lqi >> reserved >> reserved >> reserved >> reserved >> rssi; + stream >> reserved >> reserved >> indication.lqi >> reserved >> reserved >> reserved >> reserved >> indication.rssi; // Print the information for debugging - qCDebug(dcZigbeeController()) << "Data indication received:"; - qCDebug(dcZigbeeController()) << " Destination address mode:" << destinationAddressMode; - if (destinationAddressMode == Zigbee::DestinationAddressModeGroup) - qCDebug(dcZigbeeController()) << " Destination address (group):" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); + qCDebug(dcZigbeeController()) << indication; - if (destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) - qCDebug(dcZigbeeController()) << " Destination short address:" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); + emit aspDataIndicationReceived(indication); - if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) - qCDebug(dcZigbeeController()) << " Destination IEEE address:" << ZigbeeAddress(destinationIeeeAddress).toString(); - - qCDebug(dcZigbeeController()) << " Destination endpoint" << ZigbeeUtils::convertByteToHexString(destinationEndpoint); - - qCDebug(dcZigbeeController()) << " Source address mode:" << sourceAddressMode; - if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) - qCDebug(dcZigbeeController()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceShortAddress); - - if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) - qCDebug(dcZigbeeController()) << " Source IEEE address:" << ZigbeeAddress(sourceIeeeAddress).toString(); - - - qCDebug(dcZigbeeController()) << " Source endpoint:" << ZigbeeUtils::convertByteToHexString(sourceEndpoint); - qCDebug(dcZigbeeController()) << " Profile:" << static_cast(profileId); - qCDebug(dcZigbeeController()) << " Cluster:" << static_cast(clusterId); - qCDebug(dcZigbeeController()) << " ASDU:" << ZigbeeUtils::convertByteArrayToHexString(asdu); - qCDebug(dcZigbeeController()) << " LQI:" << lqi; - qCDebug(dcZigbeeController()) << " RSSI:" << rssi << "dBm"; - - processDeviceState(parseDeviceStateFlag(deviceStateFlag)); + // Process the device state in order to check if we have to request another indication + DeconzDeviceState deviceState = parseDeviceStateFlag(deviceStateFlag); + if (deviceState.aspDataIndication) { + readDataIndication(); + } } void ZigbeeBridgeControllerDeconz::processDataConfirm(const QByteArray &data) { QDataStream stream(data); stream.setByteOrder(QDataStream::LittleEndian); - quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 requestId = 0; quint8 destinationAddressMode = 0; - quint16 destinationShortAddress = 0; quint64 destinationIeeeAddress = 0; quint8 destinationEndpoint = 0; - quint8 sourceEndpoint = 0; quint8 zigbeeConfirmStatus = 0; + DeconzApsDataConfirm confirm; + quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; + stream >> payloadLenght >> deviceStateFlag; + stream >> confirm.requestId >> confirm.destinationAddressMode; - stream >> payloadLenght >> deviceStateFlag >> requestId >> destinationAddressMode; - if (destinationAddressMode == Zigbee::DestinationAddressModeGroup || destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) - stream >> destinationShortAddress; + if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeGroup || confirm.destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) + stream >> confirm.destinationShortAddress; - if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) - stream >> destinationIeeeAddress; + if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) + stream >> confirm.destinationIeeeAddress; - stream >> destinationEndpoint >> sourceEndpoint >> zigbeeConfirmStatus; + stream >> confirm.destinationEndpoint >> confirm.sourceEndpoint >> confirm.zigbeeStatusCode; // Print the information for debugging - qCDebug(dcZigbeeController()) << "Data confirm received: Request" << requestId; - qCDebug(dcZigbeeController()) << " Destination address mode:" << destinationAddressMode; - if (destinationAddressMode == Zigbee::DestinationAddressModeGroup) - qCDebug(dcZigbeeController()) << " Destination address (group):" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); + qCDebug(dcZigbeeController()) << confirm; - if (destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) - qCDebug(dcZigbeeController()) << " Destination short address:" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); + emit aspDataConfirmReceived(confirm); - if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) - qCDebug(dcZigbeeController()) << " Destination IEEE address:" << ZigbeeAddress(destinationIeeeAddress).toString(); - - qCDebug(dcZigbeeController()) << " Destination endpoint" << ZigbeeUtils::convertByteToHexString(destinationEndpoint); - qCDebug(dcZigbeeController()) << " Source endpoint" << ZigbeeUtils::convertByteToHexString(sourceEndpoint); - qCDebug(dcZigbeeController()) << " Confirm status" << static_cast(zigbeeConfirmStatus); + // Process the device state in order to check if we have to request another indication + DeconzDeviceState deviceState = parseDeviceStateFlag(deviceStateFlag); + if (deviceState.aspDataConfirm) { + readDataConfirm(); + } } void ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged(bool available) @@ -899,8 +911,8 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray & QByteArray data = package.right(package.length() - 5); Deconz::Command command = static_cast(commandInt); Deconz::StatusCode status = static_cast(statusInt); - qCDebug(dcZigbeeController()) << "Interface message received" << command << "SQN:" << sequenceNumber - << status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data); + //qCDebug(dcZigbeeController()) << "Interface message received" << command << "SQN:" << sequenceNumber + // << status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data); // Check if this is an interface response for a pending reply if (m_pendingReplies.contains(sequenceNumber) && m_pendingReplies.value(sequenceNumber)->command() == command) { @@ -982,3 +994,59 @@ QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState) debug.nospace() << "CanSend=" << deviceState.aspDataRequestFreeSlots << ")"; return debug.space(); } + +QDebug operator<<(QDebug debug, const DeconzApsDataConfirm &confirm) +{ + debug.nospace() << "ASP.Confirm("; + debug.nospace() << "Request ID: " << confirm.requestId << ", "; + + if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeGroup) + debug.nospace() << "Group address:" << ZigbeeUtils::convertUint16ToHexString(confirm.destinationShortAddress) << ", "; + + if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) + debug.nospace() << "NWK address:" << ZigbeeUtils::convertUint16ToHexString(confirm.destinationShortAddress) << ", "; + + if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) + debug.nospace() << "IEEE address:" << ZigbeeAddress(confirm.destinationIeeeAddress).toString() << ", "; + + debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(confirm.destinationEndpoint) << ", "; + debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(confirm.sourceEndpoint) << ", "; + debug.nospace() << static_cast(confirm.zigbeeStatusCode); + debug.nospace() << ")"; + + return debug.space(); +} + +QDebug operator<<(QDebug debug, const DeconzApsDataIndication &indication) +{ + debug.nospace() << "ASP.Indication("; + if (indication.destinationAddressMode == Zigbee::DestinationAddressModeGroup) + debug.nospace() << "Group address:" << ZigbeeUtils::convertUint16ToHexString(indication.destinationShortAddress) << ", "; + + if (indication.destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) + debug.nospace() << "NWK address:" << ZigbeeUtils::convertUint16ToHexString(indication.destinationShortAddress) << ", "; + + if (indication.destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) + debug.nospace() << "IEEE address:" << ZigbeeAddress(indication.destinationIeeeAddress).toString() << ", "; + + debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(indication.destinationEndpoint) << ", "; + debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(indication.sourceEndpoint) << ", "; + + if (indication.sourceAddressMode == Zigbee::SourceAddressModeShortAddress || indication.sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) + debug.nospace() << "Source NWK address:" << ZigbeeUtils::convertUint16ToHexString(indication.sourceShortAddress) << ", "; + + if (indication.sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || indication.sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) + debug.nospace() << "Source IEEE address:" << ZigbeeAddress(indication.sourceIeeeAddress).toString() << ", "; + + debug.nospace() << static_cast(indication.profileId) << ", "; + if (indication.profileId == static_cast(Zigbee::ZigbeeProfileDevice)) { + debug.nospace() << static_cast(indication.clusterId) << ", "; + } else { + debug.nospace() << static_cast(indication.clusterId) << ", "; + } + + debug.nospace() << "ASDU: " << ZigbeeUtils::convertByteArrayToHexString(indication.asdu) << ", "; + debug.nospace() << "LQI: " << indication.lqi << ", "; + debug.nospace() << "RSSI: " << indication.rssi << "dBm)"; + return debug.space(); +} diff --git a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h index 426b70b..4ac1a9b 100644 --- a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h +++ b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h @@ -35,6 +35,7 @@ #include "zigbee.h" #include "zigbeeaddress.h" #include "zigbeenetworkkey.h" +#include "zigbeenetworkrequest.h" #include "zigbeebridgecontroller.h" #include "interface/deconz.h" @@ -70,6 +71,34 @@ typedef struct DeconzDeviceState { bool aspDataRequestFreeSlots = false; } DeconzDeviceState; + +// Basic struct for interface data. Default Response +typedef struct DeconzApsDataConfirm { + quint8 requestId = 0; + quint8 destinationAddressMode = Zigbee::DestinationAddressModeShortAddress; + quint16 destinationShortAddress = 0; + quint64 destinationIeeeAddress; + quint8 destinationEndpoint = 0; + quint8 sourceEndpoint = 0; + quint8 zigbeeStatusCode = 0; +} DeconzApsDataConfirm; + +typedef struct DeconzApsDataIndication { + quint8 destinationAddressMode = 0; + quint16 destinationShortAddress = 0; + quint64 destinationIeeeAddress = 0; + quint8 destinationEndpoint = 0; + quint8 sourceAddressMode = 0; + quint16 sourceShortAddress = 0; + quint64 sourceIeeeAddress = 0; + quint8 sourceEndpoint = 0; + quint16 profileId = 0; + quint16 clusterId = 0; + QByteArray asdu; + quint8 lqi = 0; + qint8 rssi = 0; +} DeconzApsDataIndication; + class ZigbeeBridgeControllerDeconz : public ZigbeeBridgeController { Q_OBJECT @@ -96,9 +125,11 @@ public: ZigbeeInterfaceDeconzReply *requestQuerySendDataConfirm(); // Send data - ZigbeeInterfaceDeconzReply *requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); - ZigbeeInterfaceDeconzReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); - ZigbeeInterfaceDeconzReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); + ZigbeeInterfaceDeconzReply *requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); + ZigbeeInterfaceDeconzReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); + ZigbeeInterfaceDeconzReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); + ZigbeeInterfaceDeconzReply *requestSendRequest(const ZigbeeNetworkRequest &request); + private: ZigbeeInterfaceDeconz *m_interface = nullptr; @@ -122,8 +153,11 @@ private: // Device state helper DeconzDeviceState parseDeviceStateFlag(quint8 deviceStateFlag); - void processDeviceState(DeconzDeviceState deviceState); + void readDataIndication(); + void readDataConfirm(); + + void processDeviceState(DeconzDeviceState deviceState); void processDataIndication(const QByteArray &data); void processDataConfirm(const QByteArray &data); @@ -131,6 +165,9 @@ signals: void networkStateChanged(Deconz::NetworkState networkState); void networkConfigurationParameterChanged(const DeconzNetworkConfiguration &networkConfiguration); + void aspDataConfirmReceived(const DeconzApsDataConfirm &confirm); + void aspDataIndicationReceived(const DeconzApsDataIndication &indication); + private slots: void onInterfaceAvailableChanged(bool available); void onInterfacePackageReceived(const QByteArray &package); @@ -143,6 +180,8 @@ public slots: }; QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState); +QDebug operator<<(QDebug debug, const DeconzApsDataConfirm &confirm); +QDebug operator<<(QDebug debug, const DeconzApsDataIndication &indication); #endif // ZIGBEEBRIDGECONTROLLERDECONZ_H diff --git a/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp b/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp index 45079c1..1d98bd7 100644 --- a/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp +++ b/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp @@ -26,6 +26,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "zigbeenetworkdeconz.h" +#include "zigbeedeviceprofile.h" #include "loggingcategory.h" #include "zigbeeutils.h" @@ -37,6 +38,8 @@ ZigbeeNetworkDeconz::ZigbeeNetworkDeconz(QObject *parent) : m_controller = new ZigbeeBridgeControllerDeconz(this); //connect(m_controller, &ZigbeeBridgeControllerDeconz::messageReceived, this, &ZigbeeNetworkDeconz::onMessageReceived); connect(m_controller, &ZigbeeBridgeControllerDeconz::availableChanged, this, &ZigbeeNetworkDeconz::onControllerAvailableChanged); + connect(m_controller, &ZigbeeBridgeControllerDeconz::aspDataConfirmReceived, this, &ZigbeeNetworkDeconz::onAspDataConfirmReceived); + connect(m_controller, &ZigbeeBridgeControllerDeconz::aspDataIndicationReceived, this, &ZigbeeNetworkDeconz::onAspDataIndicationReceived); m_pollNetworkStateTimer = new QTimer(this); m_pollNetworkStateTimer->setInterval(1000); @@ -52,6 +55,30 @@ ZigbeeBridgeController *ZigbeeNetworkDeconz::bridgeController() const return nullptr; } +ZigbeeNetworkReply *ZigbeeNetworkDeconz::sendRequest(const ZigbeeNetworkRequest &request) +{ + ZigbeeNetworkReply *reply = createNetworkReply(request); + + // Send the request, and keep the reply until transposrt, zigbee trasmission and response arrived + m_pendingReplies.insert(request.requestId(), reply); + + ZigbeeInterfaceDeconzReply *interfaceReply = m_controller->requestSendRequest(request); + connect(interfaceReply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply, interfaceReply](){ + if (interfaceReply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could send request to controller. SQN:" << interfaceReply->sequenceNumber() << interfaceReply->statusCode(); + finishNetworkReply(reply, ZigbeeNetworkReply::ErrorInterfaceError); + return; + } + }); + + return reply; +} + +quint8 ZigbeeNetworkDeconz::generateSequenceNumber() +{ + return m_sequenceNumber++; +} + void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetworkState state) { if (m_createState == state) @@ -68,11 +95,13 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->requestChangeNetworkState(Deconz::NetworkStateOffline); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not stop network for creating a new one." << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not stop network for creating a new one. SQN:" << reply->sequenceNumber() << reply->statusCode(); // FIXME: set an appropriate error return; } + qCDebug(dcZigbeeNetwork()) << "Stop network finished successfully. SQN:" << reply->sequenceNumber(); + // Start polling the device state, should be Online -> Leaving -> Offline m_pollNetworkStateTimer->start(); }); @@ -94,12 +123,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNodeType, paramData); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterNodeType << Deconz::NodeTypeCoordinator << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterNodeType << Deconz::NodeTypeCoordinator << reply->statusCode(); // FIXME: set an appropriate error return; } - qCDebug(dcZigbeeNetwork()) << "Configured successfully bridge to" << Deconz::NodeTypeCoordinator; + qCDebug(dcZigbeeNetwork()) << "Configured successfully bridge to" << Deconz::NodeTypeCoordinator << "SQN:" << reply->sequenceNumber(); QByteArray paramData; QDataStream stream(¶mData, QIODevice::WriteOnly); @@ -109,12 +138,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterChannelMask, paramData); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterChannelMask << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterChannelMask << reply->statusCode(); // FIXME: set an appropriate error return; } - qCDebug(dcZigbeeNetwork()) << "Configured channel mask successfully"; + qCDebug(dcZigbeeNetwork()) << "Configured channel mask successfully. SQN:" << reply->sequenceNumber(); QByteArray paramData; QDataStream stream(¶mData, QIODevice::WriteOnly); @@ -124,12 +153,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterApsExtendedPanId, paramData); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterApsExtendedPanId << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterApsExtendedPanId << reply->statusCode(); // FIXME: set an appropriate error return; } - qCDebug(dcZigbeeNetwork()) << "Configured APS extended PANID successfully"; + qCDebug(dcZigbeeNetwork()) << "Configured APS extended PANID successfully. SQN:" << reply->sequenceNumber(); QByteArray paramData; QDataStream stream(¶mData, QIODevice::WriteOnly); @@ -139,12 +168,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterTrustCenterAddress, paramData); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterTrustCenterAddress << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterTrustCenterAddress << reply->statusCode(); // FIXME: set an appropriate error return; } - qCDebug(dcZigbeeNetwork()) << "Configured trust center address successfully"; + qCDebug(dcZigbeeNetwork()) << "Configured trust center address successfully. SQN:" << reply->sequenceNumber(); QByteArray paramData; QDataStream stream(¶mData, QIODevice::WriteOnly); @@ -154,7 +183,7 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterSecurityMode, paramData); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterSecurityMode << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterSecurityMode << reply->statusCode(); // FIXME: set an appropriate error return; } @@ -166,12 +195,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNetworkKey, securityConfiguration().networkKey().toByteArray()); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterNetworkKey << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterNetworkKey << reply->statusCode(); // FIXME: set an appropriate error // Note: writing the network key fails all the time... //return; } else { - qCDebug(dcZigbeeNetwork()) << "Configured network key successfully"; + qCDebug(dcZigbeeNetwork()) << "Configured network key successfully. SQN:" << reply->sequenceNumber(); } // Configuration finished, lets start the network @@ -188,11 +217,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->requestChangeNetworkState(Deconz::NetworkStateConnected); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not start network for creating a new one." << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not start network for creating a new one. SQN:" << reply->sequenceNumber() << reply->statusCode(); // FIXME: set an appropriate error return; } + qCDebug(dcZigbeeNetwork()) << "Start network finished successfully. SQN:" << reply->sequenceNumber(); // Start polling the device state, should be Online -> Leaving -> Offline m_pollNetworkStateTimer->start(); }); @@ -203,12 +233,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters(); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up." << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode(); // FIXME: set an appropriate error return; } - qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully."; + qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully. SQN:" << reply->sequenceNumber(); setPanId(m_controller->networkConfiguration().panId); setExtendedPanId(m_controller->networkConfiguration().extendedPanId); @@ -224,22 +254,53 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo coordinatorNode->setShortAddress(m_controller->networkConfiguration().shortAddress); coordinatorNode->setExtendedAddress(m_controller->networkConfiguration().ieeeAddress); + addUnitializedNode(coordinatorNode); + coordinatorNode->startInitialization(); // TODO: done when when node initialized - m_coordinatorNode = coordinatorNode; - addNode(coordinatorNode); - - setCreateNetworkState(CreateNetworkStateIdle); - setState(StateRunning); - - //addUnitializedNode(coordinatorNode); - //coordinatorNode->startInitialization(); } } } +void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const DeconzApsDataIndication &indication) +{ + if (indication.clusterId == ZigbeeDeviceProfile::DeviceAnnounce) { + QDataStream stream(indication.asdu); + stream.setByteOrder(QDataStream::LittleEndian); + quint8 sequenceNumber = 0; quint16 shortAddress = 0; quint64 ieeeAddress = 0; quint8 macFlag = 0; + stream >> sequenceNumber >> shortAddress >> ieeeAddress >> macFlag; + onDeviceAnnounced(shortAddress, ZigbeeAddress(ieeeAddress), macFlag); + return; + } + + // Check if this is a response for a ZDO request + foreach (ZigbeeNetworkReply *reply, m_pendingReplies) { + if (reply->request().profileId() == Zigbee::ZigbeeProfileDevice) { + // We have a reply which is waiting for a ZDO response, lets check if they match + + // Check if this is the response to the sent request command + if (indication.clusterId == (reply->request().clusterId() | 0x8000)) { + // Now check if the id matches, if so set the ADPU as response to the reply, otherwise this is not the message for this reply + ZigbeeDeviceProfileAdpu deviceAdpu = ZigbeeDeviceProfile::parseAdpu(indication.asdu); + if (deviceAdpu.sequenceNumber == reply->request().requestId() && deviceAdpu.addressOfInterest == reply->request().destinationShortAddress()) { + // We found the correct reply + + // Set the response payload of the + qCDebug(dcZigbeeNetwork()) << "Indication response for ZDO request received" + << static_cast(reply->request().clusterId()) + << "-->" + << static_cast(indication.clusterId) + << deviceAdpu; + setReplyResponseData(reply, indication.asdu); + return; + } + } + } + } +} + ZigbeeNode *ZigbeeNetworkDeconz::createNode(QObject *parent) { - return new ZigbeeNodeDeconz(m_controller, parent); + return new ZigbeeNodeDeconz(this, parent); } void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining) @@ -271,7 +332,6 @@ void ZigbeeNetworkDeconz::startNetworkInternally() qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().networkKey() << "network link key"; qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().globalTrustCenterLinkKey() << "global trust center link key"; - // - Read the firmware version // - Read the network configuration parameters // - Read the network state @@ -313,12 +373,12 @@ void ZigbeeNetworkDeconz::startNetworkInternally() ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState(); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not read device state during network start up." << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not read device state during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode(); // FIXME: set an appropriate error return; } - qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; + qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully. SQN:" << reply->sequenceNumber(); QDataStream stream(reply->responseData()); stream.setByteOrder(QDataStream::LittleEndian); quint8 deviceStateFlag = 0; @@ -328,11 +388,19 @@ void ZigbeeNetworkDeconz::startNetworkInternally() if (m_createNewNetwork) { setCreateNetworkState(CreateNetworkStateStopNetwork); + // Set offline + // Write configurations + // Set online + // Read configurations + // Create and initialize coordinator node + // Done. Save network } else { // Get the network state and start the network if required if (m_controller->networkState() == Deconz::NetworkStateConnected) { qCDebug(dcZigbeeNetwork()) << "The network is already running."; setState(StateRunning); + } else { + startNetwork(); } } }); @@ -340,20 +408,6 @@ void ZigbeeNetworkDeconz::startNetworkInternally() }); } -void ZigbeeNetworkDeconz::createNetwork() -{ - // Set offline - setCreateNetworkState(CreateNetworkStateStopNetwork); - - // Write configurations - - // Set online - - // Read configurations - - // Create and initialize coordinator node -} - void ZigbeeNetworkDeconz::onControllerAvailableChanged(bool available) { qCDebug(dcZigbeeNetwork()) << "Hardware controller is" << (available ? "now available" : "not available"); @@ -387,7 +441,7 @@ void ZigbeeNetworkDeconz::onPollNetworkStateTimeout() return; } - qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; + //qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; QDataStream stream(reply->responseData()); stream.setByteOrder(QDataStream::LittleEndian); quint8 deviceStateFlag = 0; @@ -409,12 +463,12 @@ void ZigbeeNetworkDeconz::onPollNetworkStateTimeout() ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState(); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not read device state during network start up." << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not read device state during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode(); // FIXME: set an appropriate error return; } - qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; + //qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully. SQN:" << reply->sequenceNumber(); QDataStream stream(reply->responseData()); stream.setByteOrder(QDataStream::LittleEndian); quint8 deviceStateFlag = 0; @@ -442,6 +496,42 @@ void ZigbeeNetworkDeconz::onPollNetworkStateTimeout() } } +void ZigbeeNetworkDeconz::onAspDataConfirmReceived(const DeconzApsDataConfirm &confirm) +{ + qCDebug(dcZigbeeNetwork()) << confirm; + + ZigbeeNetworkReply *reply = m_pendingReplies.take(confirm.requestId); + if (!reply) { + qCWarning(dcZigbeeNetwork()) << "Received confirmation but could not find any reply. Ignoring the confirmation"; + return; + } + + finishNetworkReply(reply, ZigbeeNetworkReply::ErrorNoError, static_cast(confirm.zigbeeStatusCode)); +} + +void ZigbeeNetworkDeconz::onAspDataIndicationReceived(const DeconzApsDataIndication &indication) +{ + qCDebug(dcZigbeeNetwork()) << indication; + + // Check if this indocation is related to any pending reply + if (indication.profileId == Zigbee::ZigbeeProfileDevice) { + handleZigbeeDeviceProfileIndication(indication); + return; + } + + // Find reply finish it + + qCDebug(dcZigbeeNetwork()) << "Unhandled indication" << indication; +} + +void ZigbeeNetworkDeconz::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities) +{ + qCDebug(dcZigbeeNetwork()) << "Device announced" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << ieeeAddress.toString() << ZigbeeUtils::convertByteToHexString(macCapabilities); + // Create node and initialize it + + +} + void ZigbeeNetworkDeconz::startNetwork() { loadNetwork(); @@ -466,12 +556,12 @@ void ZigbeeNetworkDeconz::stopNetwork() setState(StateStopping); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not leave network." << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not leave network. SQN:" << reply->sequenceNumber() << reply->statusCode(); // FIXME: set an appropriate error return; } - qCDebug(dcZigbeeNetwork()) << "Network left successfully"; + qCDebug(dcZigbeeNetwork()) << "Network left successfully. SQN:" << reply->sequenceNumber(); setState(StateOffline); }); } diff --git a/libnymea-zigbee/deconz/zigbeenetworkdeconz.h b/libnymea-zigbee/deconz/zigbeenetworkdeconz.h index d980d6e..3d726b2 100644 --- a/libnymea-zigbee/deconz/zigbeenetworkdeconz.h +++ b/libnymea-zigbee/deconz/zigbeenetworkdeconz.h @@ -53,7 +53,9 @@ public: ZigbeeBridgeController *bridgeController() const override; + ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) override; + quint8 generateSequenceNumber(); private: ZigbeeBridgeControllerDeconz *m_controller = nullptr; @@ -61,9 +63,16 @@ private: CreateNetworkState m_createState = CreateNetworkStateIdle; bool m_createNewNetwork = false; + QHash m_pendingReplies; + + quint8 m_sequenceNumber = 0; + QTimer *m_pollNetworkStateTimer = nullptr; void setCreateNetworkState(CreateNetworkState state); + void handleZigbeeDeviceProfileIndication(const DeconzApsDataIndication &indication); + + protected: ZigbeeNode *createNode(QObject *parent) override; @@ -71,12 +80,15 @@ protected: void startNetworkInternally(); - void createNetwork(); - private slots: void onControllerAvailableChanged(bool available); void onPollNetworkStateTimeout(); + void onAspDataConfirmReceived(const DeconzApsDataConfirm &confirm); + void onAspDataIndicationReceived(const DeconzApsDataIndication &indication); + + void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities); + public slots: void startNetwork() override; void stopNetwork() override; diff --git a/libnymea-zigbee/deconz/zigbeenodedeconz.cpp b/libnymea-zigbee/deconz/zigbeenodedeconz.cpp index 8cfad5e..c3374b3 100644 --- a/libnymea-zigbee/deconz/zigbeenodedeconz.cpp +++ b/libnymea-zigbee/deconz/zigbeenodedeconz.cpp @@ -26,10 +26,15 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "zigbeenodedeconz.h" +#include "zigbeedeviceprofile.h" +#include "zigbeenetworkdeconz.h" +#include "loggingcategory.h" -ZigbeeNodeDeconz::ZigbeeNodeDeconz(ZigbeeBridgeControllerDeconz *controller, QObject *parent) : +#include + +ZigbeeNodeDeconz::ZigbeeNodeDeconz(ZigbeeNetworkDeconz *network, QObject *parent) : ZigbeeNode(parent), - m_controller(controller) + m_network(network) { } @@ -47,6 +52,40 @@ void ZigbeeNodeDeconz::setClusterAttributeReport(const ZigbeeClusterAttributeRep void ZigbeeNodeDeconz::startInitialization() { + setState(StateInitializing); + + // Get the node descriptor + ZigbeeNetworkRequest request; + request.setRequestId(m_network->generateSequenceNumber()); + request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress); + request.setDestinationShortAddress(shortAddress()); + request.setDestinationEndpoint(0); // ZDO + request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP + request.setClusterId(ZigbeeDeviceProfile::NodeDescriptorRequest); + request.setSourceEndpoint(0); // ZDO + + // Build ASDU + QByteArray asdu; + QDataStream stream(&asdu, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << request.requestId() << request.destinationShortAddress(); + request.setAsdu(asdu); + + ZigbeeNetworkReply *reply = m_network->sendRequest(request); + connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){ + // TODO: check reply error + + ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData()); + qCDebug(dcZigbeeNode()) << "Node descriptor request finished" << adpu; + setNodeDescriptorRawData(reply->responseData()); + + QDataStream stream(adpu.payload); + stream.setByteOrder(QDataStream::LittleEndian); + + + + }); + /* Node initialisation steps (sequentially) * - Node descriptor * - Power descriptor diff --git a/libnymea-zigbee/deconz/zigbeenodedeconz.h b/libnymea-zigbee/deconz/zigbeenodedeconz.h index f46d2e7..f5a5ccb 100644 --- a/libnymea-zigbee/deconz/zigbeenodedeconz.h +++ b/libnymea-zigbee/deconz/zigbeenodedeconz.h @@ -32,7 +32,8 @@ #include "zigbee.h" #include "zigbeenode.h" -#include "zigbeebridgecontrollerdeconz.h" + +class ZigbeeNetworkDeconz; class ZigbeeNodeDeconz : public ZigbeeNode { @@ -41,12 +42,12 @@ class ZigbeeNodeDeconz : public ZigbeeNode friend class ZigbeeNetworkDeconz; public: - explicit ZigbeeNodeDeconz(ZigbeeBridgeControllerDeconz *controller, QObject *parent = nullptr); + explicit ZigbeeNodeDeconz(ZigbeeNetworkDeconz *network, QObject *parent = nullptr); void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) override; private: - ZigbeeBridgeControllerDeconz *m_controller = nullptr; + ZigbeeNetworkDeconz *m_network = nullptr; void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override; diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index 7a64985..0a4776a 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -23,7 +23,6 @@ SOURCES += \ zigbeechannelmask.cpp \ zigbeecluster.cpp \ zigbeeclusterattribute.cpp \ - zigbeedeviceobject.cpp \ zigbeedeviceprofile.cpp \ zigbeemanufacturer.cpp \ zigbeenetwork.cpp \ @@ -60,7 +59,6 @@ HEADERS += \ zigbeechannelmask.h \ zigbeecluster.h \ zigbeeclusterattribute.h \ - zigbeedeviceobject.h \ zigbeedeviceprofile.h \ zigbeemanufacturer.h \ zigbeenetwork.h \ diff --git a/libnymea-zigbee/nxp/zigbeenetworknxp.cpp b/libnymea-zigbee/nxp/zigbeenetworknxp.cpp index fee92ff..2e5a92e 100644 --- a/libnymea-zigbee/nxp/zigbeenetworknxp.cpp +++ b/libnymea-zigbee/nxp/zigbeenetworknxp.cpp @@ -265,6 +265,13 @@ void ZigbeeNetworkNxp::readPermitJoinStatus() }); } +ZigbeeNetworkReply *ZigbeeNetworkNxp::sendRequest(const ZigbeeNetworkRequest &request) +{ + Q_UNUSED(request) + qCCritical(dcZigbeeNetwork()) << "Cannot send request. Not implemented for this backend"; + return nullptr; +} + ZigbeeNode *ZigbeeNetworkNxp::createNode(QObject *parent) { return new ZigbeeNodeNxp(m_controller, parent); diff --git a/libnymea-zigbee/nxp/zigbeenetworknxp.h b/libnymea-zigbee/nxp/zigbeenetworknxp.h index 911e494..ad07c8f 100644 --- a/libnymea-zigbee/nxp/zigbeenetworknxp.h +++ b/libnymea-zigbee/nxp/zigbeenetworknxp.h @@ -62,6 +62,9 @@ private: void readControllerVersion(); void readPermitJoinStatus(); + + ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) override; + protected: ZigbeeNode *createNode(QObject *parent) override; void setPermitJoiningInternal(bool permitJoining) override; diff --git a/libnymea-zigbee/zigbeedeviceobject.cpp b/libnymea-zigbee/zigbeedeviceobject.cpp deleted file mode 100644 index 5e4532e..0000000 --- a/libnymea-zigbee/zigbeedeviceobject.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea-zigbee. -* 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 "zigbeedeviceobject.h" - -ZigbeeDeviceObject::ZigbeeDeviceObject(QObject *parent) : QObject(parent) -{ - -} diff --git a/libnymea-zigbee/zigbeedeviceobject.h b/libnymea-zigbee/zigbeedeviceobject.h deleted file mode 100644 index 04fa1dd..0000000 --- a/libnymea-zigbee/zigbeedeviceobject.h +++ /dev/null @@ -1,43 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea-zigbee. -* 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 ZIGBEEDEVICEOBJECT_H -#define ZIGBEEDEVICEOBJECT_H - -#include - -class ZigbeeDeviceObject : public QObject -{ - Q_OBJECT -public: - explicit ZigbeeDeviceObject(QObject *parent = nullptr); - -signals: - -}; - -#endif // ZIGBEEDEVICEOBJECT_H diff --git a/libnymea-zigbee/zigbeedeviceprofile.cpp b/libnymea-zigbee/zigbeedeviceprofile.cpp index 509a1cc..947d755 100644 --- a/libnymea-zigbee/zigbeedeviceprofile.cpp +++ b/libnymea-zigbee/zigbeedeviceprofile.cpp @@ -26,3 +26,28 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "zigbeedeviceprofile.h" +#include "zigbeeutils.h" + +#include + +ZigbeeDeviceProfileAdpu ZigbeeDeviceProfile::parseAdpu(const QByteArray &adpu) +{ + QDataStream stream(adpu); + stream.setByteOrder(QDataStream::LittleEndian); + + ZigbeeDeviceProfileAdpu deviceAdpu; + quint8 statusFlag = 0; + stream >> deviceAdpu.sequenceNumber >> statusFlag >> deviceAdpu.addressOfInterest; + deviceAdpu.status = static_cast(statusFlag); + deviceAdpu.payload = adpu.right(adpu.length() - 4); + return deviceAdpu; +} + +QDebug operator<<(QDebug debug, const ZigbeeDeviceProfileAdpu &deviceAdpu) +{ + debug.nospace() << "DeviceAdpu(SQN: " << deviceAdpu.sequenceNumber << ", "; + debug.nospace() << deviceAdpu.status << ", "; + debug.nospace() << ZigbeeUtils::convertUint16ToHexString(deviceAdpu.addressOfInterest) << ", "; + debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")"; + return debug.space(); +} diff --git a/libnymea-zigbee/zigbeedeviceprofile.h b/libnymea-zigbee/zigbeedeviceprofile.h index 1c810aa..c2c4cf7 100644 --- a/libnymea-zigbee/zigbeedeviceprofile.h +++ b/libnymea-zigbee/zigbeedeviceprofile.h @@ -28,14 +28,23 @@ #ifndef ZIGBEEDEVICEPROFILE_H #define ZIGBEEDEVICEPROFILE_H +#include #include +#include "zigbee.h" + +typedef struct ZigbeeDeviceProfileAdpu { + quint8 sequenceNumber = 0; + Zigbee::ZigbeeStatus status = Zigbee::ZigbeeStatusSuccess; + quint16 addressOfInterest = 0; + QByteArray payload; +} ZigbeeDeviceProfileAdpu; + class ZigbeeDeviceProfile { Q_GADGET public: - enum ZdoCommand { /* Requests */ /*Device and service discovery */ @@ -136,9 +145,11 @@ public: MgmtCacheResponse = 0x8037, MgmtNetworkUpdateResponse = 0x8038 }; + Q_ENUM(ZdoCommand) - - + static ZigbeeDeviceProfileAdpu parseAdpu(const QByteArray &adpu); }; +QDebug operator<<(QDebug debug, const ZigbeeDeviceProfileAdpu &deviceAdpu); + #endif // ZIGBEEDEVICEPROFILE_H diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index 57b86ec..586914b 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -378,6 +378,9 @@ void ZigbeeNetwork::saveNode(ZigbeeNode *node) settings.beginGroup(node->extendedAddress().toString()); settings.setValue("nwkAddress", node->shortAddress()); settings.setValue("macCapabilitiesFlag", node->m_macCapabilitiesFlag); + settings.setValue("manufacturerCode", node->m_manufacturerCode); + + settings.setValue("nodeDescriptorRawData", node->m_nodeDescriptorRawData); settings.setValue("powerDescriptorFlag", node->m_powerDescriptorFlag); @@ -491,6 +494,26 @@ bool ZigbeeNetwork::networkConfigurationAvailable() const return m_extendedPanId != 0 && m_channel != 0; } +ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest &request) +{ + ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this); + // Make sure the reply will be deleted + connect(reply, &ZigbeeNetworkReply::finished, reply, &ZigbeeNetworkReply::deleteLater); + return reply; +} + +void ZigbeeNetwork::setReplyResponseData(ZigbeeNetworkReply *reply, const QByteArray &responseData) +{ + reply->m_responseData = responseData; +} + +void ZigbeeNetwork::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error, Zigbee::ZigbeeStatus zigbeeStatus) +{ + reply->m_error = error; + reply->m_zigbeeStatus = zigbeeStatus; + reply->finished(); +} + void ZigbeeNetwork::onNodeStateChanged(ZigbeeNode::State state) { ZigbeeNode *node = qobject_cast(sender()); diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h index 1fbd959..f707cb3 100644 --- a/libnymea-zigbee/zigbeenetwork.h +++ b/libnymea-zigbee/zigbeenetwork.h @@ -94,6 +94,8 @@ public: bool permitJoining() const; void setPermitJoining(bool permitJoining); + + // Network nodes QList nodes() const; ZigbeeNode *coordinatorNode() const; @@ -150,6 +152,13 @@ protected: bool networkConfigurationAvailable() const; + virtual ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) = 0; + + // Network reply methods + ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest()); + void setReplyResponseData(ZigbeeNetworkReply *reply, const QByteArray &responseData); + void finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error = ZigbeeNetworkReply::ErrorNoError, Zigbee::ZigbeeStatus zigbeeStatus = Zigbee::ZigbeeStatusSuccess); + signals: void settingsFileNameChanged(const QString &settingsFileName); void serialPortNameChanged(const QString &serialPortName); diff --git a/libnymea-zigbee/zigbeenetworkreply.cpp b/libnymea-zigbee/zigbeenetworkreply.cpp index 7e44b52..56699e8 100644 --- a/libnymea-zigbee/zigbeenetworkreply.cpp +++ b/libnymea-zigbee/zigbeenetworkreply.cpp @@ -42,6 +42,11 @@ Zigbee::ZigbeeStatus ZigbeeNetworkReply::zigbeeStatus() const return m_zigbeeStatus; } +QByteArray ZigbeeNetworkReply::responseData() const +{ + return m_responseData; +} + ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent) : QObject(parent), m_request(request) diff --git a/libnymea-zigbee/zigbeenetworkreply.h b/libnymea-zigbee/zigbeenetworkreply.h index 9a7f5f7..b0bbe13 100644 --- a/libnymea-zigbee/zigbeenetworkreply.h +++ b/libnymea-zigbee/zigbeenetworkreply.h @@ -37,20 +37,25 @@ class ZigbeeNetworkReply : public QObject { Q_OBJECT + friend class ZigbeeNetwork; friend class ZigbeeNodeEndpoint; public: enum Error { ErrorNoError, ErrorZigbeeStatusError, + ErrorInterfaceError, ErrorNetworkOffline, + ErrorNetworkNotImplemented, ErrorUnknown }; Q_ENUM(Error) + Error error() const; ZigbeeNetworkRequest request() const; Zigbee::ZigbeeStatus zigbeeStatus() const; + QByteArray responseData() const; private: explicit ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr); @@ -59,6 +64,7 @@ private: bool m_finished = false; Error m_error = ErrorNoError; Zigbee::ZigbeeStatus m_zigbeeStatus = Zigbee::ZigbeeStatusSuccess; + QByteArray m_responseData; signals: void finished(); diff --git a/libnymea-zigbee/zigbeenode.h b/libnymea-zigbee/zigbeenode.h index 40fc968..8924af3 100644 --- a/libnymea-zigbee/zigbeenode.h +++ b/libnymea-zigbee/zigbeenode.h @@ -156,20 +156,6 @@ private: quint16 m_shortAddress = 0; ZigbeeAddress m_extendedAddress; - // Node descriptor information - QByteArray m_nodeDescriptorRawData; - NodeType m_nodeType = NodeTypeRouter; - FrequencyBand m_frequencyBand = FrequencyBand2400Mhz; - Relationship m_relationship = Parent; - quint16 m_manufacturerCode = 0; - - bool m_complexDescriptorAvailable = false; - bool m_userDescriptorAvailable = false; - - quint16 m_maximumRxSize = 0; - quint16 m_maximumTxSize = 0; - quint8 m_maximumBufferSize = 0; - // Server Mask quint16 m_serverMask = 0; bool m_isPrimaryTrustCenter = false; @@ -208,6 +194,20 @@ protected: QList m_endpoints; + // Node descriptor information + QByteArray m_nodeDescriptorRawData; + NodeType m_nodeType = NodeTypeRouter; + FrequencyBand m_frequencyBand = FrequencyBand2400Mhz; + Relationship m_relationship = Parent; + quint16 m_manufacturerCode = 0; + + bool m_complexDescriptorAvailable = false; + bool m_userDescriptorAvailable = false; + + quint16 m_maximumRxSize = 0; + quint16 m_maximumTxSize = 0; + quint8 m_maximumBufferSize = 0; + void setState(State state); void setConnected(bool connected);