Make basic node adding mechanism work

This commit is contained in:
Simon Stürz 2020-05-20 19:54:58 +02:00
parent 7cdf772b1a
commit 029ca76bae
38 changed files with 1340 additions and 1117 deletions

View File

@ -296,7 +296,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
for (int i = 0; i < asdu.length(); i++) {
stream << static_cast<quint8>(asdu.at(i));
}
stream << static_cast<quint8>(txOptions); // TX Options: Use ASP ACKs
stream << static_cast<quint8>(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<quint8>(asdu.at(i));
}
stream << static_cast<quint8>(txOptions); // TX Options: Use ASP ACKs
stream << static_cast<quint8>(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<Deconz::NetworkState>(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<int>(deviceState.aspDataConfirm) << ", ";
debug.nospace() << "Indication=" << static_cast<int>(deviceState.aspDataIndication) << ", ";
debug.nospace() << "Confirm=" << static_cast<int>(deviceState.apsDataConfirm) << ", ";
debug.nospace() << "Indication=" << static_cast<int>(deviceState.apsDataIndication) << ", ";
debug.nospace() << "ConfigChanged=" << static_cast<int>(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;

View File

@ -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);

View File

@ -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<ZigbeeNodeDeconz *>(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<ZigbeeDeviceProfile::ZdoCommand>(reply->request().clusterId())
<< "-->"
<< static_cast<ZigbeeDeviceProfile::ZdoCommand>(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<ZigbeeDeviceProfile::ZdoCommand>(reply->request().clusterId())
// << "-->"
// << static_cast<ZigbeeDeviceProfile::ZdoCommand>(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<Zigbee::ZigbeeStatus>(confirm.zigbeeStatusCode));
setReplyResponseError(reply, static_cast<Zigbee::ZigbeeApsStatus>(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<ZigbeeNodeDeconz *>(createNode(this));
node->setExtendedAddress(ieeeAddress);
node->setShortAddress(shortAddress);
node->setMacCapabilitiesFlag(macCapabilities);
ZigbeeNode *node = createNode(shortAddress, ieeeAddress, macCapabilities, this);
addUnitializedNode(node);
node->startInitialization();
}

View File

@ -31,7 +31,6 @@
#include <QObject>
#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);

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 <QDataStream>
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<quint16> inputClusters;
QList<quint16> 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<Zigbee::ZigbeeProfile>(profileId));
if (profileId == Zigbee::ZigbeeProfileLightLink) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::LightLinkDevice>(deviceId);
} else if (profileId == Zigbee::ZigbeeProfileHomeAutomation) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::HomeAutomationDevice>(deviceId);
} else if (profileId == Zigbee::ZigbeeProfileGreenPower) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::GreenPowerDevice>(deviceId);
}
qCDebug(dcZigbeeNode()) << " Device version:" << ZigbeeUtils::convertByteToHexString(deviceVersion);
// Create endpoint
ZigbeeNodeEndpointDeconz *endpoint = nullptr;
if (!hasEndpoint(endpointId)) {
endpoint = qobject_cast<ZigbeeNodeEndpointDeconz *>(createNodeEndpoint(endpointId, this));
m_endpoints.append(endpoint);
} else {
endpoint = qobject_cast<ZigbeeNodeEndpointDeconz *>(getEndpoint(endpointId));
}
endpoint->setProfile(static_cast<Zigbee::ZigbeeProfile>(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<Zigbee::ClusterId>(clusterId))) {
endpoint->addInputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Input, endpoint));
}
qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(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<Zigbee::ClusterId>(clusterId))) {
endpoint->addOutputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Output, endpoint));
}
qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(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<ZigbeeNodeEndpoint *>(new ZigbeeNodeEndpointDeconz(m_network, this, endpointId, parent));
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 <QObject>
#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<quint8> m_uninitializedEndpoints;
QList<quint16> m_uninitalizedBasicClusterAttributes;
void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override;
protected:
void startInitialization() override;
ZigbeeNodeEndpoint *createNodeEndpoint(quint8 endpointId, QObject *parent) override;
private slots:
};
#endif // ZIGBEENODEDECONZ_H

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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)
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 <QObject>
#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

View File

@ -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 \

View File

@ -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")

View File

@ -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)

View File

@ -0,0 +1,6 @@
#include "zigbeeclusterreply.h"
ZigbeeClusterReply::ZigbeeClusterReply(QObject *parent) : QObject(parent)
{
}

View File

