diff --git a/docs/docs-05-3474-20-0csg-zigbee-specification.pdf b/docs/docs-05-3474-20-0csg-zigbee-specification.pdf deleted file mode 100644 index 5c7cf97..0000000 Binary files a/docs/docs-05-3474-20-0csg-zigbee-specification.pdf and /dev/null differ diff --git a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp index fa66231..1718d9b 100644 --- a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp +++ b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp @@ -296,7 +296,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData for (int i = 0; i < asdu.length(); i++) { stream << static_cast(asdu.at(i)); } - stream << static_cast(txOptions); // TX Options: Use ASP ACKs + stream << static_cast(txOptions); // TX Options: Use APS ACKs stream << radius; m_interface->sendPackage(message); @@ -337,7 +337,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData for (int i = 0; i < asdu.length(); i++) { stream << static_cast(asdu.at(i)); } - stream << static_cast(txOptions); // TX Options: Use ASP ACKs + stream << static_cast(txOptions); // TX Options: Use APS ACKs stream << radius; m_interface->sendPackage(message); @@ -347,6 +347,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(const ZigbeeNetworkRequest &request) { + qCDebug(dcZigbeeAps()) << "APSDE-DATA.request" << request; ZigbeeInterfaceDeconzReply *interfaceReply = nullptr; switch (request.destinationAddressMode()) { case Zigbee::DestinationAddressModeGroup: @@ -733,10 +734,10 @@ DeconzDeviceState ZigbeeBridgeControllerDeconz::parseDeviceStateFlag(quint8 devi { DeconzDeviceState state; state.networkState = static_cast(deviceStateFlag & 0x03); - state.aspDataConfirm = (deviceStateFlag & 0x04); - state.aspDataIndication = (deviceStateFlag & 0x08); + state.apsDataConfirm = (deviceStateFlag & 0x04); + state.apsDataIndication = (deviceStateFlag & 0x08); state.configurationChanged = (deviceStateFlag & 0x10); - state.aspDataRequestFreeSlots = (deviceStateFlag & 0x20); + state.apsDataRequestFreeSlots = (deviceStateFlag & 0x20); return state; } @@ -750,7 +751,7 @@ void ZigbeeBridgeControllerDeconz::readDataIndication() return; } - // ASP data indication received, process the content + // APS data indication received, process the content qCDebug(dcZigbeeController()) << "Reading data indication finished successfully"; processDataIndication(reply->responseData()); }); @@ -766,7 +767,7 @@ void ZigbeeBridgeControllerDeconz::readDataConfirm() return; } - // ASP data indication received, process the content + // APS data confirm received, process the content qCDebug(dcZigbeeController()) << "Reading data confirm finished successfully"; processDataConfirm(reply->responseData()); }); @@ -782,10 +783,10 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt emit networkStateChanged(m_networkState); } - if (m_aspFreeSlotsAvailable != deviceState.aspDataRequestFreeSlots) { - m_aspFreeSlotsAvailable = deviceState.aspDataRequestFreeSlots; + if (m_apsFreeSlotsAvailable != deviceState.apsDataRequestFreeSlots) { + m_apsFreeSlotsAvailable = deviceState.apsDataRequestFreeSlots; - // FIXME: if changed to true, send next asp data request + // FIXME: if changed to true, send next aps data request } @@ -795,12 +796,12 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt // 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) { + if (deviceState.apsDataIndication) { readDataIndication(); } // Check if we have a response to read for a request - if (deviceState.aspDataConfirm) { + if (deviceState.apsDataConfirm) { readDataConfirm(); } @@ -808,7 +809,7 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt void ZigbeeBridgeControllerDeconz::processDataIndication(const QByteArray &data) { - // ASP data indication + // APS data indication QDataStream stream(data); stream.setByteOrder(QDataStream::LittleEndian); quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 reserved = 0; quint16 asduLength = 0; @@ -843,13 +844,14 @@ void ZigbeeBridgeControllerDeconz::processDataIndication(const QByteArray &data) stream >> reserved >> reserved >> indication.lqi >> reserved >> reserved >> reserved >> reserved >> indication.rssi; // Print the information for debugging + qCDebug(dcZigbeeAps()) << "APSDE-DATA.indication" << indication; qCDebug(dcZigbeeController()) << indication; - emit aspDataIndicationReceived(indication); + emit apsDataIndicationReceived(indication); // Process the device state in order to check if we have to request another indication DeconzDeviceState deviceState = parseDeviceStateFlag(deviceStateFlag); - if (deviceState.aspDataIndication) { + if (deviceState.apsDataIndication) { readDataIndication(); } } @@ -873,12 +875,13 @@ void ZigbeeBridgeControllerDeconz::processDataConfirm(const QByteArray &data) // Print the information for debugging qCDebug(dcZigbeeController()) << confirm; + qCDebug(dcZigbeeAps()) << "APSDE-DATA.confirm" << confirm; - emit aspDataConfirmReceived(confirm); + emit apsDataConfirmReceived(confirm); // Process the device state in order to check if we have to request another indication DeconzDeviceState deviceState = parseDeviceStateFlag(deviceStateFlag); - if (deviceState.aspDataConfirm) { + if (deviceState.apsDataConfirm) { readDataConfirm(); } } @@ -996,16 +999,16 @@ QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState) break; } - debug.nospace() << "Confirm=" << static_cast(deviceState.aspDataConfirm) << ", "; - debug.nospace() << "Indication=" << static_cast(deviceState.aspDataIndication) << ", "; + debug.nospace() << "Confirm=" << static_cast(deviceState.apsDataConfirm) << ", "; + debug.nospace() << "Indication=" << static_cast(deviceState.apsDataIndication) << ", "; debug.nospace() << "ConfigChanged=" << static_cast(deviceState.configurationChanged) << ", "; - debug.nospace() << "CanSend=" << deviceState.aspDataRequestFreeSlots << ")"; + debug.nospace() << "CanSend=" << deviceState.apsDataRequestFreeSlots << ")"; return debug.space(); } QDebug operator<<(QDebug debug, const DeconzApsDataConfirm &confirm) { - debug.nospace() << "ASP.Confirm("; + debug.nospace() << "APSDE-DATA.confirm("; debug.nospace() << "Request ID: " << confirm.requestId << ", "; if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeGroup) @@ -1027,7 +1030,7 @@ QDebug operator<<(QDebug debug, const DeconzApsDataConfirm &confirm) QDebug operator<<(QDebug debug, const DeconzApsDataIndication &indication) { - debug.nospace() << "ASP.Indication("; + debug.nospace() << "APSDE-DATA.indication("; if (indication.destinationAddressMode == Zigbee::DestinationAddressModeGroup) debug.nospace() << "Group address:" << ZigbeeUtils::convertUint16ToHexString(indication.destinationShortAddress) << ", "; @@ -1067,7 +1070,7 @@ QDebug operator<<(QDebug debug, const DeconzNetworkConfiguration &configuration) debug.nospace() << " - NWK address:" << ZigbeeUtils::convertUint16ToHexString(configuration.shortAddress) << endl; debug.nospace() << " - PAN ID:" << ZigbeeUtils::convertUint16ToHexString(configuration.panId) << endl; debug.nospace() << " - Extended PAN ID:" << ZigbeeUtils::convertUint64ToHexString(configuration.extendedPanId) << endl; - debug.nospace() << " - ASP Extended PAN ID:" << ZigbeeUtils::convertUint64ToHexString(configuration.apsExtendedPanId) << endl; + debug.nospace() << " - APS Extended PAN ID:" << ZigbeeUtils::convertUint64ToHexString(configuration.apsExtendedPanId) << endl; debug.nospace() << " - Trust center IEEE address:" << configuration.trustCenterAddress.toString() << endl; debug.nospace() << " - Channel mask:" << ZigbeeChannelMask(configuration.channelMask) << endl; debug.nospace() << " - Channel:" << configuration.currentChannel << endl; diff --git a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h index 510aada..70856f4 100644 --- a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h +++ b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h @@ -61,14 +61,13 @@ typedef struct DeconzNetworkConfiguration { } DeconzNetworkConfiguration; - // This struct describes the deCONZ device state typedef struct DeconzDeviceState { Deconz::NetworkState networkState = Deconz::NetworkStateOffline; - bool aspDataConfirm = false; - bool aspDataIndication = false; + bool apsDataConfirm = false; + bool apsDataIndication = false; bool configurationChanged = false; - bool aspDataRequestFreeSlots = false; + bool apsDataRequestFreeSlots = false; } DeconzDeviceState; @@ -141,7 +140,7 @@ private: Deconz::NetworkState m_networkState = Deconz::NetworkStateOffline; QTimer *m_watchdogTimer = nullptr; - bool m_aspFreeSlotsAvailable = false; + bool m_apsFreeSlotsAvailable = false; quint8 generateSequenceNumber(); @@ -165,8 +164,8 @@ signals: void networkStateChanged(Deconz::NetworkState networkState); void networkConfigurationParameterChanged(const DeconzNetworkConfiguration &networkConfiguration); - void aspDataConfirmReceived(const DeconzApsDataConfirm &confirm); - void aspDataIndicationReceived(const DeconzApsDataIndication &indication); + void apsDataConfirmReceived(const DeconzApsDataConfirm &confirm); + void apsDataIndicationReceived(const DeconzApsDataIndication &indication); private slots: void onInterfaceAvailableChanged(bool available); diff --git a/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp b/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp index 22d1ceb..cbc3d04 100644 --- a/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp +++ b/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp @@ -38,8 +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); + connect(m_controller, &ZigbeeBridgeControllerDeconz::apsDataConfirmReceived, this, &ZigbeeNetworkDeconz::onApsDataConfirmReceived); + connect(m_controller, &ZigbeeBridgeControllerDeconz::apsDataIndicationReceived, this, &ZigbeeNetworkDeconz::onApsDataIndicationReceived); m_pollNetworkStateTimer = new QTimer(this); m_pollNetworkStateTimer->setInterval(1000); @@ -70,7 +70,12 @@ ZigbeeNetworkReply *ZigbeeNetworkDeconz::sendRequest(const ZigbeeNetworkRequest m_pendingReplies.remove(request.requestId()); }); - qCDebug(dcZigbeeNetwork()) << "Send request" << request; + // Finish the reply right the way if the network is offline + if (!m_controller->available()) { + finishNetworkReply(reply, ZigbeeNetworkReply::ErrorNetworkOffline); + return reply; + } + ZigbeeInterfaceDeconzReply *interfaceReply = m_controller->requestSendRequest(request); connect(interfaceReply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply, interfaceReply](){ if (interfaceReply->statusCode() != Deconz::StatusCodeSuccess) { @@ -285,13 +290,11 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo return; } - ZigbeeNodeDeconz *coordinatorNode = qobject_cast(createNode(this)); - coordinatorNode->setShortAddress(m_controller->networkConfiguration().shortAddress); - coordinatorNode->setExtendedAddress(m_controller->networkConfiguration().ieeeAddress); + ZigbeeNode *coordinatorNode = createNode(m_controller->networkConfiguration().shortAddress, m_controller->networkConfiguration().ieeeAddress, this); m_coordinatorNode = coordinatorNode; // Network creation done when coordinator node is initialized - connect(coordinatorNode, &ZigbeeNodeDeconz::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){ + connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){ if (state == ZigbeeNode::StateInitialized) { qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode; setState(StateRunning); @@ -317,31 +320,39 @@ void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const DeconzApsDat return; } - foreach (ZigbeeNetworkReply *reply, m_pendingReplies.values()) { - // Check if this is a response for a ZDO request - 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()) { - // 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 *node = getZigbeeNode(indication.sourceShortAddress); + if (!node) { + qCWarning(dcZigbeeNetwork()) << "Received a ZDO indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; + return; } - qCWarning(dcZigbeeNetwork()) << "FIXME: Unhandled ZDO indication" << indication; + node->deviceObject()->processApsDataIndication(indication.destinationEndpoint, indication.sourceEndpoint, indication.clusterId, indication.asdu, indication.lqi, indication.rssi); + +// foreach (ZigbeeNetworkReply *reply, m_pendingReplies.values()) { +// // Check if this is a reply if for a ZDO request +// 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 +// ZigbeeDeviceProfile::Adpu deviceAdpu = ZigbeeDeviceProfile::parseAdpu(indication.asdu); +// if (deviceAdpu.transactionSequenceNumber == reply->request().requestId()) { +// // 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; +// } +// } +// } +// } + + //qCWarning(dcZigbeeNetwork()) << "FIXME: Unhandled ZDO indication" << indication; } void ZigbeeNetworkDeconz::handleZigbeeHomeAutomationIndication(const DeconzApsDataIndication &indication) @@ -352,11 +363,6 @@ void ZigbeeNetworkDeconz::handleZigbeeHomeAutomationIndication(const DeconzApsDa -} - -ZigbeeNode *ZigbeeNetworkDeconz::createNode(QObject *parent) -{ - return new ZigbeeNodeDeconz(this, parent); } void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining) @@ -371,7 +377,7 @@ void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining) ZigbeeNetworkReply *reply = setPermitJoin(Zigbee::BroadcastAddressAllRouters, duration); connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply, permitJoining, duration](){ - if (reply->zigbeeStatus() != Zigbee::ZigbeeStatusSuccess) { + if (reply->zigbeeApsStatus() != Zigbee::ZigbeeApsStatusSuccess) { qCDebug(dcZigbeeNetwork()) << "Could not set permit join to" << duration; m_permitJoining = false; emit permitJoiningChanged(m_permitJoining); @@ -598,23 +604,19 @@ void ZigbeeNetworkDeconz::onPermitJoinRefreshTimout() setPermitJoiningInternal(true); } -void ZigbeeNetworkDeconz::onAspDataConfirmReceived(const DeconzApsDataConfirm &confirm) +void ZigbeeNetworkDeconz::onApsDataConfirmReceived(const DeconzApsDataConfirm &confirm) { - qCDebug(dcZigbeeNetwork()) << confirm; - ZigbeeNetworkReply *reply = m_pendingReplies.value(confirm.requestId); if (!reply) { qCWarning(dcZigbeeNetwork()) << "Received confirmation but could not find any reply. Ignoring the confirmation"; return; } - setReplyResponseError(reply, static_cast(confirm.zigbeeStatusCode)); + setReplyResponseError(reply, static_cast(confirm.zigbeeStatusCode)); } -void ZigbeeNetworkDeconz::onAspDataIndicationReceived(const DeconzApsDataIndication &indication) +void ZigbeeNetworkDeconz::onApsDataIndicationReceived(const DeconzApsDataIndication &indication) { - qCDebug(dcZigbeeNetwork()) << indication; - // Check if this indocation is related to any pending reply if (indication.profileId == Zigbee::ZigbeeProfileDevice) { handleZigbeeDeviceProfileIndication(indication); @@ -644,10 +646,7 @@ void ZigbeeNetworkDeconz::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress return; } - ZigbeeNodeDeconz *node = static_cast(createNode(this)); - node->setExtendedAddress(ieeeAddress); - node->setShortAddress(shortAddress); - node->setMacCapabilitiesFlag(macCapabilities); + ZigbeeNode *node = createNode(shortAddress, ieeeAddress, macCapabilities, this); addUnitializedNode(node); node->startInitialization(); } diff --git a/libnymea-zigbee/deconz/zigbeenetworkdeconz.h b/libnymea-zigbee/deconz/zigbeenetworkdeconz.h index 1cbae37..27020c1 100644 --- a/libnymea-zigbee/deconz/zigbeenetworkdeconz.h +++ b/libnymea-zigbee/deconz/zigbeenetworkdeconz.h @@ -31,7 +31,6 @@ #include #include "zigbeenetwork.h" -#include "zigbeenodedeconz.h" #include "zigbeechannelmask.h" #include "zigbeeclusterlibrary.h" #include "zigbeebridgecontrollerdeconz.h" @@ -54,6 +53,7 @@ public: ZigbeeBridgeController *bridgeController() const override; + // Sending an APSDE-DATA.request, will be finished on APSDE-DATA.confirm ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) override; ZigbeeNetworkReply *setPermitJoin(quint16 shortAddress, quint8 duration); @@ -82,10 +82,7 @@ private: // GP protected: - ZigbeeNode *createNode(QObject *parent) override; - void setPermitJoiningInternal(bool permitJoining) override; - void startNetworkInternally(); private slots: @@ -93,8 +90,8 @@ private slots: void onPollNetworkStateTimeout(); void onPermitJoinRefreshTimout(); - void onAspDataConfirmReceived(const DeconzApsDataConfirm &confirm); - void onAspDataIndicationReceived(const DeconzApsDataIndication &indication); + void onApsDataConfirmReceived(const DeconzApsDataConfirm &confirm); + void onApsDataIndicationReceived(const DeconzApsDataIndication &indication); void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities); diff --git a/libnymea-zigbee/deconz/zigbeenodedeconz.cpp b/libnymea-zigbee/deconz/zigbeenodedeconz.cpp deleted file mode 100644 index c9b7558..0000000 --- a/libnymea-zigbee/deconz/zigbeenodedeconz.cpp +++ /dev/null @@ -1,429 +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 "zigbeeutils.h" -#include "zigbeenodedeconz.h" -#include "zdo/zigbeedeviceprofile.h" -#include "zigbeenetworkdeconz.h" -#include "zigbeenodeendpointdeconz.h" - -#include "loggingcategory.h" - -#include - -ZigbeeNodeDeconz::ZigbeeNodeDeconz(ZigbeeNetworkDeconz *network, QObject *parent) : - ZigbeeNode(network, parent), - m_network(network) -{ - -} - -ZigbeeNetworkReply *ZigbeeNodeDeconz::requestNodeDescriptor() -{ - // 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); - - // We expect an indication with the response and the confirmation - request.setExpectIndication(true); - return m_network->sendRequest(request); -} - -ZigbeeNetworkReply *ZigbeeNodeDeconz::requestPowerDescriptor() -{ - // Get the power 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::PowerDescriptorRequest); - 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); - - // We expect an indication with the response and the confirmation - request.setExpectIndication(true); - return m_network->sendRequest(request); -} - -ZigbeeNetworkReply *ZigbeeNodeDeconz::requestActiveEndpoints() -{ - // Get the power 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::ActiveEndpointsRequest); - 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); - - // We expect an indication with the response and the confirmation - request.setExpectIndication(true); - return m_network->sendRequest(request); -} - -ZigbeeNetworkReply *ZigbeeNodeDeconz::requestSimpleDescriptor(quint8 endpoint) -{ - // Get the power 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::SimpleDescriptorRequest); - request.setSourceEndpoint(0); // ZDO - - // Build ASDU - QByteArray asdu; - QDataStream stream(&asdu, QIODevice::WriteOnly); - stream.setByteOrder(QDataStream::LittleEndian); - stream << request.requestId() << request.destinationShortAddress() << endpoint; - request.setAsdu(asdu); - - // We expect an indication with the response and the confirmation - request.setExpectIndication(true); - return m_network->sendRequest(request); -} - -ZigbeeNetworkReply *ZigbeeNodeDeconz::requestLeaveNetwork(bool rejoin, bool removeChildren) -{ - 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::MgmtLeaveRequest); - request.setSourceEndpoint(0); // ZDO - - // Build ASDU - QByteArray asdu; - quint8 leaveFlag = 0; - if (rejoin) { - leaveFlag |= 0x01; - } - - if (removeChildren) { - leaveFlag |= 0x02; - } - - QDataStream stream(&asdu, QIODevice::WriteOnly); - stream.setByteOrder(QDataStream::LittleEndian); - stream << request.requestId() << extendedAddress().toUInt64() << leaveFlag; - request.setAsdu(asdu); - - // We expect an indication with the response and the confirmation - request.setExpectIndication(true); - return m_network->sendRequest(request); -} - -void ZigbeeNodeDeconz::leaveNetworkRequest(bool rejoin, bool removeChildren) -{ - ZigbeeNetworkReply *reply = requestLeaveNetwork(rejoin, removeChildren); - connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){ - // TODO: check reply error - - }); -} - -void ZigbeeNodeDeconz::initNodeDescriptor() -{ - ZigbeeNetworkReply *reply = requestNodeDescriptor(); - connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){ - // TODO: check reply error - - ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData()); - qCDebug(dcZigbeeNode()) << "Node descriptor request finished" << adpu; - QDataStream stream(adpu.payload); - stream.setByteOrder(QDataStream::LittleEndian); - quint8 typeDescriptorFlag = 0; quint8 frequencyFlag = 0; quint8 macCapabilities = 0; - quint16 serverMask = 0; - quint8 descriptorCapabilities = 0; - - stream >> typeDescriptorFlag >> frequencyFlag >> macCapabilities >> m_manufacturerCode >> m_maximumBufferSize; - stream >> m_maximumRxSize >> serverMask >> m_maximumTxSize >> descriptorCapabilities; - - // 0-2 Bit = logical type, 0 = coordinator, 1 = router, 2 = end device - if (!ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) { - m_nodeType = NodeTypeCoordinator; - } else if (!ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) { - m_nodeType = NodeTypeRouter; - } else if (ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) { - m_nodeType = NodeTypeEndDevice; - } - - m_complexDescriptorAvailable = (typeDescriptorFlag >> 3) & 0x0001; - m_userDescriptorAvailable = (typeDescriptorFlag >> 4) & 0x0001; - - // Frequency band, 5 bits - if (ZigbeeUtils::checkBitUint8(frequencyFlag, 3)) { - m_frequencyBand = FrequencyBand868Mhz; - } else if (ZigbeeUtils::checkBitUint8(frequencyFlag, 5)) { - m_frequencyBand = FrequencyBand902Mhz; - } else if (ZigbeeUtils::checkBitUint8(frequencyFlag, 6)) { - m_frequencyBand = FrequencyBand2400Mhz; - } - - setMacCapabilitiesFlag(macCapabilities); - setServerMask(serverMask); - setDescriptorFlag(descriptorCapabilities); - - qCDebug(dcZigbeeNode()) << "Node descriptor:" << ZigbeeUtils::convertUint16ToHexString(shortAddress()) << extendedAddress().toString(); - qCDebug(dcZigbeeNode()) << " Node type:" << nodeType(); - qCDebug(dcZigbeeNode()) << " Complex desciptor available:" << complexDescriptorAvailable(); - qCDebug(dcZigbeeNode()) << " User desciptor available:" << userDescriptorAvailable(); - qCDebug(dcZigbeeNode()) << " Frequency band:" << frequencyBand(); - qCDebug(dcZigbeeNode()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(m_manufacturerCode); - qCDebug(dcZigbeeNode()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximumRxSize) << "(" << m_maximumRxSize << ")"; - qCDebug(dcZigbeeNode()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximumTxSize) << "(" << m_maximumTxSize << ")"; - qCDebug(dcZigbeeNode()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(m_maximumBufferSize) << "(" << m_maximumBufferSize << ")"; - qCDebug(dcZigbeeNode()) << " Server mask:" << ZigbeeUtils::convertUint16ToHexString(serverMask); - qCDebug(dcZigbeeNode()) << " Primary Trust center:" << isPrimaryTrustCenter(); - qCDebug(dcZigbeeNode()) << " Backup Trust center:" << isBackupTrustCenter(); - qCDebug(dcZigbeeNode()) << " Primary Binding cache:" << isPrimaryBindingCache(); - qCDebug(dcZigbeeNode()) << " Backup Binding cache:" << isBackupBindingCache(); - qCDebug(dcZigbeeNode()) << " Primary Discovery cache:" << isPrimaryDiscoveryCache(); - qCDebug(dcZigbeeNode()) << " Backup Discovery cache:" << isBackupDiscoveryCache(); - qCDebug(dcZigbeeNode()) << " Network Manager:" << isNetworkManager(); - qCDebug(dcZigbeeNode()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorCapabilities); - qCDebug(dcZigbeeNode()) << " Extended active endpoint list available:" << extendedActiveEndpointListAvailable(); - qCDebug(dcZigbeeNode()) << " Extended simple descriptor list available:" << extendedSimpleDescriptorListAvailable(); - qCDebug(dcZigbeeNode()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macCapabilities); - qCDebug(dcZigbeeNode()) << " Alternate PAN coordinator:" << alternatePanCoordinator(); - qCDebug(dcZigbeeNode()) << " Device type:" << deviceType(); - qCDebug(dcZigbeeNode()) << " Power source flag main power:" << powerSourceFlagMainPower(); - qCDebug(dcZigbeeNode()) << " Receiver on when idle:" << receiverOnWhenIdle(); - qCDebug(dcZigbeeNode()) << " Security capability:" << securityCapability(); - qCDebug(dcZigbeeNode()) << " Allocate address:" << allocateAddress(); - - - // Continue with the power descriptor - initPowerDescriptor(); - }); -} - -void ZigbeeNodeDeconz::initPowerDescriptor() -{ - ZigbeeNetworkReply *reply = requestPowerDescriptor(); - connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){ - // TODO: check reply error - - ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData()); - qCDebug(dcZigbeeNode()) << "Power descriptor request finished" << this << adpu; - QDataStream stream(adpu.payload); - stream.setByteOrder(QDataStream::LittleEndian); - quint16 powerDescriptorFlag = 0; - stream >> powerDescriptorFlag; - setPowerDescriptorFlag(powerDescriptorFlag); - - // Continue with endpoint fetching - initEndpoints(); - }); -} - -void ZigbeeNodeDeconz::initEndpoints() -{ - ZigbeeNetworkReply *reply = requestActiveEndpoints(); - connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){ - // TODO: check reply error - - ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData()); - qCDebug(dcZigbeeNode()) << "Active endpoints request finished" << this << adpu; - QDataStream stream(adpu.payload); - stream.setByteOrder(QDataStream::LittleEndian); - quint8 endpointCount = 0; - m_uninitializedEndpoints.clear(); - stream >> endpointCount; - for (int i = 0; i < endpointCount; i++) { - quint8 endpoint = 0; - stream >> endpoint; - m_uninitializedEndpoints.append(endpoint); - } - - qCDebug(dcZigbeeNode()) << "Endpoints" << endpointCount; - for (int i = 0; i < m_uninitializedEndpoints.count(); i++) { - qCDebug(dcZigbeeNode()) << " -" << ZigbeeUtils::convertByteToHexString(m_uninitializedEndpoints.at(i)); - } - - // Read simple descriptor for each endpoint - if (m_uninitializedEndpoints.isEmpty()) { - initBasicCluster(); - } - - for (int i = 0; i < m_uninitializedEndpoints.count(); i++) { - quint8 endpointId = m_uninitializedEndpoints.at(i); - qCDebug(dcZigbeeNode()) << "Read simple descriptor of endpoint" << ZigbeeUtils::convertByteToHexString(endpointId); - ZigbeeNetworkReply *reply = requestSimpleDescriptor(endpointId); - connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply, endpointId](){ - // TODO: check reply error - ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData()); - qCDebug(dcZigbeeNode()) << "Simple descriptor request finished" << this << endpointId << adpu; - - QDataStream stream(adpu.payload); - stream.setByteOrder(QDataStream::LittleEndian); - quint8 length = 0; - quint8 endpointId = 0; - quint16 profileId = 0; - quint16 deviceId = 0; - quint8 deviceVersion = 0; - quint8 inputClusterCount = 0; - quint8 outputClusterCount = 0; - - QList inputClusters; - QList outputClusters; - - stream >> length >> endpointId >> profileId >> deviceId >> deviceVersion >> inputClusterCount; - - qCDebug(dcZigbeeNode()) << "Node endpoint simple descriptor:"; - qCDebug(dcZigbeeNode()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); - qCDebug(dcZigbeeNode()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endpointId); - qCDebug(dcZigbeeNode()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); - if (profileId == Zigbee::ZigbeeProfileLightLink) { - qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); - } else if (profileId == Zigbee::ZigbeeProfileHomeAutomation) { - qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); - } else if (profileId == Zigbee::ZigbeeProfileGreenPower) { - qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); - } - - qCDebug(dcZigbeeNode()) << " Device version:" << ZigbeeUtils::convertByteToHexString(deviceVersion); - - // Create endpoint - ZigbeeNodeEndpointDeconz *endpoint = nullptr; - if (!hasEndpoint(endpointId)) { - endpoint = qobject_cast(createNodeEndpoint(endpointId, this)); - m_endpoints.append(endpoint); - } else { - endpoint = qobject_cast(getEndpoint(endpointId)); - } - endpoint->setProfile(static_cast(profileId)); - endpoint->setDeviceId(deviceId); - endpoint->setDeviceVersion(deviceVersion); - - qCDebug(dcZigbeeNode()) << " Input clusters: (" << inputClusterCount << ")"; - for (int i = 0; i < inputClusterCount; i++) { - quint16 clusterId = 0; - stream >> clusterId; - if (!endpoint->hasInputCluster(static_cast(clusterId))) { - endpoint->addInputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast(clusterId), ZigbeeCluster::Input, endpoint)); - } - qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); - - } - stream >> outputClusterCount; - - qCDebug(dcZigbeeNode()) << " Output clusters: (" << outputClusterCount << ")"; - for (int i = 0; i < outputClusterCount; i++) { - quint16 clusterId = 0; - stream >> clusterId; - if (!endpoint->hasOutputCluster(static_cast(clusterId))) { - endpoint->addOutputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast(clusterId), ZigbeeCluster::Output, endpoint)); - } - qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); - } - - m_uninitializedEndpoints.removeAll(endpointId); - - if (m_uninitializedEndpoints.isEmpty()) { - // Continue with the basic cluster attributes - initBasicCluster(); - } - }); - } - }); -} - -void ZigbeeNodeDeconz::initBasicCluster() -{ - - // TODO - - setState(StateInitialized); -} - -void ZigbeeNodeDeconz::setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) -{ - Q_UNUSED(report) -} - -void ZigbeeNodeDeconz::startInitialization() -{ - setState(StateInitializing); - - /* Node initialisation steps (sequentially) - * - Node descriptor - * - Power descriptor - * - Active endpoints - * - for each endpoint do: - * - Simple descriptor request - * - for each endpoint - * - read basic cluster - */ - - initNodeDescriptor(); - - /* - - - }); - }); - */ -} - -ZigbeeNodeEndpoint *ZigbeeNodeDeconz::createNodeEndpoint(quint8 endpointId, QObject *parent) -{ - return qobject_cast(new ZigbeeNodeEndpointDeconz(m_network, this, endpointId, parent)); -} diff --git a/libnymea-zigbee/deconz/zigbeenodedeconz.h b/libnymea-zigbee/deconz/zigbeenodedeconz.h deleted file mode 100644 index f53a08f..0000000 --- a/libnymea-zigbee/deconz/zigbeenodedeconz.h +++ /dev/null @@ -1,80 +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 ZIGBEENODEDECONZ_H -#define ZIGBEENODEDECONZ_H - -#include - -#include "zigbee.h" -#include "zigbeenode.h" - -class ZigbeeNodeEndpoint; -class ZigbeeNetworkDeconz; - -class ZigbeeNodeDeconz : public ZigbeeNode -{ - Q_OBJECT - - friend class ZigbeeNetworkDeconz; - -public: - explicit ZigbeeNodeDeconz(ZigbeeNetworkDeconz *network, QObject *parent = nullptr); - - ZigbeeNetworkReply *requestNodeDescriptor(); - ZigbeeNetworkReply *requestPowerDescriptor(); - ZigbeeNetworkReply *requestActiveEndpoints(); - ZigbeeNetworkReply *requestSimpleDescriptor(quint8 endpoint); - - ZigbeeNetworkReply *requestLeaveNetwork(bool rejoin = false, bool removeChildren = false); - - void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) override; - -private: - ZigbeeNetworkDeconz *m_network = nullptr; - - // Init methods - void initNodeDescriptor(); - void initPowerDescriptor(); - void initEndpoints(); - void initBasicCluster(); - - QList m_uninitializedEndpoints; - QList m_uninitalizedBasicClusterAttributes; - - void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override; - -protected: - void startInitialization() override; - ZigbeeNodeEndpoint *createNodeEndpoint(quint8 endpointId, QObject *parent) override; - -private slots: - - -}; - -#endif // ZIGBEENODEDECONZ_H diff --git a/libnymea-zigbee/deconz/zigbeenodeendpointdeconz.cpp b/libnymea-zigbee/deconz/zigbeenodeendpointdeconz.cpp deleted file mode 100644 index 3956aac..0000000 --- a/libnymea-zigbee/deconz/zigbeenodeendpointdeconz.cpp +++ /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 -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "zigbeenodeendpointdeconz.h" -#include "zigbeenodeendpoint.h" - -ZigbeeNodeEndpointDeconz::ZigbeeNodeEndpointDeconz(ZigbeeNetworkDeconz *network, ZigbeeNode *node, quint8 endpointId, QObject *parent) : - ZigbeeNodeEndpoint(node, endpointId, parent), - m_network(network), - m_node(node) -{ - -} - -void ZigbeeNodeEndpointDeconz::setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute) -{ - Q_UNUSED(clusterId) - Q_UNUSED(attribute) -} diff --git a/libnymea-zigbee/deconz/zigbeenodeendpointdeconz.h b/libnymea-zigbee/deconz/zigbeenodeendpointdeconz.h deleted file mode 100644 index 78f8879..0000000 --- a/libnymea-zigbee/deconz/zigbeenodeendpointdeconz.h +++ /dev/null @@ -1,59 +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 ZIGBEENODEENDPOINTDECONZ_H -#define ZIGBEENODEENDPOINTDECONZ_H - -#include -#include "zigbeenodeendpoint.h" -#include "zigbeeclusterlibrary.h" - -class ZigbeeNodeDeconz; -class ZigbeeNetworkDeconz; - -class ZigbeeNodeEndpointDeconz : public ZigbeeNodeEndpoint -{ - Q_OBJECT - - friend class ZigbeeNodeDeconz; - -public: - explicit ZigbeeNodeEndpointDeconz(ZigbeeNetworkDeconz *network, ZigbeeNode *node, quint8 endpointId, QObject *parent = nullptr); - -protected: - // Cluster commands - void setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute = ZigbeeClusterAttribute()) override; - -private: - ZigbeeNetworkDeconz *m_network = nullptr; - ZigbeeNode *m_node = nullptr; - -signals: - -}; - -#endif // ZIGBEENODEENDPOINTDECONZ_H diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index 98ac205..95949c1 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -8,8 +8,6 @@ SOURCES += \ deconz/interface/zigbeeinterfacedeconzreply.cpp \ deconz/zigbeebridgecontrollerdeconz.cpp \ deconz/zigbeenetworkdeconz.cpp \ - deconz/zigbeenodedeconz.cpp \ - deconz/zigbeenodeendpointdeconz.cpp \ # nxp/interface/zigbeeinterface.cpp \ # nxp/interface/zigbeeinterfacemessage.cpp \ # nxp/interface/zigbeeinterfacerequest.cpp \ @@ -19,9 +17,9 @@ SOURCES += \ # nxp/zigbeenodeendpointnxp.cpp \ # nxp/zigbeenodenxp.cpp \ zcl/zigbeeclusterbasic.cpp \ + zcl/zigbeeclusterreply.cpp \ zdo/zigbeedeviceobject.cpp \ zdo/zigbeedeviceobjectreply.cpp \ - zdo/zigbeedeviceprofilehandler.cpp \ zdo/zigbeedeviceprofile.cpp \ zigbeeadpu.cpp \ zigbeebridgecontroller.cpp \ @@ -52,8 +50,6 @@ HEADERS += \ deconz/interface/zigbeeinterfacedeconzreply.h \ deconz/zigbeebridgecontrollerdeconz.h \ deconz/zigbeenetworkdeconz.h \ - deconz/zigbeenodedeconz.h \ - deconz/zigbeenodeendpointdeconz.h \ # nxp/interface/zigbeeinterface.h \ # nxp/interface/zigbeeinterfacemessage.h \ # nxp/interface/zigbeeinterfacerequest.h \ @@ -63,9 +59,9 @@ HEADERS += \ # nxp/zigbeenodeendpointnxp.h \ # nxp/zigbeenodenxp.h \ zcl/zigbeeclusterbasic.h \ + zcl/zigbeeclusterreply.h \ zdo/zigbeedeviceobject.h \ zdo/zigbeedeviceobjectreply.h \ - zdo/zigbeedeviceprofilehandler.h \ zdo/zigbeedeviceprofile.h \ zigbeeadpu.h \ zigbeebridgecontroller.h \ diff --git a/libnymea-zigbee/loggingcategory.cpp b/libnymea-zigbee/loggingcategory.cpp index 98d6842..092d9b4 100644 --- a/libnymea-zigbee/loggingcategory.cpp +++ b/libnymea-zigbee/loggingcategory.cpp @@ -29,8 +29,10 @@ Q_LOGGING_CATEGORY(dcZigbeeNetwork, "ZigbeeNetwork") Q_LOGGING_CATEGORY(dcZigbeeNode, "ZigbeeNode") +Q_LOGGING_CATEGORY(dcZigbeeAps, "ZigbeeAps") Q_LOGGING_CATEGORY(dcZigbeeCluster, "ZigbeeCluster") Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface") Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController") +Q_LOGGING_CATEGORY(dcZigbeeDeviceObject, "ZigbeeDeviceObject") Q_LOGGING_CATEGORY(dcZigbeeNetworkDatabase, "ZigbeeNetworkDatabase") Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic") diff --git a/libnymea-zigbee/loggingcategory.h b/libnymea-zigbee/loggingcategory.h index 5cae2fe..b24c6ca 100644 --- a/libnymea-zigbee/loggingcategory.h +++ b/libnymea-zigbee/loggingcategory.h @@ -33,9 +33,11 @@ Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetwork) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNode) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeAps) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeCluster) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeDeviceObject) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetworkDatabase) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic) diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp new file mode 100644 index 0000000..42f863d --- /dev/null +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp @@ -0,0 +1,6 @@ +#include "zigbeeclusterreply.h" + +ZigbeeClusterReply::ZigbeeClusterReply(QObject *parent) : QObject(parent) +{ + +} diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.h b/libnymea-zigbee/zcl/zigbeeclusterreply.h new file mode 100644 index 0000000..ebc4c1e --- /dev/null +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.h @@ -0,0 +1,16 @@ +#ifndef ZIGBEECLUSTERREPLY_H +#define ZIGBEECLUSTERREPLY_H + +#include + +class ZigbeeClusterReply : public QObject +{ + Q_OBJECT +public: + explicit ZigbeeClusterReply(QObject *parent = nullptr); + +signals: + +}; + +#endif // ZIGBEECLUSTERREPLY_H diff --git a/libnymea-zigbee/zdo/zigbeedeviceobject.cpp b/libnymea-zigbee/zdo/zigbeedeviceobject.cpp index 77dafb6..51bb29e 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobject.cpp +++ b/libnymea-zigbee/zdo/zigbeedeviceobject.cpp @@ -1,9 +1,360 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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" #include "zigbeenetwork.h" +#include "loggingcategory.h" -ZigbeeDeviceObject::ZigbeeDeviceObject(ZigbeeNetwork *network, QObject *parent) : +#include + +ZigbeeDeviceObject::ZigbeeDeviceObject(ZigbeeNetwork *network, ZigbeeNode *node, QObject *parent) : QObject(parent), - m_network(network) + m_network(network), + m_node(node) { } + +ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestNodeDescriptor() +{ + qCDebug(dcZigbeeDeviceObject()) << "Request node descriptor from" << m_node; + + // Build APS request + ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::NodeDescriptorRequest); + + // Generate a new transaction sequence number for this device object + quint8 transactionSequenceNumber = m_transactionSequenceNumber++; + + // Build ZDO frame + QByteArray asdu; + QDataStream stream(&asdu, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << transactionSequenceNumber << m_node->shortAddress(); + + // Set the ZDO frame as APS request payload + request.setAsdu(asdu); + + // Create the device object reply and wait for the response indication + ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber); + + // Send the request, on finished read the confirm information + ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); + connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + if (!verifyNetworkError(zdoReply, networkReply)) { + qCWarning(dcZigbeeDeviceObject()) << "Failed to send request" + << static_cast(networkReply->request().clusterId()) + << m_node << networkReply->error() + << networkReply->zigbeeApsStatus(); + finishZdoReply(zdoReply); + return; + } + + // The request was successfully sent to the device + // Now check if the expected indication response received already + if (zdoReply->isComplete()) { + finishZdoReply(zdoReply); + return; + } + + // We received the confirmation but not yet the indication + }); + + return zdoReply; +} + +ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestPowerDescriptor() +{ + qCDebug(dcZigbeeDeviceObject()) << "Request power descriptor from" << m_node; + + // Build APS request + ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::PowerDescriptorRequest); + + // Generate a new transaction sequence number for this device object + quint8 transactionSequenceNumber = m_transactionSequenceNumber++; + + // Build ZDO frame + QByteArray asdu; + QDataStream stream(&asdu, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << transactionSequenceNumber << m_node->shortAddress(); + + // Set the ZDO frame as APS request payload + request.setAsdu(asdu); + + // Create the device object reply and wait for the response indication + ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber); + + // Send the request, on finished read the confirm information + ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); + connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + if (!verifyNetworkError(zdoReply, networkReply)) { + qCWarning(dcZigbeeDeviceObject()) << "Failed to send request" + << static_cast(networkReply->request().clusterId()) + << m_node << networkReply->error() + << networkReply->zigbeeApsStatus(); + finishZdoReply(zdoReply); + return; + } + + // The request was successfully sent to the device + // Now check if the expected indication response received already + if (zdoReply->isComplete()) { + finishZdoReply(zdoReply); + return; + } + // We received the confirmation but not yet the indication + }); + + return zdoReply; +} + +ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestActiveEndpoints() +{ + qCDebug(dcZigbeeDeviceObject()) << "Request active endpoints from" << m_node; + + // Build APS request + ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::ActiveEndpointsRequest); + + // Generate a new transaction sequence number for this device object + quint8 transactionSequenceNumber = m_transactionSequenceNumber++; + + // Build ZDO frame + QByteArray asdu; + QDataStream stream(&asdu, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << transactionSequenceNumber << m_node->shortAddress(); + + // Set the ZDO frame as APS request payload + request.setAsdu(asdu); + + // Create the device object reply and wait for the response indication + ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber); + + // Send the request, on finished read the confirm information + ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); + connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + if (!verifyNetworkError(zdoReply, networkReply)) { + qCWarning(dcZigbeeDeviceObject()) << "Failed to send request" + << static_cast(networkReply->request().clusterId()) + << m_node << networkReply->error() + << networkReply->zigbeeApsStatus(); + finishZdoReply(zdoReply); + return; + } + + // The request was successfully sent to the device + // Now check if the expected indication response received already + if (zdoReply->isComplete()) { + finishZdoReply(zdoReply); + return; + } + // We received the confirmation but not yet the indication + }); + + return zdoReply; +} + +ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestSimpleDescriptor(quint8 endpointId) +{ + qCDebug(dcZigbeeDeviceObject()) << "Request simple descriptor from" << m_node << "endpoint" << endpointId; + + // Build APS request + ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::SimpleDescriptorRequest); + + // Generate a new transaction sequence number for this device object + quint8 transactionSequenceNumber = m_transactionSequenceNumber++; + + // Build ZDO frame + QByteArray asdu; + QDataStream stream(&asdu, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << transactionSequenceNumber << request.destinationShortAddress() << endpointId; + + // Set the ZDO frame as APS request payload + request.setAsdu(asdu); + + // Create the device object reply and wait for the response indication + ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber); + + // Send the request, on finished read the confirm information + ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); + connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + if (!verifyNetworkError(zdoReply, networkReply)) { + qCWarning(dcZigbeeDeviceObject()) << "Failed to send request" + << static_cast(networkReply->request().clusterId()) + << m_node << networkReply->error() + << networkReply->zigbeeApsStatus(); + finishZdoReply(zdoReply); + return; + } + + // The request was successfully sent to the device + // Now check if the expected indication response received already + if (zdoReply->isComplete()) { + finishZdoReply(zdoReply); + return; + } + // We received the confirmation but not yet the indication + }); + + return zdoReply; +} + +ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLeaveNetwork(bool rejoin, bool removeChildren) +{ + qCDebug(dcZigbeeDeviceObject()) << "Request management leave network from" << m_node << "rejoin" << rejoin << "remove children" << removeChildren; + + // Build APS request + ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::MgmtLeaveRequest); + + // Generate a new transaction sequence number for this device object + quint8 transactionSequenceNumber = m_transactionSequenceNumber++; + + // Build ZDO frame + quint8 leaveFlag = 0; + if (rejoin) { + leaveFlag |= 0x01; + } + + if (removeChildren) { + leaveFlag |= 0x02; + } + + QByteArray asdu; + QDataStream stream(&asdu, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << transactionSequenceNumber << m_node->extendedAddress().toUInt64() << leaveFlag; + + // Set the ZDO frame as APS request payload + request.setAsdu(asdu); + + // Create the device object reply and wait for the response indication + ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber); + + // Send the request, on finished read the confirm information + ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); + connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + if (!verifyNetworkError(zdoReply, networkReply)) { + qCWarning(dcZigbeeDeviceObject()) << "Failed to send request" + << static_cast(networkReply->request().clusterId()) + << m_node << networkReply->error() + << networkReply->zigbeeApsStatus(); + finishZdoReply(zdoReply); + return; + } + + // The request was successfully sent to the device + // Now check if the expected indication response received already + if (zdoReply->isComplete()) { + finishZdoReply(zdoReply); + return; + } + // We received the confirmation but not yet the indication + }); + + return zdoReply; +} + +ZigbeeNetworkRequest ZigbeeDeviceObject::buildZdoRequest(quint16 zdoRequest) +{ + ZigbeeNetworkRequest request; + request.setRequestId(m_network->generateSequenceNumber()); + request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress); + request.setDestinationShortAddress(m_node->shortAddress()); + request.setDestinationEndpoint(0); // ZDO + request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP + request.setClusterId(zdoRequest); + request.setSourceEndpoint(0); // ZDO + return request; +} + +ZigbeeDeviceObjectReply *ZigbeeDeviceObject::createZigbeeDeviceObjectReply(const ZigbeeNetworkRequest &request, quint8 transactionSequenceNumber) +{ + ZigbeeDeviceObjectReply *zdoReply = new ZigbeeDeviceObjectReply(request, this); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, zdoReply, &ZigbeeDeviceObjectReply::deleteLater); + zdoReply->m_expectedResponse = static_cast(request.clusterId() | 0x8000); + zdoReply->m_transactionSequenceNumber = transactionSequenceNumber; + m_pendingReplies.insert(transactionSequenceNumber, zdoReply); + return zdoReply; +} + +bool ZigbeeDeviceObject::verifyNetworkError(ZigbeeDeviceObjectReply *zdoReply, ZigbeeNetworkReply *networkReply) +{ + bool success = false; + switch (networkReply->error()) { + case ZigbeeNetworkReply::ErrorNoError: + // The request has been transported successfully to he destination, now + // wait for the expected indication or check if we already recieved it + zdoReply->m_apsConfirmReceived = true; + zdoReply->m_zigbeeApsStatus = networkReply->zigbeeApsStatus(); + success = true; + break; + case ZigbeeNetworkReply::ErrorInterfaceError: + zdoReply->m_error = ZigbeeDeviceObjectReply::ErrorInterfaceError; + break; + case ZigbeeNetworkReply::ErrorNetworkOffline: + zdoReply->m_error = ZigbeeDeviceObjectReply::ErrorNetworkOffline; + break; + case ZigbeeNetworkReply::ErrorZigbeeApsStatusError: + zdoReply->m_error = ZigbeeDeviceObjectReply::ErrorZigbeeApsStatusError; + zdoReply->m_apsConfirmReceived = true; + zdoReply->m_zigbeeApsStatus = networkReply->zigbeeApsStatus(); + break; + } + + return success; +} + +void ZigbeeDeviceObject::finishZdoReply(ZigbeeDeviceObjectReply *zdoReply) +{ + m_pendingReplies.remove(zdoReply->transactionSequenceNumber()); + zdoReply->finished(); +} + +void ZigbeeDeviceObject::processApsDataIndication(quint8 destinationEndpoint, quint8 sourceEndpoint, quint16 clusterId, QByteArray payload, quint8 lqi, qint8 rssi) +{ + Q_UNUSED(destinationEndpoint) + Q_UNUSED(sourceEndpoint) + Q_UNUSED(clusterId) + Q_UNUSED(lqi) + Q_UNUSED(rssi) + + // Check if we have a waiting ZDO reply for this data + ZigbeeDeviceProfile::Adpu asdu = ZigbeeDeviceProfile::parseAdpu(payload); + ZigbeeDeviceObjectReply *zdoReply = m_pendingReplies.value(asdu.transactionSequenceNumber); + if (zdoReply && clusterId == (zdoReply->request().clusterId() | 0x8000)) { + zdoReply->m_responseData = payload; + zdoReply->m_responseAdpu = asdu; + zdoReply->m_zdpIndicationReceived = true; + if (zdoReply->isComplete()) { + finishZdoReply(zdoReply); + } + return; + } + + qCWarning(dcZigbeeDeviceObject()) << m_node << "unhandled ZDO indication"; +} diff --git a/libnymea-zigbee/zdo/zigbeedeviceobject.h b/libnymea-zigbee/zdo/zigbeedeviceobject.h index 0fcbcc3..7591993 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobject.h +++ b/libnymea-zigbee/zdo/zigbeedeviceobject.h @@ -1,21 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +#include "zigbeenetworkreply.h" +#include "zigbeedeviceobjectreply.h" + +class ZigbeeNode; class ZigbeeNetwork; class ZigbeeDeviceObject : public QObject { Q_OBJECT public: - explicit ZigbeeDeviceObject(ZigbeeNetwork *network, QObject *parent = nullptr); + explicit ZigbeeDeviceObject(ZigbeeNetwork *network, ZigbeeNode *node, QObject *parent = nullptr); + + // Device and service discovery + ZigbeeDeviceObjectReply *requestNodeDescriptor(); + ZigbeeDeviceObjectReply *requestPowerDescriptor(); + ZigbeeDeviceObjectReply *requestActiveEndpoints(); + ZigbeeDeviceObjectReply *requestSimpleDescriptor(quint8 endpointId); + + // Management request + ZigbeeDeviceObjectReply *requestMgmtLeaveNetwork(bool rejoin = false, bool removeChildren = false); + + // TODO: write all requests private: ZigbeeNetwork *m_network = nullptr; + ZigbeeNode *m_node = nullptr; + + quint8 m_transactionSequenceNumber = 0; + QHash m_pendingReplies; + + // Helper methods + ZigbeeNetworkRequest buildZdoRequest(quint16 zdoRequest); + ZigbeeDeviceObjectReply *createZigbeeDeviceObjectReply(const ZigbeeNetworkRequest &request, quint8 transactionSequenceNumber); + bool verifyNetworkError(ZigbeeDeviceObjectReply *zdoReply, ZigbeeNetworkReply *networkReply); + void finishZdoReply(ZigbeeDeviceObjectReply *zdoReply); signals: +public slots: + void processApsDataIndication(quint8 destinationEndpoint, quint8 sourceEndpoint, quint16 clusterId, QByteArray payload, quint8 lqi, qint8 rssi); + }; #endif // ZIGBEEDEVICEOBJECT_H diff --git a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp index f870ca6..43d113b 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp +++ b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp @@ -1,6 +1,75 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 "zigbeedeviceobjectreply.h" -ZigbeeDeviceObjectReply::ZigbeeDeviceObjectReply(QObject *parent) : QObject(parent) +ZigbeeDeviceObjectReply::ZigbeeDeviceObjectReply(const ZigbeeNetworkRequest &request, QObject *parent) : + QObject(parent), + m_request(request) { } + +ZigbeeDeviceObjectReply::Error ZigbeeDeviceObjectReply::error() const +{ + return m_error; +} + +ZigbeeNetworkRequest ZigbeeDeviceObjectReply::request() const +{ + return m_request; +} + +quint8 ZigbeeDeviceObjectReply::transactionSequenceNumber() const +{ + return m_transactionSequenceNumber; +} + +ZigbeeDeviceProfile::ZdoCommand ZigbeeDeviceObjectReply::expectedResponse() const +{ + return m_expectedResponse; +} + +QByteArray ZigbeeDeviceObjectReply::responseData() const +{ + return m_responseData; +} + +ZigbeeDeviceProfile::Adpu ZigbeeDeviceObjectReply::responseAdpu() const +{ + return m_responseAdpu; +} + +Zigbee::ZigbeeApsStatus ZigbeeDeviceObjectReply::zigbeeApsStatus() const +{ + return m_zigbeeApsStatus; +} + +bool ZigbeeDeviceObjectReply::isComplete() const +{ + return m_apsConfirmReceived && m_zdpIndicationReceived; +} diff --git a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h index 9faeaf1..b7ff3e0 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h +++ b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.h @@ -1,15 +1,89 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ZIGBEEDEVICEOBJECTREPLY_H #define ZIGBEEDEVICEOBJECTREPLY_H #include +#include "zigbeedeviceprofile.h" +#include "zigbeenetworkrequest.h" + class ZigbeeDeviceObjectReply : public QObject { Q_OBJECT + + friend class ZigbeeDeviceObject; + public: - explicit ZigbeeDeviceObjectReply(QObject *parent = nullptr); + enum Error { + ErrorNoError, // All OK, no error occured + ErrorTimeout, // The request timeouted + ErrorZigbeeApsStatusError, // An APS transport error occured. See zigbeeApsStatus() + ErrorInterfaceError, // A transport interface error occured. Could not communicate with the hardware. + ErrorNetworkOffline // The network is offline. Cannot send any requests + }; + Q_ENUM(Error) + + Error error() const; + + ZigbeeNetworkRequest request() const; + quint8 transactionSequenceNumber() const; + ZigbeeDeviceProfile::ZdoCommand expectedResponse() const; + + QByteArray responseData() const; + ZigbeeDeviceProfile::Adpu responseAdpu() const; + + Zigbee::ZigbeeApsStatus zigbeeApsStatus() const; + + bool isComplete() const; + +private: + explicit ZigbeeDeviceObjectReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr); + + Error m_error = ErrorNoError; + + // Request information + ZigbeeNetworkRequest m_request; + quint8 m_transactionSequenceNumber = 0; + + // APS transport + bool m_apsConfirmReceived = false; + Zigbee::ZigbeeApsStatus m_zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess; + + // ZDP response data + bool m_zdpIndicationReceived = false; + ZigbeeDeviceProfile::ZdoCommand m_expectedResponse; + QByteArray m_responseData; + ZigbeeDeviceProfile::Adpu m_responseAdpu; + signals: + void finished(); }; diff --git a/libnymea-zigbee/zdo/zigbeedeviceprofile.cpp b/libnymea-zigbee/zdo/zigbeedeviceprofile.cpp index 947d755..b23d688 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceprofile.cpp +++ b/libnymea-zigbee/zdo/zigbeedeviceprofile.cpp @@ -30,22 +30,22 @@ #include -ZigbeeDeviceProfileAdpu ZigbeeDeviceProfile::parseAdpu(const QByteArray &adpu) +ZigbeeDeviceProfile::Adpu ZigbeeDeviceProfile::parseAdpu(const QByteArray &adpu) { QDataStream stream(adpu); stream.setByteOrder(QDataStream::LittleEndian); - ZigbeeDeviceProfileAdpu deviceAdpu; + ZigbeeDeviceProfile::Adpu deviceAdpu; quint8 statusFlag = 0; - stream >> deviceAdpu.sequenceNumber >> statusFlag >> deviceAdpu.addressOfInterest; - deviceAdpu.status = static_cast(statusFlag); + stream >> deviceAdpu.transactionSequenceNumber >> statusFlag >> deviceAdpu.addressOfInterest; + deviceAdpu.status = static_cast(statusFlag); deviceAdpu.payload = adpu.right(adpu.length() - 4); return deviceAdpu; } -QDebug operator<<(QDebug debug, const ZigbeeDeviceProfileAdpu &deviceAdpu) +QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::Adpu &deviceAdpu) { - debug.nospace() << "DeviceAdpu(SQN: " << deviceAdpu.sequenceNumber << ", "; + debug.nospace() << "DeviceAdpu(SQN: " << deviceAdpu.transactionSequenceNumber << ", "; debug.nospace() << deviceAdpu.status << ", "; debug.nospace() << ZigbeeUtils::convertUint16ToHexString(deviceAdpu.addressOfInterest) << ", "; debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")"; diff --git a/libnymea-zigbee/zdo/zigbeedeviceprofile.h b/libnymea-zigbee/zdo/zigbeedeviceprofile.h index feb2812..f643667 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceprofile.h +++ b/libnymea-zigbee/zdo/zigbeedeviceprofile.h @@ -33,13 +33,6 @@ #include "zigbee.h" -typedef struct ZigbeeDeviceProfileAdpu { - quint8 sequenceNumber = 0; - Zigbee::ZigbeeStatus status = Zigbee::ZigbeeStatusSuccess; - quint16 addressOfInterest = 0; - QByteArray payload; -} ZigbeeDeviceProfileAdpu; - class ZigbeeDeviceProfile { Q_GADGET @@ -47,8 +40,20 @@ class ZigbeeDeviceProfile public: enum Status { StatusSuccess = 0x00, - StatusInvalidRequestType = 0x01, - StatusDeviceNotFound = 0x02 + StatusInvalidRequestType = 0x80, + StatusDeviceNotFound = 0x81, + StatusInvalidEndpoint = 0x82, + StatusNotActive = 0x83, + StatusNotSupported = 0x84, + StatusTimeout = 0x85, + StatusNoMatch = 0x86, + StatusNoEntry = 0x88, + StatusNoDescriptor = 0x89, + StatusInsufficientSpace = 0x8a, + StatusNotPermitted = 0x8b, + StatusTableFull = 0x8c, + StatusNotAuthorized = 0x8d, + StatusDeviceBindingTableFull = 0x8e }; Q_ENUM(Status) @@ -154,9 +159,23 @@ public: }; Q_ENUM(ZdoCommand) - static ZigbeeDeviceProfileAdpu parseAdpu(const QByteArray &adpu); + // For sending + typedef struct Frame { + quint8 transactionSequenceNumber = 0; + QByteArray payload; + } Frame; + + // Receiving + typedef struct Adpu { + quint8 transactionSequenceNumber = 0; + ZigbeeDeviceProfile::Status status = ZigbeeDeviceProfile::StatusSuccess; + quint16 addressOfInterest = 0; + QByteArray payload; + } Adpu; + + static ZigbeeDeviceProfile::Adpu parseAdpu(const QByteArray &adpu); }; -QDebug operator<<(QDebug debug, const ZigbeeDeviceProfileAdpu &deviceAdpu); +QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::Adpu &deviceAdpu); #endif // ZIGBEEDEVICEPROFILE_H diff --git a/libnymea-zigbee/zdo/zigbeedeviceprofilehandler.cpp b/libnymea-zigbee/zdo/zigbeedeviceprofilehandler.cpp deleted file mode 100644 index bc8f4ee..0000000 --- a/libnymea-zigbee/zdo/zigbeedeviceprofilehandler.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "zigbeedeviceprofilehandler.h" - -ZigbeeDeviceProfileHandler::ZigbeeDeviceProfileHandler(QObject *parent) : QObject(parent) -{ - -} diff --git a/libnymea-zigbee/zdo/zigbeedeviceprofilehandler.h b/libnymea-zigbee/zdo/zigbeedeviceprofilehandler.h deleted file mode 100644 index 1aa324c..0000000 --- a/libnymea-zigbee/zdo/zigbeedeviceprofilehandler.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ZIGBEEDEVICEPROFILEHANDLER_H -#define ZIGBEEDEVICEPROFILEHANDLER_H - -#include - -class ZigbeeDeviceProfileHandler : public QObject -{ - Q_OBJECT -public: - explicit ZigbeeDeviceProfileHandler(QObject *parent = nullptr); - -signals: - -}; - -#endif // ZIGBEEDEVICEPROFILEHANDLER_H diff --git a/libnymea-zigbee/zigbee.h b/libnymea-zigbee/zigbee.h index 5637688..3c83a41 100644 --- a/libnymea-zigbee/zigbee.h +++ b/libnymea-zigbee/zigbee.h @@ -74,210 +74,210 @@ public: Q_ENUM(ZigbeeChannel) Q_DECLARE_FLAGS(ZigbeeChannels, ZigbeeChannel) - enum InterfaceMessageType { - // Common Commands - MessageTypeNone = 0x0000, - MessageTypeStatus = 0x8000, - MessageTypeLogging = 0x8001, +// enum InterfaceMessageType { +// // Common Commands +// MessageTypeNone = 0x0000, +// MessageTypeStatus = 0x8000, +// MessageTypeLogging = 0x8001, - MessageTypeDataIndication = 0x8002, +// MessageTypeDataIndication = 0x8002, - MessageTypeNodeClusterList = 0x8003, - MessageTypeNodeAttributeList = 0x8004, - MessageTypeNodeCommandIdList = 0x8005, - MessageTypeRestartProvisioned = 0x8006, - MessageTypeFactoryNewRestart = 0x8007, - MessageTypeGetVersion = 0x0010, - MessageTypeVersionList = 0x8010, +// MessageTypeNodeClusterList = 0x8003, +// MessageTypeNodeAttributeList = 0x8004, +// MessageTypeNodeCommandIdList = 0x8005, +// MessageTypeRestartProvisioned = 0x8006, +// MessageTypeFactoryNewRestart = 0x8007, +// MessageTypeGetVersion = 0x0010, +// MessageTypeVersionList = 0x8010, - MessageTypeSetExtendetPanId = 0x0020, - MessageTypeSetChannelMask = 0x0021, - MessageTypeSetSecurity = 0x0022, - MessageTypeSetDeviceType = 0x0023, - MessageTypeStartNetwork = 0x0024, - MessageTypeStartScan = 0x0025, - MessageTypeNetworkJoinedFormed = 0x8024, - MessageTypeNetworkRemoveDevice = 0x0026, - MessageTypeNetworkWhitelistEnable = 0x0027, - MessageTypeAuthenticateDeviceRequest = 0x0028, - MessageTypeAuthenticateDeviceResponse = 0x8028, - MessageTypeOutOfBandCommisioningDataRequest = 0x0029, - MessageTypeOutOfBandCommisioningDataResponse = 0x8029, - MessageTypeUserDescriptorSet = 0x002B, - MessageTypeUserDescriptorNotify = 0x802B, - MessageTypeUserDescriptorRequest = 0x002C, - MessageTypeUserDescriptorResponse = 0x802C, +// MessageTypeSetExtendetPanId = 0x0020, +// MessageTypeSetChannelMask = 0x0021, +// MessageTypeSetSecurity = 0x0022, +// MessageTypeSetDeviceType = 0x0023, +// MessageTypeStartNetwork = 0x0024, +// MessageTypeStartScan = 0x0025, +// MessageTypeNetworkJoinedFormed = 0x8024, +// MessageTypeNetworkRemoveDevice = 0x0026, +// MessageTypeNetworkWhitelistEnable = 0x0027, +// MessageTypeAuthenticateDeviceRequest = 0x0028, +// MessageTypeAuthenticateDeviceResponse = 0x8028, +// MessageTypeOutOfBandCommisioningDataRequest = 0x0029, +// MessageTypeOutOfBandCommisioningDataResponse = 0x8029, +// MessageTypeUserDescriptorSet = 0x002B, +// MessageTypeUserDescriptorNotify = 0x802B, +// MessageTypeUserDescriptorRequest = 0x002C, +// MessageTypeUserDescriptorResponse = 0x802C, - MessageTypeReset = 0x0011, - MessageTypeErasePersistentData = 0x0012, - MessageTypeZllFactoryNew = 0x0013, - MessageTypeGetPermitJoining = 0x0014, - MessageTypeGetPermitJoiningResponse = 0x8014, - MessageTypeBind = 0x0030, - MessageTypeBindResponse = 0x8030, - MessageTypeUnbind = 0x0031, - MessageTypeBindGroup = 0x0032, - MessageTypeBindGroupResponse = 0x8032, - MessageTypeUnbindGroup = 0x0033, - MessageTypeUnbindGroupResponse = 0x8033, +// MessageTypeReset = 0x0011, +// MessageTypeErasePersistentData = 0x0012, +// MessageTypeZllFactoryNew = 0x0013, +// MessageTypeGetPermitJoining = 0x0014, +// MessageTypeGetPermitJoiningResponse = 0x8014, +// MessageTypeBind = 0x0030, +// MessageTypeBindResponse = 0x8030, +// MessageTypeUnbind = 0x0031, +// MessageTypeBindGroup = 0x0032, +// MessageTypeBindGroupResponse = 0x8032, +// MessageTypeUnbindGroup = 0x0033, +// MessageTypeUnbindGroupResponse = 0x8033, - MessageTypeUnbindResponse = 0x8031, - MessageTypeComplexDescriptorRequest = 0x0034, - MessageTypeComplexDescriptorResponse = 0x8034, +// MessageTypeUnbindResponse = 0x8031, +// MessageTypeComplexDescriptorRequest = 0x0034, +// MessageTypeComplexDescriptorResponse = 0x8034, - MessageTypeNetworkAdressRequest = 0x0040, - MessageTypeNetworkAdressResponse = 0x8040, - MessageTypeIeeeAddressResponse = 0x0041, - MessageTypeIeeeAddressRequest = 0x8041, - MessageTypeNodeDescriptorRequest = 0x0042, - MessageTypeNodeDescriptorRsponse = 0x8042, - MessageTypeSimpleDescriptorRequest = 0x0043, - MessageTypeSimpleDescriptorResponse = 0x8043, - MessageTypePowerDescriptorRequest = 0x0044, - MessageTypePowerDescriptorResponse = 0x8044, - MessageTypeActiveEndpointRequest = 0x0045, - MessageTypeActiveEndpointResponse = 0x8045, - MessageTypeMatchDescriptorRequest = 0x0046, - MessageTypeMatchDescriptorResponse = 0x8046, - MessageTypeManagementLeaveRequest = 0x0047, - MessageTypeManagementLeaveResponse = 0x8047, - MessageTypeLeaveIndication = 0x8048, - MessageTypePermitJoiningRequest = 0x0049, - MessageTypeManagementNetworkUpdateRequest = 0x004A, - MessageTypeManagementNetworkUpdateResponse = 0x804A, - MessageTypeSystemServerDiscoveryRequest = 0x004B, - MessageTypeSystemServerDiscoveryResponse = 0x804B, - MessageTypeDeviceAnnounce = 0x004D, - MessageTypeManagementLqiRequest = 0x004E, - MessageTypeManagementLqiResponse = 0x804E, +// MessageTypeNetworkAdressRequest = 0x0040, +// MessageTypeNetworkAdressResponse = 0x8040, +// MessageTypeIeeeAddressResponse = 0x0041, +// MessageTypeIeeeAddressRequest = 0x8041, +// MessageTypeNodeDescriptorRequest = 0x0042, +// MessageTypeNodeDescriptorRsponse = 0x8042, +// MessageTypeSimpleDescriptorRequest = 0x0043, +// MessageTypeSimpleDescriptorResponse = 0x8043, +// MessageTypePowerDescriptorRequest = 0x0044, +// MessageTypePowerDescriptorResponse = 0x8044, +// MessageTypeActiveEndpointRequest = 0x0045, +// MessageTypeActiveEndpointResponse = 0x8045, +// MessageTypeMatchDescriptorRequest = 0x0046, +// MessageTypeMatchDescriptorResponse = 0x8046, +// MessageTypeManagementLeaveRequest = 0x0047, +// MessageTypeManagementLeaveResponse = 0x8047, +// MessageTypeLeaveIndication = 0x8048, +// MessageTypePermitJoiningRequest = 0x0049, +// MessageTypeManagementNetworkUpdateRequest = 0x004A, +// MessageTypeManagementNetworkUpdateResponse = 0x804A, +// MessageTypeSystemServerDiscoveryRequest = 0x004B, +// MessageTypeSystemServerDiscoveryResponse = 0x804B, +// MessageTypeDeviceAnnounce = 0x004D, +// MessageTypeManagementLqiRequest = 0x004E, +// MessageTypeManagementLqiResponse = 0x804E, - // Basic cluster - MessageBasicResetFactoryDefaults = 0x0050, - MessageBasicResetFactoryDefaultsResponse = 0x8050, +// // Basic cluster +// MessageBasicResetFactoryDefaults = 0x0050, +// MessageBasicResetFactoryDefaultsResponse = 0x8050, - // Group Cluster - MessageTypeAddGroupRequest = 0x0060, - MessageTypeAddGroupResponse = 0x8060, - MessageTypeViewGroupRequest = 0x0061, - MessageTypeViewGroupResponse = 0x8061, - MessageTypeGetGroupMembershipRequest = 0x0062, - MessageTypeGetGroupMembershipResponse = 0x8062, - MessageTypeRemoveGroupRequest = 0x0063, - MessageTypeRemoveGroupResponse = 0x8063, - MessageTypeRemoveAllGroups = 0x0064, - MessageTypeGroupIfIdentify = 0x0065, +// // Group Cluster +// MessageTypeAddGroupRequest = 0x0060, +// MessageTypeAddGroupResponse = 0x8060, +// MessageTypeViewGroupRequest = 0x0061, +// MessageTypeViewGroupResponse = 0x8061, +// MessageTypeGetGroupMembershipRequest = 0x0062, +// MessageTypeGetGroupMembershipResponse = 0x8062, +// MessageTypeRemoveGroupRequest = 0x0063, +// MessageTypeRemoveGroupResponse = 0x8063, +// MessageTypeRemoveAllGroups = 0x0064, +// MessageTypeGroupIfIdentify = 0x0065, - // Identify Cluster - MessageTypeIdentifySend = 0x0070, - MessageTypeIdentifyQuery = 0x0071, +// // Identify Cluster +// MessageTypeIdentifySend = 0x0070, +// MessageTypeIdentifyQuery = 0x0071, - // Level Cluster - MessageTypeMoveToLevel = 0x0080, - MessageTypeMoveToLevelOnOff = 0x0081, - MessageTypeMoveStep = 0x0082, - MessageTypeMoveStopMove = 0x0083, - MessageTypeMoveStopMoveOnOff = 0x0084, +// // Level Cluster +// MessageTypeMoveToLevel = 0x0080, +// MessageTypeMoveToLevelOnOff = 0x0081, +// MessageTypeMoveStep = 0x0082, +// MessageTypeMoveStopMove = 0x0083, +// MessageTypeMoveStopMoveOnOff = 0x0084, - // Scenes Cluster - MessageTypeViewScene = 0x00A0, - MessageTypeViewSceneResponse = 0x80A0, - MessageTypeAddScene = 0x00A1, - MessageTypeAddSceneResponse = 0x80A1, - MessageTypeRemoveScene = 0x00A2, - MessageTypeRemoveSceneResponse = 0x80A2, - MessageTypeRemoveAllScenes = 0x00A3, - MessageTypeRemoveAllScenesResponse = 0x80A3, - MessageTypeStoreScene = 0x00A4, - MessageTypeStoreSceneResponse = 0x80A4, - MessageTypeRecallScene = 0x00A5, - MessageTypeSceneMembershipRequest = 0x00A6, - MessageTypeSceneMembershipResponse = 0x80A6, +// // Scenes Cluster +// MessageTypeViewScene = 0x00A0, +// MessageTypeViewSceneResponse = 0x80A0, +// MessageTypeAddScene = 0x00A1, +// MessageTypeAddSceneResponse = 0x80A1, +// MessageTypeRemoveScene = 0x00A2, +// MessageTypeRemoveSceneResponse = 0x80A2, +// MessageTypeRemoveAllScenes = 0x00A3, +// MessageTypeRemoveAllScenesResponse = 0x80A3, +// MessageTypeStoreScene = 0x00A4, +// MessageTypeStoreSceneResponse = 0x80A4, +// MessageTypeRecallScene = 0x00A5, +// MessageTypeSceneMembershipRequest = 0x00A6, +// MessageTypeSceneMembershipResponse = 0x80A6, - //Colour Cluster - MessageTypeMoveToHue = 0x00B0, - MessageTypeMoveHue = 0x00B1, - MessageTypeStepHue = 0x00B2, - MessageTypeMoveToSaturation = 0x00B3, - MessageTypeMoveSaturation = 0x00B4, - MessageTypeStepStaturation = 0x00B5, - MessageTypeMoveToHueSaturation = 0x00B6, - MessageTypeMoveToColor = 0x00B7, - MessageTypeMoveColor = 0x00B8, - MessageTypeStepColor = 0x00B9, +// //Colour Cluster +// MessageTypeMoveToHue = 0x00B0, +// MessageTypeMoveHue = 0x00B1, +// MessageTypeStepHue = 0x00B2, +// MessageTypeMoveToSaturation = 0x00B3, +// MessageTypeMoveSaturation = 0x00B4, +// MessageTypeStepStaturation = 0x00B5, +// MessageTypeMoveToHueSaturation = 0x00B6, +// MessageTypeMoveToColor = 0x00B7, +// MessageTypeMoveColor = 0x00B8, +// MessageTypeStepColor = 0x00B9, - // ZLL Commands - // Touchlink - MessageTypeInitiateTouchlink = 0x00D0, - MessageTypeTouchlinkStatus = 0x00D1, - MessageTypeTouchlinkFactoryReset = 0x00D2, +// // ZLL Commands +// // Touchlink +// MessageTypeInitiateTouchlink = 0x00D0, +// MessageTypeTouchlinkStatus = 0x00D1, +// MessageTypeTouchlinkFactoryReset = 0x00D2, - // Identify Cluster - MessageTypeIdentifyTriggerEffect = 0x00E0, +// // Identify Cluster +// MessageTypeIdentifyTriggerEffect = 0x00E0, - // On/Off Cluster - MessageTypeCluserOnOff = 0x0092, - MessageTypeCluserOnOffTimed = 0x0093, - MessageTypeCluserOnOffEffects = 0x0094, - MessageTypeCluserOnOffUpdate = 0x8095, +// // On/Off Cluster +// MessageTypeCluserOnOff = 0x0092, +// MessageTypeCluserOnOffTimed = 0x0093, +// MessageTypeCluserOnOffEffects = 0x0094, +// MessageTypeCluserOnOffUpdate = 0x8095, - // Scenes Cluster - MessageTypeAddEnhancedScene = 0x00A7, - MessageTypeViewEnhancedScene = 0x00A8, - MessageTypeCopyScene = 0x00A9, +// // Scenes Cluster +// MessageTypeAddEnhancedScene = 0x00A7, +// MessageTypeViewEnhancedScene = 0x00A8, +// MessageTypeCopyScene = 0x00A9, - // Colour Cluster - MessageTypeEnhancedMoveToHue = 0x00BA, - MessageTypeEnhancedMoveHue = 0x00BB, - MessageTypeEnhancedStepHue = 0x00BC, - MessageTypeEnhancedMoveToHueSaturation = 0x00BD, - MessageTypeColourLoopSet = 0x00BE, - MessageTypeStopMoveStep = 0x00BF, - MessageTypeMoveToColorTemperature = 0x00C0, - MessageTypeMoveColorTemperature = 0x00C1, - MessageTypeStepColorTemperature = 0x00C2, +// // Colour Cluster +// MessageTypeEnhancedMoveToHue = 0x00BA, +// MessageTypeEnhancedMoveHue = 0x00BB, +// MessageTypeEnhancedStepHue = 0x00BC, +// MessageTypeEnhancedMoveToHueSaturation = 0x00BD, +// MessageTypeColourLoopSet = 0x00BE, +// MessageTypeStopMoveStep = 0x00BF, +// MessageTypeMoveToColorTemperature = 0x00C0, +// MessageTypeMoveColorTemperature = 0x00C1, +// MessageTypeStepColorTemperature = 0x00C2, - // ZHA Commands - // Door Lock Cluster - MessageTypeLockUnlockDoor = 0x00F0, +// // ZHA Commands +// // Door Lock Cluster +// MessageTypeLockUnlockDoor = 0x00F0, - // Attributes - MessageTypeReadAttributeRequest = 0x0100, - MessageTypeReadAttributeResponse = 0x8100, - MessageTypeDefaultResponse = 0x8101, - MessageTypeAttributeReport = 0x8102, - MessageTypeWriteAttributeRequest = 0x0110, - MessageTypeWriteAttributeResponse = 0x8110, - MessageTypeConfigReportingRequest = 0x0120, - MessageTypeConfigReportingResponse = 0x8120, - MessageTypeReportAttributes = 0x8121, - MessageTypeAttributeDiscoveryRequest = 0x0140, - MessageTypeAttributeDiscoveryResponse = 0x8140, +// // Attributes +// MessageTypeReadAttributeRequest = 0x0100, +// MessageTypeReadAttributeResponse = 0x8100, +// MessageTypeDefaultResponse = 0x8101, +// MessageTypeAttributeReport = 0x8102, +// MessageTypeWriteAttributeRequest = 0x0110, +// MessageTypeWriteAttributeResponse = 0x8110, +// MessageTypeConfigReportingRequest = 0x0120, +// MessageTypeConfigReportingResponse = 0x8120, +// MessageTypeReportAttributes = 0x8121, +// MessageTypeAttributeDiscoveryRequest = 0x0140, +// MessageTypeAttributeDiscoveryResponse = 0x8140, - // Persistant data manager messages - MessageTypeDataManagerAvailableRequest = 0x0300, - MessageTypeDataManagerAvailableResponse = 0x8300, - MessageTypeDataManagerSaveRecordRequest = 0x0200, - MessageTypeDataManagerSaveRecordResponse = 0x8200, - MessageTypeDataManagerLoadRecordRequest = 0x0201, - MessageTypeDataManagerLoadRecordResponse = 0x8201, - MessageTypeDataManagerDeleteAllRecordsRequest = 0x0202, - MessageTypeDataManagerDeleteAllRecordsResponse = 0x8202, +// // Persistant data manager messages +// MessageTypeDataManagerAvailableRequest = 0x0300, +// MessageTypeDataManagerAvailableResponse = 0x8300, +// MessageTypeDataManagerSaveRecordRequest = 0x0200, +// MessageTypeDataManagerSaveRecordResponse = 0x8200, +// MessageTypeDataManagerLoadRecordRequest = 0x0201, +// MessageTypeDataManagerLoadRecordResponse = 0x8201, +// MessageTypeDataManagerDeleteAllRecordsRequest = 0x0202, +// MessageTypeDataManagerDeleteAllRecordsResponse = 0x8202, - // Appliance Statistics Cluster 0x0B03 - // http://www.nxp.com/documents/user_manual/JN-UG-3076.pdf - MessageTypeStatisticsClusterLogMessage = 0x0301, // Was 0x0500, was 0x0301 - MessageTypeStatisticsClusterLogMessageResponse = 0x8301, +// // Appliance Statistics Cluster 0x0B03 +// // http://www.nxp.com/documents/user_manual/JN-UG-3076.pdf +// MessageTypeStatisticsClusterLogMessage = 0x0301, // Was 0x0500, was 0x0301 +// MessageTypeStatisticsClusterLogMessageResponse = 0x8301, - // IAS Cluster - MessageTypeSendIasZoneEnroolResponse = 0x0400, - MessageTypeIasZoneStatusChangeNotify = 0x8401, +// // IAS Cluster +// MessageTypeSendIasZoneEnroolResponse = 0x0400, +// MessageTypeIasZoneStatusChangeNotify = 0x8401, - // Extended utils - MessageTypeRawApsDataRequest = 0x0530, - MessageTypeRouterDiscoveryConfirm = 0x8701, - MessageTypeApsDataConfirmFail = 0x8702 - }; - Q_ENUM(InterfaceMessageType) +// // Extended utils +// MessageTypeRawApsDataRequest = 0x0530, +// MessageTypeRouterDiscoveryConfirm = 0x8701, +// MessageTypeApsDataConfirmFail = 0x8702 +// }; +// Q_ENUM(InterfaceMessageType) enum ClusterId { @@ -616,6 +616,28 @@ public: }; Q_ENUM(ZigbeeNwkLayerStatus) + enum ZigbeeApsStatus { + ZigbeeApsStatusSuccess = 0x00, + ZigbeeApsStatusAsduTooLong = 0xa0, + ZigbeeApsStatusDefragDeferred = 0xa1, + ZigbeeApsStatusDefragUnsupported = 0xa2, + ZigbeeApsStatusIllegalRequest = 0xa3, + ZigbeeApsStatusInvalidBinding = 0xa4, + ZigbeeApsStatusInvalidGroup = 0xa5, + ZigbeeApsStatusInvalidParameter = 0xa6, + ZigbeeApsStatusNoAck = 0xa7, + ZigbeeApsStatusNoBoundDevice = 0xa8, + ZigbeeApsStatusNoShortAddress = 0xa9, + ZigbeeApsStatusNotSupported = 0xaa, + ZigbeeApsStatusSecuredLinkKey = 0xab, + ZigbeeApsStatusSecuredNwkKey = 0xac, + ZigbeeApsStatusSecurityFail = 0xad, + ZigbeeApsStatusTableFull = 0xae, + ZigbeeApsStatusUnsecured = 0xaf, + ZigbeeApsStatusUnsupportedAttribute = 0xb0 + }; + Q_ENUM(ZigbeeApsStatus) + enum ZigbeeStatus { ZigbeeStatusSuccess = 0x00, ZigbeeStatusFailure = 0x01, diff --git a/libnymea-zigbee/zigbeeadpu.h b/libnymea-zigbee/zigbeeadpu.h index 279bee1..7429c5a 100644 --- a/libnymea-zigbee/zigbeeadpu.h +++ b/libnymea-zigbee/zigbeeadpu.h @@ -81,10 +81,8 @@ private: FrameControl m_frameControl; quint8 m_destinationEndpoint; - quint8 buildFrameControlByte(FrameControl frameControl); FrameControl readFrameControlByte(quint8 frameControlByte); -signals: }; diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index e9aa06e..2a307ab 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -34,11 +34,6 @@ ZigbeeNetwork::ZigbeeNetwork(QObject *parent) : QObject(parent) { - m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), "zigbee"); - m_db.setDatabaseName(""); - qCDebug(dcZigbeeNetwork()) << "Opening zigbee network database" << m_db.databaseName(); - - } @@ -269,6 +264,18 @@ void ZigbeeNetwork::removeNodeInternally(ZigbeeNode *node) node->deleteLater(); } +ZigbeeNode *ZigbeeNetwork::createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent) +{ + return new ZigbeeNode(this, shortAddress, extendedAddress, parent); +} + +ZigbeeNode *ZigbeeNetwork::createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, quint8 macCapabilities, QObject *parent) +{ + ZigbeeNode *node = createNode(shortAddress, extendedAddress, parent); + node->setMacCapabilitiesFlag(macCapabilities); + return node; +} + void ZigbeeNetwork::saveNetwork() { qCDebug(dcZigbeeNetwork()) << "Save current network configuration to" << m_settingsFileName; @@ -308,10 +315,8 @@ void ZigbeeNetwork::loadNetwork() settings.beginGroup("Nodes"); foreach (const QString ieeeAddressString, settings.childGroups()) { settings.beginGroup(ieeeAddressString); - - ZigbeeNode *node = createNode(this); - node->setExtendedAddress(ZigbeeAddress(ieeeAddressString)); - node->setShortAddress(static_cast(settings.value("nwkAddress", 0).toUInt())); + quint16 shortAddress = static_cast(settings.value("nwkAddress", 0).toUInt()); + ZigbeeNode *node = createNode(shortAddress, ZigbeeAddress(ieeeAddressString), this); // Node descriptor node->m_nodeType = static_cast(settings.value("nodeType", 0).toUInt()); @@ -334,7 +339,7 @@ void ZigbeeNetwork::loadNetwork() for (int i = 0; i < endpointsCount; i++) { settings.setArrayIndex(i); quint8 endpointId = static_cast(settings.value("id", 0).toUInt()); - ZigbeeNodeEndpoint *endpoint = node->createNodeEndpoint(endpointId, node); + ZigbeeNodeEndpoint *endpoint = new ZigbeeNodeEndpoint(this, node, endpointId, node); endpoint->m_profile = static_cast(settings.value("profile", 0).toUInt()); endpoint->m_deviceId = static_cast(settings.value("deviceId", 0).toUInt()); endpoint->m_deviceVersion = static_cast(settings.value("deviceId", 0).toUInt()); @@ -542,29 +547,14 @@ ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest return reply; } -void ZigbeeNetwork::setReplyResponseData(ZigbeeNetworkReply *reply, const QByteArray &responseData) +void ZigbeeNetwork::setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeApsStatus zigbeeApsStatus) { - reply->m_responseData = responseData; - if (reply->isComplete()) { - if (reply->m_zigbeeStatus == Zigbee::ZigbeeStatusSuccess) { - finishNetworkReply(reply); - } else { - finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeStatusError); - } - } -} + reply->m_zigbeeApsStatus = zigbeeApsStatus; -void ZigbeeNetwork::setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeStatus zigbeeStatus) -{ - reply->m_zigbeeStatus = zigbeeStatus; - reply->m_zigbeeConfirmArrived = true; - - if (reply->isComplete()) { - if (reply->m_zigbeeStatus == Zigbee::ZigbeeStatusSuccess) { - finishNetworkReply(reply); - } else { - finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeStatusError); - } + if (reply->m_zigbeeApsStatus == Zigbee::ZigbeeApsStatusSuccess) { + finishNetworkReply(reply); + } else { + finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeApsStatusError); } } diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h index 160207c..79396b3 100644 --- a/libnymea-zigbee/zigbeenetwork.h +++ b/libnymea-zigbee/zigbeenetwork.h @@ -34,6 +34,7 @@ #include #include "zigbeenode.h" +#include "zigbeenodeendpoint.h" #include "zigbeechannelmask.h" #include "zigbeebridgecontroller.h" #include "zigbeesecurityconfiguration.h" @@ -134,11 +135,7 @@ private: QList m_nodes; QList m_uninitializedNodes; - QSqlDatabase m_db; - private: - bool initDB(); - void addNodeInternally(ZigbeeNode *node); void removeNodeInternally(ZigbeeNode *node); @@ -148,7 +145,8 @@ protected: bool m_permitJoining = false; ZigbeeSecurityConfiguration m_securityConfiguration; - virtual ZigbeeNode *createNode(QObject *parent) = 0; + ZigbeeNode *createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent); + ZigbeeNode *createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, quint8 macCapabilities, QObject *parent); virtual void setPermitJoiningInternal(bool permitJoining) = 0; void saveNetwork(); @@ -169,8 +167,7 @@ protected: // Network reply methods ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest()); - void setReplyResponseData(ZigbeeNetworkReply *reply, const QByteArray &responseData); - void setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeStatus zigbeeStatus = Zigbee::ZigbeeStatusSuccess); + void setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeApsStatus zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess); void finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error = ZigbeeNetworkReply::ErrorNoError); signals: diff --git a/libnymea-zigbee/zigbeenetworkmanager.cpp b/libnymea-zigbee/zigbeenetworkmanager.cpp index d9f9b97..04d73c3 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.cpp +++ b/libnymea-zigbee/zigbeenetworkmanager.cpp @@ -28,7 +28,6 @@ #include "zigbeenetworkmanager.h" #include "loggingcategory.h" -#include "nxp/zigbeenetworknxp.h" #include "deconz/zigbeenetworkdeconz.h" #include @@ -39,8 +38,8 @@ ZigbeeNetwork *ZigbeeNetworkManager::createZigbeeNetwork(ZigbeeNetworkManager::B srand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); switch (backend) { - case BackendTypeNxp: - return qobject_cast(new ZigbeeNetworkNxp(parent)); +// case BackendTypeNxp: +// return qobject_cast(new ZigbeeNetworkNxp(parent)); case BackendTypeDeconz: return qobject_cast(new ZigbeeNetworkDeconz(parent)); } diff --git a/libnymea-zigbee/zigbeenetworkmanager.h b/libnymea-zigbee/zigbeenetworkmanager.h index f99323c..88f290e 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.h +++ b/libnymea-zigbee/zigbeenetworkmanager.h @@ -36,7 +36,6 @@ class ZigbeeNetworkManager { public: enum BackendType { - BackendTypeNxp, BackendTypeDeconz }; diff --git a/libnymea-zigbee/zigbeenetworkreply.cpp b/libnymea-zigbee/zigbeenetworkreply.cpp index 40f0ffb..4ab80fd 100644 --- a/libnymea-zigbee/zigbeenetworkreply.cpp +++ b/libnymea-zigbee/zigbeenetworkreply.cpp @@ -37,34 +37,9 @@ ZigbeeNetworkRequest ZigbeeNetworkReply::request() const return m_request; } -Zigbee::ZigbeeStatus ZigbeeNetworkReply::zigbeeStatus() const +Zigbee::ZigbeeApsStatus ZigbeeNetworkReply::zigbeeApsStatus() const { - return m_zigbeeStatus; -} - -QByteArray ZigbeeNetworkReply::responseData() const -{ - return m_responseData; -} - -bool ZigbeeNetworkReply::isComplete() const -{ - // If we expect indication and confirmation - if (m_request.expectConfirmation() && m_request.expectIndication()) { - if (m_zigbeeConfirmArrived && !m_responseData.isEmpty()) { - return true; - } else { - return false; - } - } - - // If we expect only a confirmation - if (m_request.expectConfirmation() && !m_request.expectIndication()) { - return m_zigbeeConfirmArrived; - } - - // If we don't expect any response... - return true; + return m_zigbeeApsStatus; } ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent) : diff --git a/libnymea-zigbee/zigbeenetworkreply.h b/libnymea-zigbee/zigbeenetworkreply.h index 0489ad2..96eadad 100644 --- a/libnymea-zigbee/zigbeenetworkreply.h +++ b/libnymea-zigbee/zigbeenetworkreply.h @@ -43,30 +43,23 @@ class ZigbeeNetworkReply : public QObject public: enum Error { ErrorNoError, - ErrorZigbeeStatusError, + ErrorZigbeeApsStatusError, ErrorInterfaceError, - ErrorNetworkOffline, - ErrorNetworkNotImplemented, - ErrorUnknown + ErrorNetworkOffline }; Q_ENUM(Error) Error error() const; - ZigbeeNetworkRequest request() const; - Zigbee::ZigbeeStatus zigbeeStatus() const; - QByteArray responseData() const; - bool isComplete() const; + ZigbeeNetworkRequest request() const; + Zigbee::ZigbeeApsStatus zigbeeApsStatus() const; private: explicit ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr); ZigbeeNetworkRequest m_request; - bool m_finished = false; Error m_error = ErrorNoError; - bool m_zigbeeConfirmArrived = false; - Zigbee::ZigbeeStatus m_zigbeeStatus = Zigbee::ZigbeeStatusSuccess; - QByteArray m_responseData; + Zigbee::ZigbeeApsStatus m_zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess; signals: void finished(); diff --git a/libnymea-zigbee/zigbeenetworkrequest.cpp b/libnymea-zigbee/zigbeenetworkrequest.cpp index ed7f730..c62bacd 100644 --- a/libnymea-zigbee/zigbeenetworkrequest.cpp +++ b/libnymea-zigbee/zigbeenetworkrequest.cpp @@ -144,26 +144,6 @@ void ZigbeeNetworkRequest::setRadius(quint8 radius) m_radius = radius; } -bool ZigbeeNetworkRequest::expectIndication() const -{ - return m_expectIndication; -} - -void ZigbeeNetworkRequest::setExpectIndication(bool expectIndication) -{ - m_expectIndication = expectIndication; -} - -bool ZigbeeNetworkRequest::expectConfirmation() const -{ - return m_expectConfirmation; -} - -void ZigbeeNetworkRequest::setExpectConfirmation(bool expectConfirmation) -{ - m_expectConfirmation = expectConfirmation; -} - QDebug operator<<(QDebug debug, const ZigbeeNetworkRequest &request) { debug.nospace() << "Request(ID:" << request.requestId() << ", "; @@ -187,7 +167,7 @@ QDebug operator<<(QDebug debug, const ZigbeeNetworkRequest &request) debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(request.sourceEndpoint()) << ", "; debug.nospace() << "Radius:" << request.radius() << ", "; debug.nospace() << request.txOptions() << ", "; - debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(request.asdu()) << ", "; + debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(request.asdu()); debug.nospace() << ")"; return debug.space(); } diff --git a/libnymea-zigbee/zigbeenetworkrequest.h b/libnymea-zigbee/zigbeenetworkrequest.h index 518ea2c..54b2877 100644 --- a/libnymea-zigbee/zigbeenetworkrequest.h +++ b/libnymea-zigbee/zigbeenetworkrequest.h @@ -72,13 +72,6 @@ public: quint8 radius() const; void setRadius(quint8 radius); - // Response expectations - bool expectIndication() const; - void setExpectIndication(bool expectIndication); - - bool expectConfirmation() const; - void setExpectConfirmation(bool expectConfirmation); - private: quint8 m_requestId = 0; Zigbee::DestinationAddressMode m_destinationAddressMode = Zigbee::DestinationAddressModeShortAddress; @@ -92,8 +85,6 @@ private: Zigbee::ZigbeeTxOptions m_txOptions = Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission); quint8 m_radius = 0; - bool m_expectIndication = false; - bool m_expectConfirmation = true; }; QDebug operator<<(QDebug debug, const ZigbeeNetworkRequest &request); diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index 00ded90..c5a5f17 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -32,11 +32,13 @@ #include -ZigbeeNode::ZigbeeNode(ZigbeeNetwork *network, QObject *parent) : +ZigbeeNode::ZigbeeNode(ZigbeeNetwork *network, quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent) : QObject(parent), - m_network(network) + m_network(network), + m_shortAddress(shortAddress), + m_extendedAddress(extendedAddress) { - m_deviceObject = new ZigbeeDeviceObject(m_network, this); + m_deviceObject = new ZigbeeDeviceObject(m_network, this, this); } ZigbeeNode::State ZigbeeNode::state() const @@ -230,7 +232,7 @@ void ZigbeeNode::setState(ZigbeeNode::State state) if (m_state == state) return; - qCDebug(dcZigbeeNode()) << "State changed" << state; + qCDebug(dcZigbeeNode()) << "State changed" << this << state; m_state = state; emit stateChanged(m_state); } @@ -240,7 +242,7 @@ void ZigbeeNode::setConnected(bool connected) if (m_connected == connected) return; - qCDebug(dcZigbeeNode()) << "Connected changed" << connected; + qCDebug(dcZigbeeNode()) << "Connected changed" << this << connected; m_connected = connected; emit connectedChanged(m_connected); } @@ -410,10 +412,10 @@ void ZigbeeNode::setPowerDescriptorFlag(quint16 powerDescriptorFlag) } // Bit 4 - 7 Available power sources - // Bit 0: Permanent mains supply - // Bit 1: Rechargeable battery - // Bit 2: Disposable battery - // Bit 4: Reserved + // Bit 0: Permanent mains supply + // Bit 1: Rechargeable battery + // Bit 2: Disposable battery + // Bit 4: Reserved m_availablePowerSources.clear(); if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 4)) { @@ -450,19 +452,293 @@ void ZigbeeNode::setPowerDescriptorFlag(quint16 powerDescriptorFlag) m_powerLevel = PowerLevelFull; } -// qCDebug(dcZigbeeNode()) << "Node power descriptor (" << ZigbeeUtils::convertUint16ToHexString(m_powerDescriptorFlag) << "):"; -// qCDebug(dcZigbeeNode()) << " Power mode:" << m_powerMode; -// qCDebug(dcZigbeeNode()) << " Available power sources:"; -// foreach (const PowerSource &source, m_availablePowerSources) { -// qCDebug(dcZigbeeNode()) << " " << source; -// } -// qCDebug(dcZigbeeNode()) << " Power source:" << m_powerSource; -// qCDebug(dcZigbeeNode()) << " Power level:" << m_powerLevel; + // qCDebug(dcZigbeeNode()) << "Node power descriptor (" << ZigbeeUtils::convertUint16ToHexString(m_powerDescriptorFlag) << "):"; + // qCDebug(dcZigbeeNode()) << " Power mode:" << m_powerMode; + // qCDebug(dcZigbeeNode()) << " Available power sources:"; + // foreach (const PowerSource &source, m_availablePowerSources) { + // qCDebug(dcZigbeeNode()) << " " << source; + // } + // qCDebug(dcZigbeeNode()) << " Power source:" << m_powerSource; + // qCDebug(dcZigbeeNode()) << " Power level:" << m_powerLevel; } void ZigbeeNode::startInitialization() { - qCWarning(dcZigbeeNode()) << "Start initialization is not implemented for this backend."; + setState(StateInitializing); + + /* Node initialisation steps (sequentially) + * - Node descriptor + * - Power descriptor + * - Active endpoints + * - for each endpoint do: + * - Simple descriptor request + * - for each endpoint + * - read basic cluster + */ + + initNodeDescriptor(); +} + +void ZigbeeNode::initNodeDescriptor() +{ + ZigbeeDeviceObjectReply *reply = deviceObject()->requestNodeDescriptor(); + connect(reply, &ZigbeeDeviceObjectReply::finished, this, [this, reply](){ + if (reply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read node descriptor" << reply->error(); + // FIXME: decide what to do, retry or stop initialization + return; + } + + if (reply->responseAdpu().status != ZigbeeDeviceProfile::StatusSuccess) { + qCWarning(dcZigbeeNode()) << this << "failed to read node descriptor" << reply->responseAdpu().status; + // FIXME: decide what to do, retry or stop initialization + return; + } + + qCDebug(dcZigbeeNode()) << this << "reading node descriptor finished successfully."; + + // Parse and set the node descriptor FIXME: make it nicer using the data types + + QDataStream stream(reply->responseAdpu().payload); + stream.setByteOrder(QDataStream::LittleEndian); + quint8 typeDescriptorFlag = 0; quint8 frequencyFlag = 0; quint8 macCapabilities = 0; + quint16 serverMask = 0; + quint8 descriptorCapabilities = 0; + + stream >> typeDescriptorFlag >> frequencyFlag >> macCapabilities >> m_manufacturerCode >> m_maximumBufferSize; + stream >> m_maximumRxSize >> serverMask >> m_maximumTxSize >> descriptorCapabilities; + + // 0-2 Bit = logical type, 0 = coordinator, 1 = router, 2 = end device + if (!ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) { + m_nodeType = NodeTypeCoordinator; + } else if (!ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) { + m_nodeType = NodeTypeRouter; + } else if (ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) { + m_nodeType = NodeTypeEndDevice; + } + + m_complexDescriptorAvailable = (typeDescriptorFlag >> 3) & 0x0001; + m_userDescriptorAvailable = (typeDescriptorFlag >> 4) & 0x0001; + + // Frequency band, 5 bits + if (ZigbeeUtils::checkBitUint8(frequencyFlag, 3)) { + m_frequencyBand = FrequencyBand868Mhz; + } else if (ZigbeeUtils::checkBitUint8(frequencyFlag, 5)) { + m_frequencyBand = FrequencyBand902Mhz; + } else if (ZigbeeUtils::checkBitUint8(frequencyFlag, 6)) { + m_frequencyBand = FrequencyBand2400Mhz; + } + + setMacCapabilitiesFlag(macCapabilities); + setServerMask(serverMask); + setDescriptorFlag(descriptorCapabilities); + + qCDebug(dcZigbeeNode()) << "Node descriptor:" << ZigbeeUtils::convertUint16ToHexString(shortAddress()) << extendedAddress().toString(); + qCDebug(dcZigbeeNode()) << " Node type:" << nodeType(); + qCDebug(dcZigbeeNode()) << " Complex desciptor available:" << complexDescriptorAvailable(); + qCDebug(dcZigbeeNode()) << " User desciptor available:" << userDescriptorAvailable(); + qCDebug(dcZigbeeNode()) << " Frequency band:" << frequencyBand(); + qCDebug(dcZigbeeNode()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(m_manufacturerCode); + qCDebug(dcZigbeeNode()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximumRxSize) << "(" << m_maximumRxSize << ")"; + qCDebug(dcZigbeeNode()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximumTxSize) << "(" << m_maximumTxSize << ")"; + qCDebug(dcZigbeeNode()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(m_maximumBufferSize) << "(" << m_maximumBufferSize << ")"; + qCDebug(dcZigbeeNode()) << " Server mask:" << ZigbeeUtils::convertUint16ToHexString(serverMask); + qCDebug(dcZigbeeNode()) << " Primary Trust center:" << isPrimaryTrustCenter(); + qCDebug(dcZigbeeNode()) << " Backup Trust center:" << isBackupTrustCenter(); + qCDebug(dcZigbeeNode()) << " Primary Binding cache:" << isPrimaryBindingCache(); + qCDebug(dcZigbeeNode()) << " Backup Binding cache:" << isBackupBindingCache(); + qCDebug(dcZigbeeNode()) << " Primary Discovery cache:" << isPrimaryDiscoveryCache(); + qCDebug(dcZigbeeNode()) << " Backup Discovery cache:" << isBackupDiscoveryCache(); + qCDebug(dcZigbeeNode()) << " Network Manager:" << isNetworkManager(); + qCDebug(dcZigbeeNode()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorCapabilities); + qCDebug(dcZigbeeNode()) << " Extended active endpoint list available:" << extendedActiveEndpointListAvailable(); + qCDebug(dcZigbeeNode()) << " Extended simple descriptor list available:" << extendedSimpleDescriptorListAvailable(); + qCDebug(dcZigbeeNode()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macCapabilities); + qCDebug(dcZigbeeNode()) << " Alternate PAN coordinator:" << alternatePanCoordinator(); + qCDebug(dcZigbeeNode()) << " Device type:" << deviceType(); + qCDebug(dcZigbeeNode()) << " Power source flag main power:" << powerSourceFlagMainPower(); + qCDebug(dcZigbeeNode()) << " Receiver on when idle:" << receiverOnWhenIdle(); + qCDebug(dcZigbeeNode()) << " Security capability:" << securityCapability(); + qCDebug(dcZigbeeNode()) << " Allocate address:" << allocateAddress(); + + + // Continue with the power descriptor + initPowerDescriptor(); + }); +} + +void ZigbeeNode::initPowerDescriptor() +{ + ZigbeeDeviceObjectReply *reply = deviceObject()->requestPowerDescriptor(); + connect(reply, &ZigbeeDeviceObjectReply::finished, this, [this, reply](){ + if (reply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read power descriptor" << reply->error(); + // FIXME: decide what to do, retry or stop initialization + return; + } + + ZigbeeDeviceProfile::Adpu adpu = reply->responseAdpu(); + if (adpu.status != ZigbeeDeviceProfile::StatusSuccess) { + qCWarning(dcZigbeeNode()) << this << "failed to read node descriptor" << adpu.status; + // FIXME: decide what to do, retry or stop initialization + return; + } + + qCDebug(dcZigbeeNode()) << this << "reading power descriptor finished successfully."; + + QDataStream stream(adpu.payload); + stream.setByteOrder(QDataStream::LittleEndian); + quint16 powerDescriptorFlag = 0; + stream >> powerDescriptorFlag; + setPowerDescriptorFlag(powerDescriptorFlag); + + // Continue with endpoint fetching + initEndpoints(); + }); +} + +void ZigbeeNode::initEndpoints() +{ + ZigbeeDeviceObjectReply *reply = deviceObject()->requestActiveEndpoints(); + connect(reply, &ZigbeeDeviceObjectReply::finished, this, [this, reply](){ + if (reply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read active endpoints" << reply->error(); + // FIXME: decide what to do, retry or stop initialization + return; + } + + if (reply->responseAdpu().status != ZigbeeDeviceProfile::StatusSuccess) { + qCWarning(dcZigbeeNode()) << this << "failed to read active endpoints" << reply->responseAdpu().status; + // FIXME: decide what to do, retry or stop initialization + return; + } + + qCDebug(dcZigbeeNode()) << this << "reading active endpoints finished successfully."; + + QDataStream stream(reply->responseAdpu().payload); + stream.setByteOrder(QDataStream::LittleEndian); + quint8 endpointCount = 0; + m_uninitializedEndpoints.clear(); + stream >> endpointCount; + for (int i = 0; i < endpointCount; i++) { + quint8 endpoint = 0; + stream >> endpoint; + m_uninitializedEndpoints.append(endpoint); + } + + qCDebug(dcZigbeeNode()) << "Endpoints (" << endpointCount << ")"; + for (int i = 0; i < m_uninitializedEndpoints.count(); i++) { + qCDebug(dcZigbeeNode()) << " -" << ZigbeeUtils::convertByteToHexString(m_uninitializedEndpoints.at(i)); + } + + // If there a no endpoints or all endpoints have already be initialized, continue with reading the basic cluster information + if (m_uninitializedEndpoints.isEmpty()) { + initBasicCluster(); + } + + // Read simple descriptor for each uninitialized endpoint + for (int i = 0; i < m_uninitializedEndpoints.count(); i++) { + quint8 endpointId = m_uninitializedEndpoints.at(i); + qCDebug(dcZigbeeNode()) << "Read simple descriptor of endpoint" << ZigbeeUtils::convertByteToHexString(endpointId); + initEndpoint(endpointId); + } + }); +} + + +void ZigbeeNode::initEndpoint(quint8 endpointId) +{ + ZigbeeDeviceObjectReply *reply = deviceObject()->requestSimpleDescriptor(endpointId); + connect(reply, &ZigbeeDeviceObjectReply::finished, this, [this, reply, endpointId](){ + if (reply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read simple descriptor for endpoint" << endpointId << reply->error(); + // FIXME: decide what to do, retry or stop initialization + return; + } + + if (reply->responseAdpu().status != ZigbeeDeviceProfile::StatusSuccess) { + qCWarning(dcZigbeeNode()) << this << "failed to read simple descriptor from endpoint" << endpointId << reply->responseAdpu().status; + // FIXME: decide what to do, retry or stop initialization + return; + } + + qCDebug(dcZigbeeNode()) << this << "reading simple descriptor for endpoint" << endpointId << "finished successfully."; + + quint8 length = 0; quint8 endpointId = 0; quint16 profileId = 0; quint16 deviceId = 0; quint8 deviceVersion = 0; + quint8 inputClusterCount = 0; quint8 outputClusterCount = 0; + QList inputClusters; + QList outputClusters; + + QDataStream stream(reply->responseAdpu().payload); + stream.setByteOrder(QDataStream::LittleEndian); + stream >> length >> endpointId >> profileId >> deviceId >> deviceVersion >> inputClusterCount; + + qCDebug(dcZigbeeNode()) << "Node endpoint simple descriptor:"; + qCDebug(dcZigbeeNode()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); + qCDebug(dcZigbeeNode()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endpointId); + qCDebug(dcZigbeeNode()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); + if (profileId == Zigbee::ZigbeeProfileLightLink) { + qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); + } else if (profileId == Zigbee::ZigbeeProfileHomeAutomation) { + qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); + } else if (profileId == Zigbee::ZigbeeProfileGreenPower) { + qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); + } + + qCDebug(dcZigbeeNode()) << " Device version:" << ZigbeeUtils::convertByteToHexString(deviceVersion); + + // Create endpoint + ZigbeeNodeEndpoint *endpoint = nullptr; + if (!hasEndpoint(endpointId)) { + endpoint = new ZigbeeNodeEndpoint(m_network, this, endpointId, this); + m_endpoints.append(endpoint); + } else { + endpoint = getEndpoint(endpointId); + } + endpoint->setProfile(static_cast(profileId)); + endpoint->setDeviceId(deviceId); + endpoint->setDeviceVersion(deviceVersion); + + qCDebug(dcZigbeeNode()) << " Input clusters: (" << inputClusterCount << ")"; + for (int i = 0; i < inputClusterCount; i++) { + quint16 clusterId = 0; + stream >> clusterId; + if (!endpoint->hasInputCluster(static_cast(clusterId))) { + endpoint->addInputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast(clusterId), ZigbeeCluster::Input, endpoint)); + } + qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + + } + stream >> outputClusterCount; + + qCDebug(dcZigbeeNode()) << " Output clusters: (" << outputClusterCount << ")"; + for (int i = 0; i < outputClusterCount; i++) { + quint16 clusterId = 0; + stream >> clusterId; + if (!endpoint->hasOutputCluster(static_cast(clusterId))) { + endpoint->addOutputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast(clusterId), ZigbeeCluster::Output, endpoint)); + } + qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + } + + m_uninitializedEndpoints.removeAll(endpointId); + + if (m_uninitializedEndpoints.isEmpty()) { + + //if (m_shortAddress == 0) { + setState(StateInitialized); + return; + //} + + // Continue with the basic cluster attributes + //initBasicCluster(); + } + }); +} + +void ZigbeeNode::initBasicCluster() +{ + } void ZigbeeNode::onClusterAttributeChanged(const ZigbeeClusterAttribute &attribute) @@ -511,7 +787,6 @@ QDebug operator<<(QDebug debug, ZigbeeNode *node) { debug.nospace().noquote() << "ZigbeeNode(" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress()); debug.nospace().noquote() << ", " << node->extendedAddress().toString(); - debug.nospace().noquote() << ", " << node->nodeType(); debug.nospace().noquote() << ")"; return debug.space(); } diff --git a/libnymea-zigbee/zigbeenode.h b/libnymea-zigbee/zigbeenode.h index 400d6af..3b8c932 100644 --- a/libnymea-zigbee/zigbeenode.h +++ b/libnymea-zigbee/zigbeenode.h @@ -100,6 +100,45 @@ public: }; Q_ENUM(PowerLevel) + typedef struct MacCapabilities { + bool alternatePanCoordinator = false; + DeviceType deviceType = DeviceTypeReducedFunction; + bool powerSourceFlagMainPower = false; + bool receiverOnWhenIdle = false; + bool securityCapability = false; + bool allocateAddress = false; + } MacCapabilities; + + typedef struct DescriptorCapabilities { + bool extendedActiveEndpointListAvailable = false; + bool extendedSimpleDescriptorListAvailable = false; + } DescriptorCapabilities; + + typedef struct ServerMask { + bool primaryTrustCenter = false; + bool backupTrustCenter = false; + bool primaryBindingCache = false; + bool backupBindingCache = false; + bool primaryDiscoveryCache = false; + bool backupDiscoveryCache = false; + bool networkManager = false; + quint8 stackComplianceVersion = 0; + } ServerMask; + + typedef struct NodeDescriptor { + NodeType nodeType = NodeTypeRouter; + bool complexDescriptorAvailable = false; + bool userDescriptorAvailable = false; + FrequencyBand frequencyBand = FrequencyBand2400Mhz; + MacCapabilities macCapabilities; + quint16 manufacturerCode = 0; + quint8 maximumBufferSize = 0; + quint16 maximumRxSize = 0; + ServerMask serverMask; + quint16 maximumTxSize = 0; + DescriptorCapabilities descriptorCapabilities; + } NodeDescriptor; + State state() const; bool connected() const; @@ -152,50 +191,11 @@ public: QList availablePowerSources() const; PowerLevel powerLevel() const; - virtual void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) = 0; + // This method starts the node initialization phase (read descriptors and endpoints) + void startInitialization(); private: - bool m_connected = false; - State m_state = StateUninitialized; - - quint16 m_shortAddress = 0; - ZigbeeAddress m_extendedAddress; - - // Server Mask - quint16 m_serverMask = 0; - bool m_isPrimaryTrustCenter = false; - bool m_isBackupTrustCenter = false; - bool m_isPrimaryBindingCache = false; - bool m_isBackupBindingCache = false; - bool m_isPrimaryDiscoveryCache = false; - bool m_isBackupDiscoveryCache = false; - bool m_isNetworkManager = false; - - // Power information - quint16 m_powerDescriptorFlag = 0; - PowerMode m_powerMode; - PowerSource m_powerSource; - QList m_availablePowerSources; - PowerLevel m_powerLevel; - - // Mac capabilities flag - quint8 m_macCapabilitiesFlag = 0; - bool m_alternatePanCoordinator = false; - DeviceType m_deviceType = DeviceTypeFullFunction; - bool m_powerSourceFlagMainPower = false; - bool m_receiverOnWhenIdle = false; - bool m_securityCapability = false; - bool m_allocateAddress = false; - - // Descriptor capability - quint8 m_descriptorFlag = 0; - bool m_extendedActiveEndpointListAvailable = false; - bool m_extendedSimpleDescriptorListAvailable = false; - - virtual void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) = 0; - -protected: - ZigbeeNode(ZigbeeNetwork *network, QObject *parent = nullptr); + ZigbeeNode(ZigbeeNetwork *network, quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent = nullptr); ZigbeeNetwork *m_network; ZigbeeDeviceObject *m_deviceObject = nullptr; @@ -235,9 +235,55 @@ protected: quint16 powerDescriptorFlag() const; void setPowerDescriptorFlag(quint16 powerDescriptorFlag); - // This method starts the node initialization phase (read descriptors and endpoints) - virtual void startInitialization(); - virtual ZigbeeNodeEndpoint *createNodeEndpoint(quint8 endpointId, QObject *parent) = 0; + bool m_connected = false; + State m_state = StateUninitialized; + + quint16 m_shortAddress = 0; + ZigbeeAddress m_extendedAddress; + + // Server Mask + quint16 m_serverMask = 0; + bool m_isPrimaryTrustCenter = false; + bool m_isBackupTrustCenter = false; + bool m_isPrimaryBindingCache = false; + bool m_isBackupBindingCache = false; + bool m_isPrimaryDiscoveryCache = false; + bool m_isBackupDiscoveryCache = false; + bool m_isNetworkManager = false; + + // Power information + quint16 m_powerDescriptorFlag = 0; + PowerMode m_powerMode; + PowerSource m_powerSource; + QList m_availablePowerSources; + PowerLevel m_powerLevel; + + // Mac capabilities flag + quint8 m_macCapabilitiesFlag = 0; + bool m_alternatePanCoordinator = false; + DeviceType m_deviceType = DeviceTypeFullFunction; + bool m_powerSourceFlagMainPower = false; + bool m_receiverOnWhenIdle = false; + bool m_securityCapability = false; + bool m_allocateAddress = false; + + // Descriptor capability + quint8 m_descriptorFlag = 0; + bool m_extendedActiveEndpointListAvailable = false; + bool m_extendedSimpleDescriptorListAvailable = false; + + //virtual void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) = 0; + + // Init methods + void initNodeDescriptor(); + void initPowerDescriptor(); + void initEndpoints(); + void initEndpoint(quint8 endpointId); + void initBasicCluster(); + + QList m_uninitializedEndpoints; + QList m_uninitalizedBasicClusterAttributes; + signals: void stateChanged(State state); diff --git a/libnymea-zigbee/zigbeenodeendpoint.cpp b/libnymea-zigbee/zigbeenodeendpoint.cpp index 49a8966..1cdb72c 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.cpp +++ b/libnymea-zigbee/zigbeenodeendpoint.cpp @@ -110,8 +110,9 @@ bool ZigbeeNodeEndpoint::hasOutputCluster(Zigbee::ClusterId clusterId) const return m_outputClusters.keys().contains(clusterId); } -ZigbeeNodeEndpoint::ZigbeeNodeEndpoint(ZigbeeNode *node, quint8 endpointId, QObject *parent) : +ZigbeeNodeEndpoint::ZigbeeNodeEndpoint(ZigbeeNetwork *network, ZigbeeNode *node, quint8 endpointId, QObject *parent) : QObject(parent), + m_network(network), m_node(node), m_endpointId(endpointId) { @@ -163,10 +164,10 @@ ZigbeeNetworkReply *ZigbeeNodeEndpoint::createNetworkReply(const ZigbeeNetworkRe return reply; } -void ZigbeeNodeEndpoint::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error, Zigbee::ZigbeeStatus zigbeeStatus) +void ZigbeeNodeEndpoint::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error, Zigbee::ZigbeeApsStatus zigbeeApsStatus) { reply->m_error = error; - reply->m_zigbeeStatus = zigbeeStatus; + reply->m_zigbeeApsStatus = zigbeeApsStatus; reply->finished(); } diff --git a/libnymea-zigbee/zigbeenodeendpoint.h b/libnymea-zigbee/zigbeenodeendpoint.h index 065cf54..32b86b1 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.h +++ b/libnymea-zigbee/zigbeenodeendpoint.h @@ -36,6 +36,7 @@ #include "zigbeenetworkreply.h" class ZigbeeNode; +class ZigbeeNetwork; class ZigbeeNodeEndpoint : public QObject { @@ -74,14 +75,15 @@ public: bool hasOutputCluster(Zigbee::ClusterId clusterId) const; private: + explicit ZigbeeNodeEndpoint(ZigbeeNetwork *network, ZigbeeNode *node, quint8 endpointId, QObject *parent = nullptr); + + ZigbeeNetwork *m_network = nullptr; ZigbeeNode *m_node = nullptr; quint8 m_endpointId = 0; Zigbee::ZigbeeProfile m_profile = Zigbee::ZigbeeProfileLightLink; quint16 m_deviceId = 0; quint8 m_deviceVersion = 0; -protected: - explicit ZigbeeNodeEndpoint(ZigbeeNode *node, quint8 endpointId, QObject *parent = nullptr); QHash m_inputClusters; QHash m_outputClusters; @@ -95,14 +97,14 @@ protected: void setSoftwareBuildId(const QString &softwareBuildId); // Cluster commands - virtual void setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute = ZigbeeClusterAttribute()) = 0; + //virtual void setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute = ZigbeeClusterAttribute()) = 0; void addInputCluster(ZigbeeCluster *cluster); void addOutputCluster(ZigbeeCluster *cluster); // Network reply methods ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest()); - void finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error = ZigbeeNetworkReply::ErrorNoError, Zigbee::ZigbeeStatus zigbeeStatus = Zigbee::ZigbeeStatusSuccess); + void finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error = ZigbeeNetworkReply::ErrorNoError, Zigbee::ZigbeeApsStatus zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess); signals: void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute); diff --git a/libnymea-zigbee/zigbeeutils.cpp b/libnymea-zigbee/zigbeeutils.cpp index 8d2f6c0..0d9e293 100644 --- a/libnymea-zigbee/zigbeeutils.cpp +++ b/libnymea-zigbee/zigbeeutils.cpp @@ -260,15 +260,15 @@ QString ZigbeeUtils::convertUint64ToHexString(const quint64 &value) return QString("0x%1").arg(convertByteArrayToHexString(data).remove(" ").remove("0x")); } -QString ZigbeeUtils::messageTypeToString(const Zigbee::InterfaceMessageType &type) -{ - QMetaObject metaObject = Zigbee::staticMetaObject; - QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("InterfaceMessageType")); +//QString ZigbeeUtils::messageTypeToString(const Zigbee::InterfaceMessageType &type) +//{ +// QMetaObject metaObject = Zigbee::staticMetaObject; +// QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("InterfaceMessageType")); - QString enumString = metaEnum.valueToKey(type); +// QString enumString = metaEnum.valueToKey(type); - return enumString.remove("Zigbee::InterfaceMessageType(MessageType").remove(")"); -} +// return enumString.remove("Zigbee::InterfaceMessageType(MessageType").remove(")"); +//} QString ZigbeeUtils::clusterIdToString(const Zigbee::ClusterId &clusterId) { diff --git a/libnymea-zigbee/zigbeeutils.h b/libnymea-zigbee/zigbeeutils.h index 2460f97..5b91126 100644 --- a/libnymea-zigbee/zigbeeutils.h +++ b/libnymea-zigbee/zigbeeutils.h @@ -61,7 +61,7 @@ public: static QString convertUint64ToHexString(const quint64 &value); // Enum prittify print methods - static QString messageTypeToString(const Zigbee::InterfaceMessageType &type); + //static QString messageTypeToString(const Zigbee::InterfaceMessageType &type); static QString clusterIdToString(const Zigbee::ClusterId &clusterId); static QString profileIdToString(const Zigbee::ZigbeeProfile &profileId);