@ -0,0 +1,16 @@
#ifndef ZIGBEECLUSTERREPLY_H
#define ZIGBEECLUSTERREPLY_H
#include <QObject>
class ZigbeeClusterReply : public QObject
{
Q_OBJECT
public:
explicit ZigbeeClusterReply(QObject *parent = nullptr);
signals:
};
#endif // ZIGBEECLUSTERREPLY_H

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 <QDataStream>
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<ZigbeeDeviceProfile::ZdoCommand>(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<ZigbeeDeviceProfile::ZdoCommand>(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<ZigbeeDeviceProfile::ZdoCommand>(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<ZigbeeDeviceProfile::ZdoCommand>(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<ZigbeeDeviceProfile::ZdoCommand>(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<ZigbeeDeviceProfile::ZdoCommand>(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";
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 <QObject>
#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<quint8, ZigbeeDeviceObjectReply *> 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

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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;
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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 <QObject>
#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();
};

View File

@ -30,22 +30,22 @@
#include <QDataStream>
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<Zigbee::ZigbeeStatus>(statusFlag);
stream >> deviceAdpu.transactionSequenceNumber >> statusFlag >> deviceAdpu.addressOfInterest;
deviceAdpu.status = static_cast<ZigbeeDeviceProfile::Status>(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) << ")";

View File

@ -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

View File

@ -1,6 +0,0 @@
#include "zigbeedeviceprofilehandler.h"
ZigbeeDeviceProfileHandler::ZigbeeDeviceProfileHandler(QObject *parent) : QObject(parent)
{
}

View File

@ -1,16 +0,0 @@
#ifndef ZIGBEEDEVICEPROFILEHANDLER_H
#define ZIGBEEDEVICEPROFILEHANDLER_H
#include <QObject>
class ZigbeeDeviceProfileHandler : public QObject
{
Q_OBJECT
public:
explicit ZigbeeDeviceProfileHandler(QObject *parent = nullptr);
signals:
};
#endif // ZIGBEEDEVICEPROFILEHANDLER_H

View File

@ -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,

View File

@ -81,10 +81,8 @@ private:
FrameControl m_frameControl;
quint8 m_destinationEndpoint;
quint8 buildFrameControlByte(FrameControl frameControl);
FrameControl readFrameControlByte(quint8 frameControlByte);
signals:
};

View File

@ -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<quint16>(settings.value("nwkAddress", 0).toUInt()));
quint16 shortAddress = static_cast<quint16>(settings.value("nwkAddress", 0).toUInt());
ZigbeeNode *node = createNode(shortAddress, ZigbeeAddress(ieeeAddressString), this);
// Node descriptor
node->m_nodeType = static_cast<ZigbeeNode::NodeType>(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<quint8>(settings.value("id", 0).toUInt());
ZigbeeNodeEndpoint *endpoint = node->createNodeEndpoint(endpointId, node);
ZigbeeNodeEndpoint *endpoint = new ZigbeeNodeEndpoint(this, node, endpointId, node);
endpoint->m_profile = static_cast<Zigbee::ZigbeeProfile>(settings.value("profile", 0).toUInt());
endpoint->m_deviceId = static_cast<quint16>(settings.value("deviceId", 0).toUInt());
endpoint->m_deviceVersion = static_cast<quint8>(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);
}
}

View File

@ -34,6 +34,7 @@
#include <QSqlDatabase>
#include "zigbeenode.h"
#include "zigbeenodeendpoint.h"
#include "zigbeechannelmask.h"
#include "zigbeebridgecontroller.h"
#include "zigbeesecurityconfiguration.h"
@ -134,11 +135,7 @@ private:
QList<ZigbeeNode *> m_nodes;
QList<ZigbeeNode *> 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:

View File

@ -28,7 +28,6 @@
#include "zigbeenetworkmanager.h"
#include "loggingcategory.h"
#include "nxp/zigbeenetworknxp.h"
#include "deconz/zigbeenetworkdeconz.h"
#include <QDateTime>
@ -39,8 +38,8 @@ ZigbeeNetwork *ZigbeeNetworkManager::createZigbeeNetwork(ZigbeeNetworkManager::B
srand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch() / 1000));
switch (backend) {
case BackendTypeNxp:
return qobject_cast<ZigbeeNetwork *>(new ZigbeeNetworkNxp(parent));
// case BackendTypeNxp:
// return qobject_cast<ZigbeeNetwork *>(new ZigbeeNetworkNxp(parent));
case BackendTypeDeconz:
return qobject_cast<ZigbeeNetwork *>(new ZigbeeNetworkDeconz(parent));
}

View File

@ -36,7 +36,6 @@ class ZigbeeNetworkManager
{
public:
enum BackendType {
BackendTypeNxp,
BackendTypeDeconz
};

View File

@ -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) :

View File

@ -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();

View File

@ -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();
}

View File

@ -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);

View File

@ -32,11 +32,13 @@
#include <QDataStream>
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<quint16> inputClusters;
QList<quint16> 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<Zigbee::ZigbeeProfile>(profileId));
if (profileId == Zigbee::ZigbeeProfileLightLink) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::LightLinkDevice>(deviceId);
} else if (profileId == Zigbee::ZigbeeProfileHomeAutomation) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::HomeAutomationDevice>(deviceId);
} else if (profileId == Zigbee::ZigbeeProfileGreenPower) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::GreenPowerDevice>(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<Zigbee::ZigbeeProfile>(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<Zigbee::ClusterId>(clusterId))) {
endpoint->addInputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Input, endpoint));
}
qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(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<Zigbee::ClusterId>(clusterId))) {
endpoint->addOutputCluster(new ZigbeeCluster(m_network, this, endpoint, static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Output, endpoint));
}
qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(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();
}

View File

@ -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<PowerSource> 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<PowerSource> 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<PowerSource> 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<quint8> m_uninitializedEndpoints;
QList<quint16> m_uninitalizedBasicClusterAttributes;
signals:
void stateChanged(State state);

View File

@ -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();
}

View File

@ -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<Zigbee::ClusterId, ZigbeeCluster *> m_inputClusters;
QHash<Zigbee::ClusterId, ZigbeeCluster *> 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);

View File

@ -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)
{

View File

@ -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);