Restructure the descriptor handling and implement level control cluster server side

This commit is contained in:
Simon Stürz 2020-06-03 19:50:47 +02:00
parent b5b6709da3
commit 80d4b1416e
23 changed files with 892 additions and 1025 deletions

View File

@ -73,8 +73,7 @@ private slots:
public slots:
void sendPackage(const QByteArray &package);
bool enable(const QString &serialPort = "/dev/ttyS0", qint32 baudrate = 115200);
bool enable(const QString &serialPort = "/dev/ttyS0", qint32 baudrate = 38400);
void reconnectController();
void disable();

View File

@ -27,6 +27,11 @@
#include "zigbeeinterfacedeconzreply.h"
ZigbeeNetworkRequest ZigbeeInterfaceDeconzReply::networkRequest() const
{
return m_networkRequest;
}
Deconz::Command ZigbeeInterfaceDeconzReply::command() const
{
return m_command;
@ -47,6 +52,11 @@ Deconz::StatusCode ZigbeeInterfaceDeconzReply::statusCode() const
return m_statusCode;
}
bool ZigbeeInterfaceDeconzReply::timendOut() const
{
return m_timeout;
}
bool ZigbeeInterfaceDeconzReply::aborted() const
{
return m_aborted;
@ -64,7 +74,7 @@ ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command,
m_command(command),
m_sequenceNumber(sequenceNumber)
{
m_timer->setInterval(2000);
m_timer->setInterval(5000);
m_timer->setSingleShot(true);
connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceDeconzReply::onTimeout);
}

View File

@ -32,6 +32,7 @@
#include <QTimer>
#include "deconz.h"
#include "zigbeenetworkrequest.h"
class ZigbeeInterfaceDeconzReply : public QObject
{
@ -41,6 +42,7 @@ class ZigbeeInterfaceDeconzReply : public QObject
public:
// Request content
ZigbeeNetworkRequest networkRequest() const;
Deconz::Command command() const;
quint8 sequenceNumber() const;
QByteArray responseData() const;
@ -48,12 +50,13 @@ public:
// Response content
Deconz::StatusCode statusCode() const;
bool timeout() const;
bool timendOut() const;
bool aborted() const;
void abort();
private:
explicit ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent = nullptr);
ZigbeeNetworkRequest m_networkRequest;
QTimer *m_timer = nullptr;
bool m_timeout = false;
bool m_aborted = false;

View File

@ -221,6 +221,66 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestQuerySendDataCo
return createReply(Deconz::CommandApsDataConfirm, sequenceNumber, this);
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(const ZigbeeNetworkRequest &request)
{
// Send the request only if there are free slots on the device, otherwise enque request
// if (m_apsFreeSlotsAvailable) {
// }
qCDebug(dcZigbeeAps()) << "APSDE-DATA.request" << request;
ZigbeeInterfaceDeconzReply *interfaceReply = nullptr;
switch (request.destinationAddressMode()) {
case Zigbee::DestinationAddressModeGroup:
interfaceReply = requestEnqueueSendDataGroup(request.requestId(), request.destinationShortAddress(),
request.profileId(), request.clusterId(),request.sourceEndpoint(),
request.asdu(), request.txOptions(), request.radius());
break;
case Zigbee::DestinationAddressModeShortAddress:
interfaceReply = requestEnqueueSendDataShortAddress(request.requestId(), request.destinationShortAddress(),
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.txOptions(), request.radius());
break;
case Zigbee::DestinationAddressModeIeeeAddress:
interfaceReply = requestEnqueueSendDataIeeeAddress(request.requestId(), request.destinationIeeeAddress(),
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.txOptions(), request.radius());
break;
}
return interfaceReply;
}
quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber()
{
return m_sequenceNumber++;
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent)
{
// Create the reply
ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(command, sequenceNumber, parent);
connect(reply, &ZigbeeInterfaceDeconzReply::timeout, this, [this, reply](){
qCWarning(dcZigbeeController()) << "Reply timeout" << reply->command() << "SQN:" << reply->sequenceNumber();
if (m_pendingReplies.contains(reply->sequenceNumber())) {
m_pendingReplies.remove(reply->sequenceNumber());
// Note: will be deleted with the finished signal
}
});
// Auto delete the object on finished
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection);
// Add it to the pending list
m_pendingReplies.insert(sequenceNumber, reply);
// Fixme: start the timer once actually sent to the interface
reply->m_timer->start();
return reply;
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius)
{
quint8 sequenceNumber = generateSequenceNumber();
@ -313,7 +373,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
<< profileId << clusterId
<< ZigbeeUtils::convertByteToHexString(sourceEndpoint);
Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes");
Q_ASSERT_X(asdu.length() <= 127, "ZigbeeController", "ASDU package length has to be <= 127 bytes");
// Note: 21 protocol bytes + asdu package length
quint16 payloadLength = static_cast<quint16>(21 + asdu.length());
@ -345,53 +405,6 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this);
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(const ZigbeeNetworkRequest &request)
{
qCDebug(dcZigbeeAps()) << "APSDE-DATA.request" << request;
ZigbeeInterfaceDeconzReply *interfaceReply = nullptr;
switch (request.destinationAddressMode()) {
case Zigbee::DestinationAddressModeGroup:
interfaceReply = requestEnqueueSendDataGroup(request.requestId(), request.destinationShortAddress(),
request.profileId(), request.clusterId(),request.sourceEndpoint(),
request.asdu(), request.txOptions(), request.radius());
break;
case Zigbee::DestinationAddressModeShortAddress:
interfaceReply = requestEnqueueSendDataShortAddress(request.requestId(), request.destinationShortAddress(),
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.txOptions(), request.radius());
break;
case Zigbee::DestinationAddressModeIeeeAddress:
interfaceReply = requestEnqueueSendDataIeeeAddress(request.requestId(), request.destinationIeeeAddress(),
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.txOptions(), request.radius());
break;
}
return interfaceReply;
}
quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber()
{
return m_sequenceNumber++;
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent)
{
// Create the reply
ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(command, sequenceNumber, parent);
// Auto delete the object on finished
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection);
// Add it to the pending list
m_pendingReplies.insert(sequenceNumber, reply);
// Fixme: start the timer once actually sent to the interface
reply->m_timer->start();
return reply;
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters()
{
qCDebug(dcZigbeeController()) << "Start reading network parameters";
@ -408,8 +421,8 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
ZigbeeInterfaceDeconzReply *replyMacAddress = requestReadParameter(Deconz::ParameterMacAddress);
connect(replyMacAddress, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyMacAddress](){
if (replyMacAddress->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyMacAddress->command() << Deconz::ParameterMacAddress
<< "finished with error" << replyMacAddress->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyMacAddress->sequenceNumber() << replyMacAddress->command()
<< Deconz::ParameterMacAddress << "finished with error" << replyMacAddress->statusCode();
readNetworkParametersReply->m_statusCode = replyMacAddress->statusCode();
readNetworkParametersReply->finished();
@ -421,16 +434,16 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
stream >> payloadLenght >> parameter >> macAddress;
m_networkConfiguration.ieeeAddress = ZigbeeAddress(macAddress);
qCDebug(dcZigbeeController()) << "Request" << replyMacAddress->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyMacAddress->sequenceNumber() << replyMacAddress->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << "IEEE address:" << m_networkConfiguration.ieeeAddress.toString();
// Read PAN ID
ZigbeeInterfaceDeconzReply *replyPanId = requestReadParameter(Deconz::ParameterPanId);
connect(replyPanId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyPanId](){
if (replyPanId->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyPanId->command() << Deconz::ParameterPanId
<< "finished with error" << replyPanId->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyPanId->sequenceNumber() << replyPanId->command()
<< Deconz::ParameterPanId << "finished with error" << replyPanId->statusCode();
readNetworkParametersReply->m_statusCode = replyPanId->statusCode();
readNetworkParametersReply->finished();
return;
@ -441,15 +454,15 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
stream >> payloadLenght >> parameter >> panId;
m_networkConfiguration.panId = panId;
qCDebug(dcZigbeeController()) << "Request" << replyPanId->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyPanId->sequenceNumber() << replyPanId->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << "PAN ID:" << ZigbeeUtils::convertUint16ToHexString(m_networkConfiguration.panId);
// Read short address
ZigbeeInterfaceDeconzReply *replyShortAddress = requestReadParameter(Deconz::ParameterNetworkAddress);
connect(replyShortAddress, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyShortAddress](){
if (replyShortAddress->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyShortAddress->command() << Deconz::ParameterNetworkAddress
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyShortAddress->sequenceNumber() << replyShortAddress->command() << Deconz::ParameterNetworkAddress
<< "finished with error" << replyShortAddress->statusCode();
readNetworkParametersReply->m_statusCode = replyShortAddress->statusCode();
readNetworkParametersReply->finished();
@ -461,16 +474,16 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
quint16 payloadLenght = 0; quint8 parameter = 0; quint16 shortAddress = 0;
stream >> payloadLenght >> parameter >> shortAddress;
m_networkConfiguration.shortAddress = shortAddress;
qCDebug(dcZigbeeController()) << "Request" << replyShortAddress->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyShortAddress->sequenceNumber()
<< replyShortAddress->command() << static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << ZigbeeUtils::convertUint16ToHexString(m_networkConfiguration.shortAddress);
// Read extended PAN ID
ZigbeeInterfaceDeconzReply *replyExtendedPanId = requestReadParameter(Deconz::ParameterNetworkExtendedPanId);
connect(replyExtendedPanId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyExtendedPanId](){
if (replyExtendedPanId->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyExtendedPanId->command() << Deconz::ParameterNetworkExtendedPanId
<< "finished with error" << replyExtendedPanId->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyExtendedPanId->sequenceNumber() << replyExtendedPanId->command()
<< Deconz::ParameterNetworkExtendedPanId << "finished with error" << replyExtendedPanId->statusCode();
readNetworkParametersReply->m_statusCode = replyExtendedPanId->statusCode();
readNetworkParametersReply->finished();
return;
@ -481,7 +494,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
quint16 payloadLenght = 0; quint8 parameter = 0; quint64 networkExtendedPanId = 0;
stream >> payloadLenght >> parameter >> networkExtendedPanId;
m_networkConfiguration.extendedPanId = networkExtendedPanId;
qCDebug(dcZigbeeController()) << "Request" << replyExtendedPanId->command() << static_cast<Deconz::Parameter>(parameter)
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyExtendedPanId->sequenceNumber() << replyExtendedPanId->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << ZigbeeUtils::convertUint64ToHexString(m_networkConfiguration.extendedPanId);
@ -489,8 +502,8 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
ZigbeeInterfaceDeconzReply *replyNodeType = requestReadParameter(Deconz::ParameterNodeType);
connect(replyNodeType, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyNodeType](){
if (replyNodeType->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyNodeType->command() << Deconz::ParameterNodeType
<< "finished with error" << replyNodeType->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyNodeType->sequenceNumber() << replyNodeType->command()
<< Deconz::ParameterNodeType << "finished with error" << replyNodeType->statusCode();
readNetworkParametersReply->m_statusCode = replyNodeType->statusCode();
readNetworkParametersReply->finished();
return;
@ -502,7 +515,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
stream >> payloadLenght >> parameter >> nodeType;
m_networkConfiguration.nodeType = static_cast<Deconz::NodeType>(nodeType);
qCDebug(dcZigbeeController()) << "Request" << replyNodeType->command() << static_cast<Deconz::Parameter>(parameter)
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyNodeType->sequenceNumber() << replyNodeType->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << m_networkConfiguration.nodeType;
@ -510,7 +523,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
ZigbeeInterfaceDeconzReply *replyChannelMask = requestReadParameter(Deconz::ParameterChannelMask);
connect(replyChannelMask, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyChannelMask](){
if (replyChannelMask->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyChannelMask->command() << Deconz::ParameterChannelMask
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyChannelMask->sequenceNumber() << replyChannelMask->command() << Deconz::ParameterChannelMask
<< "finished with error" << replyChannelMask->statusCode();
readNetworkParametersReply->m_statusCode = replyChannelMask->statusCode();
readNetworkParametersReply->finished();
@ -523,16 +536,16 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
stream >> payloadLenght >> parameter >> channelMask;
m_networkConfiguration.channelMask = channelMask;
qCDebug(dcZigbeeController()) << "Request" << replyChannelMask->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyChannelMask->sequenceNumber() << replyChannelMask->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << ZigbeeUtils::convertUint32ToHexString(m_networkConfiguration.channelMask);
// Read APS extended PAN ID
ZigbeeInterfaceDeconzReply *replyApsExtendedPanId = requestReadParameter(Deconz::ParameterApsExtendedPanId);
connect(replyApsExtendedPanId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyApsExtendedPanId](){
if (replyApsExtendedPanId->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyApsExtendedPanId->command() << Deconz::ParameterApsExtendedPanId
<< "finished with error" << replyApsExtendedPanId->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyApsExtendedPanId->sequenceNumber() << replyApsExtendedPanId->command()
<< Deconz::ParameterApsExtendedPanId << "finished with error" << replyApsExtendedPanId->statusCode();
readNetworkParametersReply->m_statusCode = replyApsExtendedPanId->statusCode();
readNetworkParametersReply->finished();
return;
@ -544,16 +557,16 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
stream >> payloadLenght >> parameter >> apsExtendedPanId;
m_networkConfiguration.apsExtendedPanId = apsExtendedPanId;
qCDebug(dcZigbeeController()) << "Request" << replyApsExtendedPanId->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyApsExtendedPanId->sequenceNumber() << replyApsExtendedPanId->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << ZigbeeUtils::convertUint64ToHexString(m_networkConfiguration.apsExtendedPanId);
// Read trust center address
ZigbeeInterfaceDeconzReply *replyTrustCenterAddress = requestReadParameter(Deconz::ParameterTrustCenterAddress);
connect(replyTrustCenterAddress, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyTrustCenterAddress](){
if (replyTrustCenterAddress->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyTrustCenterAddress->command() << Deconz::ParameterTrustCenterAddress
<< "finished with error" << replyTrustCenterAddress->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyTrustCenterAddress->sequenceNumber() << replyTrustCenterAddress->command()
<< Deconz::ParameterTrustCenterAddress << "finished with error" << replyTrustCenterAddress->statusCode();
readNetworkParametersReply->m_statusCode = replyTrustCenterAddress->statusCode();
readNetworkParametersReply->finished();
return;
@ -565,16 +578,16 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
stream >> payloadLenght >> parameter >> trustCenterAddress;
m_networkConfiguration.trustCenterAddress = ZigbeeAddress(trustCenterAddress);
qCDebug(dcZigbeeController()) << "Request" << replyTrustCenterAddress->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyTrustCenterAddress->sequenceNumber() << replyTrustCenterAddress->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << m_networkConfiguration.trustCenterAddress;
// Read security mode
ZigbeeInterfaceDeconzReply *replySecurityMode = requestReadParameter(Deconz::ParameterSecurityMode);
connect(replySecurityMode, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replySecurityMode](){
if (replySecurityMode->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replySecurityMode->command() << Deconz::ParameterSecurityMode
<< "finished with error" << replySecurityMode->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replySecurityMode->sequenceNumber() << replySecurityMode->command()
<< Deconz::ParameterSecurityMode << "finished with error" << replySecurityMode->statusCode();
readNetworkParametersReply->m_statusCode = replySecurityMode->statusCode();
readNetworkParametersReply->finished();
return;
@ -586,8 +599,8 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
stream >> payloadLenght >> parameter >> securityMode;
m_networkConfiguration.securityMode = static_cast<Deconz::SecurityMode>(securityMode);
qCDebug(dcZigbeeController()) << "Request" << replySecurityMode->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replySecurityMode->sequenceNumber() << replySecurityMode->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << m_networkConfiguration.securityMode;
// Note: reading the network key returns "InavlidParameter". Might be for security reasons which is good!
@ -596,7 +609,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
ZigbeeInterfaceDeconzReply *replyChannel = requestReadParameter(Deconz::ParameterCurrentChannel);
connect(replyChannel, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyChannel](){
if (replyChannel->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyChannel->command() << Deconz::ParameterCurrentChannel
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyChannel->sequenceNumber() << replyChannel->command() << Deconz::ParameterCurrentChannel
<< "finished with error" << replyChannel->statusCode();
readNetworkParametersReply->m_statusCode = replyChannel->statusCode();
readNetworkParametersReply->finished();
@ -608,7 +621,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
quint16 payloadLenght = 0; quint8 parameter = 0; quint8 channel = 0;
stream >> payloadLenght >> parameter >> channel;
m_networkConfiguration.currentChannel = channel;
qCDebug(dcZigbeeController()) << "Request" << replyChannel->command() << static_cast<Deconz::Parameter>(parameter)
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyChannel->sequenceNumber() << replyChannel->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Current channel:" << m_networkConfiguration.currentChannel;
@ -617,8 +630,8 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
ZigbeeInterfaceDeconzReply *replyPermitJoin = requestReadParameter(Deconz::ParameterPermitJoin);
connect(replyPermitJoin, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyPermitJoin](){
if (replyPermitJoin->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyPermitJoin->command() << Deconz::ParameterPermitJoin
<< "finished with error" << replyPermitJoin->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyPermitJoin->sequenceNumber() << replyPermitJoin->command()
<< Deconz::ParameterPermitJoin << "finished with error" << replyPermitJoin->statusCode();
readNetworkParametersReply->m_statusCode = replyPermitJoin->statusCode();
readNetworkParametersReply->finished();
return;
@ -629,7 +642,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
quint16 payloadLenght = 0; quint8 parameter = 0;
stream >> payloadLenght >> parameter;
//m_networkConfiguration.currentChannel = channel;
qCDebug(dcZigbeeController()) << "Request" << replyPermitJoin->command() << static_cast<Deconz::Parameter>(parameter)
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyPermitJoin->sequenceNumber() << replyPermitJoin->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully" << ZigbeeUtils::convertByteArrayToHexString(replyPermitJoin->responseData());
@ -637,8 +650,8 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
ZigbeeInterfaceDeconzReply *replyProtocolVersion = requestReadParameter(Deconz::ParameterProtocolVersion);
connect(replyProtocolVersion, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyProtocolVersion](){
if (replyProtocolVersion->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyProtocolVersion->command() << Deconz::ParameterProtocolVersion
<< "finished with error" << replyProtocolVersion->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyProtocolVersion->sequenceNumber() << replyProtocolVersion->command()
<< Deconz::ParameterProtocolVersion << "finished with error" << replyProtocolVersion->statusCode();
readNetworkParametersReply->m_statusCode = replyProtocolVersion->statusCode();
readNetworkParametersReply->finished();
return;
@ -649,16 +662,16 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
quint16 payloadLenght = 0; quint8 parameter = 0; quint16 protocolVersion = 0;
stream >> payloadLenght >> parameter >> protocolVersion;
m_networkConfiguration.protocolVersion = protocolVersion;
qCDebug(dcZigbeeController()) << "Request" << replyProtocolVersion->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyProtocolVersion->sequenceNumber() << replyProtocolVersion->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << "Protocol version:" << ZigbeeUtils::convertUint16ToHexString(m_networkConfiguration.protocolVersion);
// Read network updat id
ZigbeeInterfaceDeconzReply *replyNetworkUpdateId = requestReadParameter(Deconz::ParameterNetworkUpdateId);
connect(replyNetworkUpdateId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyNetworkUpdateId](){
if (replyNetworkUpdateId->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyNetworkUpdateId->command() << Deconz::ParameterNetworkUpdateId
<< "finished with error" << replyNetworkUpdateId->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyNetworkUpdateId->sequenceNumber() << replyNetworkUpdateId->command()
<< Deconz::ParameterNetworkUpdateId << "finished with error" << replyNetworkUpdateId->statusCode();
readNetworkParametersReply->m_statusCode = replyNetworkUpdateId->statusCode();
readNetworkParametersReply->finished();
return;
@ -669,8 +682,8 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
quint16 payloadLenght = 0; quint8 parameter = 0; quint8 networkUpdateId = 0;
stream >> payloadLenght >> parameter >> networkUpdateId;
m_networkConfiguration.networkUpdateId = networkUpdateId;
qCDebug(dcZigbeeController()) << "Request" << replyNetworkUpdateId->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyNetworkUpdateId->sequenceNumber() << replyNetworkUpdateId->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << "Network update ID:" << m_networkConfiguration.networkUpdateId;
// Make sure the watchdog is available for this version
@ -692,8 +705,8 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
ZigbeeInterfaceDeconzReply *replyWatchdogTimeout = requestReadParameter(Deconz::ParameterWatchdogTtl);
connect(replyWatchdogTimeout, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyWatchdogTimeout](){
if (replyWatchdogTimeout->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << replyWatchdogTimeout->command() << Deconz::ParameterWatchdogTtl
<< "finished with error" << replyWatchdogTimeout->statusCode();
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyWatchdogTimeout->sequenceNumber() << replyWatchdogTimeout->command()
<< Deconz::ParameterWatchdogTtl << "finished with error" << replyWatchdogTimeout->statusCode();
readNetworkParametersReply->m_statusCode = replyWatchdogTimeout->statusCode();
readNetworkParametersReply->finished();
return;
@ -704,8 +717,8 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
quint16 payloadLenght = 0; quint8 parameter = 0; quint32 watchdogTimeout = 0;
stream >> payloadLenght >> parameter >> watchdogTimeout;
m_networkConfiguration.watchdogTimeout = watchdogTimeout;
qCDebug(dcZigbeeController()) << "Request" << replyWatchdogTimeout->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully";
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyWatchdogTimeout->sequenceNumber() << replyWatchdogTimeout->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << "Watchdog timeout:" << m_networkConfiguration.watchdogTimeout;
// Finished reading all parameters. Finish the independent reply in order to indicate the process has finished
@ -746,13 +759,13 @@ void ZigbeeBridgeControllerDeconz::readDataIndication()
ZigbeeInterfaceDeconzReply *reply = requestReadReceivedDataIndication();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read data indication." << reply->statusCode();
qCWarning(dcZigbeeController()) << "Could not read data indication." << "SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error
return;
}
// APS data indication received, process the content
qCDebug(dcZigbeeController()) << "Reading data indication finished successfully";
qCDebug(dcZigbeeController()) << "Reading data indication finished successfully" << "SQN:" << reply->sequenceNumber();
processDataIndication(reply->responseData());
});
}
@ -762,20 +775,20 @@ void ZigbeeBridgeControllerDeconz::readDataConfirm()
ZigbeeInterfaceDeconzReply *reply = requestQuerySendDataConfirm();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read data confirm." << reply->statusCode();
qCWarning(dcZigbeeController()) << "Could not read data confirm." << "SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error
return;
}
// APS data confirm received, process the content
qCDebug(dcZigbeeController()) << "Reading data confirm finished successfully";
qCDebug(dcZigbeeController()) << "Reading data confirm finished successfully" << "SQN:" << reply->sequenceNumber();
processDataConfirm(reply->responseData());
});
}
void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceState)
{
qCDebug(dcZigbeeController()) << deviceState;
qCDebug(dcZigbeeController()) << "Process device state notification" << deviceState;
if (m_networkState != deviceState.networkState) {
qCDebug(dcZigbeeController()) << "Network state changed" << deviceState.networkState;
@ -785,7 +798,10 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt
if (m_apsFreeSlotsAvailable != deviceState.apsDataRequestFreeSlots) {
m_apsFreeSlotsAvailable = deviceState.apsDataRequestFreeSlots;
if (!m_apsFreeSlotsAvailable) {
qCWarning(dcZigbeeController()) << "The APS request table is full on the device. Cannot send requests until the queue gets processed on the controller.";
return;
}
// FIXME: if changed to true, send next aps data request
}
@ -851,6 +867,7 @@ void ZigbeeBridgeControllerDeconz::processDataIndication(const QByteArray &data)
// Process the device state in order to check if we have to request another indication
DeconzDeviceState deviceState = parseDeviceStateFlag(deviceStateFlag);
qCDebug(dcZigbeeController()) << "Verify device state after data indication response" << deviceState;
if (deviceState.apsDataIndication) {
readDataIndication();
}
@ -881,6 +898,7 @@ void ZigbeeBridgeControllerDeconz::processDataConfirm(const QByteArray &data)
// Process the device state in order to check if we have to request another indication
DeconzDeviceState deviceState = parseDeviceStateFlag(deviceStateFlag);
qCDebug(dcZigbeeController()) << "Verify device state after data confirmation response" << deviceState;
if (deviceState.apsDataConfirm) {
readDataConfirm();
}
@ -912,12 +930,16 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
QByteArray data = package.right(package.length() - 5);
Deconz::Command command = static_cast<Deconz::Command>(commandInt);
Deconz::StatusCode status = static_cast<Deconz::StatusCode>(statusInt);
//qCDebug(dcZigbeeController()) << "Interface message received" << command << "SQN:" << sequenceNumber
// << status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data);
qCDebug(dcZigbeeController()) << "Interface message received" << command << "SQN:" << sequenceNumber
<< status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data);
// Check if this is an interface response for a pending reply
if (m_pendingReplies.contains(sequenceNumber) && m_pendingReplies.value(sequenceNumber)->command() == command) {
ZigbeeInterfaceDeconzReply *reply = m_pendingReplies.take(sequenceNumber);
if (!reply) {
qCWarning(dcZigbeeController()) << "Received message but the corresponding reply does not exist any more.";
return;
}
reply->m_responseData = data;
reply->m_statusCode = status;
reply->finished();
@ -927,7 +949,7 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
// Note: we got a notification, lets set the current sequence number to the notification id,
// so the next request will be a continuouse increase
m_sequenceNumber = sequenceNumber;
m_sequenceNumber = sequenceNumber + 1;
// No request for this data, lets check which notification and process the data
switch (command) {
@ -938,12 +960,12 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
break;
}
case Deconz::CommandMacPoll: {
// FIXME: parse the data and print info
qCDebug(dcZigbeeController()) << "MAC Poll command received" << ZigbeeUtils::convertByteArrayToHexString(data);// FIXME: parse the data and print info
break;
}
case Deconz::CommandSimplifiedBeacon: {
// FIXME: parse the data and print info
qCDebug(dcZigbeeController()) << "Simplified beacon command received" << ZigbeeUtils::convertByteArrayToHexString(data);
break;
}
default:
@ -951,7 +973,6 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
<< status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data);
break;
}
}
void ZigbeeBridgeControllerDeconz::resetControllerWatchdog()

View File

@ -29,8 +29,9 @@
#define ZIGBEEBRIDGECONTROLLERDECONZ_H
#include <QHash>
#include <QObject>
#include <QTimer>
#include <QQueue>
#include <QObject>
#include "zigbee.h"
#include "zigbeeaddress.h"
@ -85,6 +86,7 @@ public:
Deconz::NetworkState networkState() const;
// Controllere requests
ZigbeeInterfaceDeconzReply *requestVersion();
ZigbeeInterfaceDeconzReply *requestDeviceState();
ZigbeeInterfaceDeconzReply *requestReadParameter(Deconz::Parameter parameter);
@ -96,12 +98,8 @@ public:
ZigbeeInterfaceDeconzReply *requestQuerySendDataConfirm();
// Send data
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0);
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0);
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0);
ZigbeeInterfaceDeconzReply *requestSendRequest(const ZigbeeNetworkRequest &request);
private:
ZigbeeInterfaceDeconz *m_interface = nullptr;
quint8 m_sequenceNumber = 0;
@ -112,12 +110,20 @@ private:
Deconz::NetworkState m_networkState = Deconz::NetworkStateOffline;
QTimer *m_watchdogTimer = nullptr;
// APS request queue
bool m_apsFreeSlotsAvailable = false;
QQueue<ZigbeeNetworkRequest> m_requestQueue;
void sendNextRequest();
quint8 generateSequenceNumber();
ZigbeeInterfaceDeconzReply *createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent);
// Send data depending on the request destination address mode
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0);
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0);
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0);
// Note: this method reads all parameters individual. The returned reply it self will not send or receive any data.
// The data can be fetched from m_networkConfiguration on success.
ZigbeeInterfaceDeconzReply *readNetworkParameters();

View File

@ -191,7 +191,7 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
return;
}
qCDebug(dcZigbeeNetwork()) << "Configured APS extended PANID successfully. SQN:" << reply->sequenceNumber();
qCDebug(dcZigbeeController()) << "Configured APS extended PANID successfully. SQN:" << reply->sequenceNumber();
QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly);
@ -206,7 +206,7 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
return;
}
qCDebug(dcZigbeeNetwork()) << "Configured trust center address successfully. SQN:" << reply->sequenceNumber();
qCDebug(dcZigbeeController()) << "Configured trust center address successfully. SQN:" << reply->sequenceNumber();
QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly);
@ -221,7 +221,7 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
return;
}
qCDebug(dcZigbeeNetwork()) << "Configured security mode successfully. SQN:" << reply->sequenceNumber();
qCDebug(dcZigbeeController()) << "Configured security mode successfully. SQN:" << reply->sequenceNumber();
qCDebug(dcZigbeeNetwork()) << "Configure network key" << securityConfiguration().networkKey().toString();
@ -233,7 +233,7 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
// Note: writing the network key fails all the time...
//return;
} else {
qCDebug(dcZigbeeNetwork()) << "Configured network key successfully. SQN:" << reply->sequenceNumber();
qCDebug(dcZigbeeController()) << "Configured network key successfully. SQN:" << reply->sequenceNumber();
}
// Configuration finished, lets start the network
@ -284,7 +284,9 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
case CreateNetworkStateInitializeCoordinatorNode: {
if (m_coordinatorNode) {
qCDebug(dcZigbeeNetwork()) << "We already have the coordinator node. Network starting done.";
m_initializing = false;
setState(StateRunning);
setPermitJoiningInternal(false);
return;
}
@ -295,7 +297,9 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){
if (state == ZigbeeNode::StateInitialized) {
qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode;
m_initializing = false;
setState(StateRunning);
setPermitJoiningInternal(false);
return;
}
});
@ -350,6 +354,11 @@ void ZigbeeNetworkDeconz::handleZigbeeClusterLibraryIndication(const Zigbee::Aps
if (!node) {
qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication;
// FIXME: maybe create and init the node, since it is in the network, but not recognized
// Remove this node since we might have removed it but it did not respond, or we not explicitly allowed it to join.
return;
}
@ -467,6 +476,8 @@ void ZigbeeNetworkDeconz::startNetworkInternally()
return;
}
qCDebug(dcZigbeeNetwork()) << "Reading current network state finished successfully." << "SQN:" << reply->sequenceNumber();
QDataStream stream(reply->responseData());
stream.setByteOrder(QDataStream::LittleEndian);
quint8 deviceStateFlag = 0;
@ -489,8 +500,11 @@ void ZigbeeNetworkDeconz::startNetworkInternally()
// Get the network state and start the network if required
if (m_controller->networkState() == Deconz::NetworkStateConnected) {
qCDebug(dcZigbeeNetwork()) << "The network is already running.";
m_initializing = false;
setState(StateRunning);
setPermitJoiningInternal(false);
} else if (m_controller->networkState() == Deconz::NetworkStateOffline) {
m_initializing = true;
qCDebug(dcZigbeeNetwork()) << "The network is offline. Lets start it";
setCreateNetworkState(CreateNetworkStateStartNetwork);
} else {
@ -507,12 +521,14 @@ void ZigbeeNetworkDeconz::onControllerAvailableChanged(bool available)
if (!available) {
qCWarning(dcZigbeeNetwork()) << "Hardware controller is not available any more.";
setError(ErrorHardwareUnavailable);
m_initializing = false;
m_permitJoining = false;
emit permitJoiningChanged(m_permitJoining);
setState(StateOffline);
} else {
m_error = ErrorNoError;
m_permitJoining = false;
m_initializing = true;
emit permitJoiningChanged(m_permitJoining);
setState(StateStarting);
qCDebug(dcZigbeeNetwork()) << "Hardware controller is now available.";
@ -647,7 +663,10 @@ void ZigbeeNetworkDeconz::startNetwork()
m_permitJoining = false;
emit permitJoiningChanged(m_permitJoining);
// Note: wait for the controller available signal and start the initialization there
m_initializing = true;
}
void ZigbeeNetworkDeconz::stopNetwork()
@ -674,6 +693,7 @@ void ZigbeeNetworkDeconz::reset()
void ZigbeeNetworkDeconz::factoryResetNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Factory reset network and forget all information. This cannot be undone.";
m_controller->disable();
clearSettings();
setState(StateUninitialized);
qCDebug(dcZigbeeNetwork()) << "The factory reset is finished. Start restart with a fresh network.";

View File

@ -56,13 +56,14 @@ public:
// Sending an APSDE-DATA.request, will be finished on APSDE-DATA.confirm
ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) override;
ZigbeeNetworkReply *setPermitJoin(quint16 shortAddress, quint8 duration);
ZigbeeNetworkReply *setPermitJoin(quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, quint8 duration = 0xfe);
private:
ZigbeeBridgeControllerDeconz *m_controller = nullptr;
bool m_networkRunning = false;
CreateNetworkState m_createState = CreateNetworkStateIdle;
bool m_createNewNetwork = false;
bool m_initializing = false;
QTimer *m_permitJoinRefreshTimer = nullptr;

View File

@ -9,6 +9,7 @@ SOURCES += \
backends/deconz/zigbeebridgecontrollerdeconz.cpp \
backends/deconz/zigbeenetworkdeconz.cpp \
zcl/general/zigbeeclusteridentify.cpp \
zcl/general/zigbeeclusterlevelcontrol.cpp \
zcl/general/zigbeeclusteronoff.cpp \
zcl/measurement/zigbeeclusterilluminancemeasurment.cpp \
zcl/measurement/zigbeeclusteroccupancysensing.cpp \
@ -57,6 +58,7 @@ HEADERS += \
backends/deconz/zigbeebridgecontrollerdeconz.h \
backends/deconz/zigbeenetworkdeconz.h \
zcl/general/zigbeeclusteridentify.h \
zcl/general/zigbeeclusterlevelcontrol.h \
zcl/general/zigbeeclusteronoff.h \
zcl/measurement/zigbeeclusterilluminancemeasurment.h \
zcl/measurement/zigbeeclusteroccupancysensing.h \

View File

@ -40,156 +40,25 @@ ZigbeeClusterIdentify::ZigbeeClusterIdentify(ZigbeeNetwork *network, ZigbeeNode
ZigbeeClusterReply *ZigbeeClusterIdentify::identify(quint16 seconds)
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterIdentify::CommandIdentify;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
// Note: the identify time unit is 0.5 seconds
QByteArray payload = ZigbeeDataType(seconds * 2).data();
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
frame.payload = payload;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
return executeClusterCommand(ZigbeeClusterIdentify::CommandIdentify, payload);
}
ZigbeeClusterReply *ZigbeeClusterIdentify::identifyQuery()
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterIdentify::CommandIdentifyQuery;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
// No payload
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
return executeClusterCommand(ZigbeeClusterIdentify::CommandIdentifyQuery);
}
ZigbeeClusterReply *ZigbeeClusterIdentify::triggerEffect(ZigbeeClusterIdentify::Effect effect, quint8 effectVariant)
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterIdentify::CommandTriggerEffect;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(effect);
stream << static_cast<quint8>(effectVariant);
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
frame.payload = payload;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
return executeClusterCommand(ZigbeeClusterIdentify::CommandTriggerEffect, payload);
}
void ZigbeeClusterIdentify::setAttribute(const ZigbeeClusterAttribute &attribute)

View File

@ -0,0 +1,137 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 "zigbeeclusterlevelcontrol.h"
#include "zigbeenetworkreply.h"
#include "loggingcategory.h"
#include "zigbeenetwork.h"
#include <QDataStream>
ZigbeeClusterLevelControl::ZigbeeClusterLevelControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdLevelControl, direction, parent)
{
}
ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveToLevel(quint8 level, quint16 transistionTime)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << level << transistionTime;
return executeClusterCommand(ZigbeeClusterLevelControl::CommandMoveToLevel, payload);
}
ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMove(ZigbeeClusterLevelControl::MoveMode moveMode, quint8 rate)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(moveMode) << rate;
return executeClusterCommand(ZigbeeClusterLevelControl::CommandMove, payload);
}
ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStep(ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transistionTime)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(fadeMode) << stepSize << transistionTime;
return executeClusterCommand(ZigbeeClusterLevelControl::CommandStep, payload);
}
ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStop()
{
return executeClusterCommand(ZigbeeClusterLevelControl::CommandStop);
}
ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveToLevelWithOnOff(quint8 level, quint16 transistionTime)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << level << transistionTime;
return executeClusterCommand(ZigbeeClusterLevelControl::CommandMoveToLevelWithOnOff, payload);
}
ZigbeeClusterReply *ZigbeeClusterLevelControl::commandMoveWithOnOff(ZigbeeClusterLevelControl::MoveMode moveMode, quint8 rate)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(moveMode) << rate;
return executeClusterCommand(ZigbeeClusterLevelControl::CommandMoveWithOnOff, payload);
}
ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStepWithOnOff(ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transistionTime)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(fadeMode) << stepSize << transistionTime;
return executeClusterCommand(ZigbeeClusterLevelControl::CommandStepWithOnOff, payload);
}
ZigbeeClusterReply *ZigbeeClusterLevelControl::commandStopWithOnOff()
{
return executeClusterCommand(ZigbeeClusterLevelControl::CommandStopWithOnOff);
}
void ZigbeeClusterLevelControl::setAttribute(const ZigbeeClusterAttribute &attribute)
{
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();
if (hasAttribute(attribute.id())) {
m_attributes[attribute.id()] = attribute;
emit attributeChanged(attribute);
} else {
m_attributes.insert(attribute.id(), attribute);
emit attributeChanged(attribute);
}
// Parse the information for convinience
if (attribute.id() == AttributeCurrentLevel) {
bool valueOk = false;
quint8 value = attribute.dataType().toUInt8(&valueOk);
if (valueOk) {
qCDebug(dcZigbeeCluster()) << "CurrentLevel state changed on" << m_node << m_endpoint << this << value;
emit currentLevelChanged(value);
} else {
qCWarning(dcZigbeeCluster()) << "Failed to parse attribute data" << m_node << m_endpoint << this << attribute;
}
}
}
void ZigbeeClusterLevelControl::processDataIndication(ZigbeeClusterLibrary::Frame frame)
{
qCDebug(dcZigbeeCluster()) << "Processing cluster frame" << m_node << m_endpoint << this << frame;
// Increase the tsn for continuouse id increasing on both sides
m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
// FIXME: parse client commands to group
}

View File

@ -0,0 +1,108 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 ZIGBEECLUSTERLEVELCONTROL_H
#define ZIGBEECLUSTERLEVELCONTROL_H
#include <QObject>
#include "zcl/zigbeecluster.h"
#include "zcl/zigbeeclusterreply.h"
class ZigbeeNode;
class ZigbeeNetwork;
class ZigbeeNodeEndpoint;
class ZigbeeNetworkReply;
class ZigbeeClusterLevelControl : public ZigbeeCluster
{
Q_OBJECT
friend class ZigbeeNode;
friend class ZigbeeNetwork;
public:
enum Attribute {
AttributeCurrentLevel = 0x0000,
AttributeRemainingTime = 0x0001,
AttributeOnOffTransitionTime = 0x0010,
AttributeOnLevel = 0x0011,
AttributeOnTransitionTime = 0x0012,
AttributeOffTransitionTime = 0x0013,
AttributeDefaultMoveRate = 0x0014
};
Q_ENUM(Attribute)
enum Command {
CommandMoveToLevel = 0x00,
CommandMove = 0x01,
CommandStep = 0x02,
CommandStop = 0x03,
CommandMoveToLevelWithOnOff = 0x04,
CommandMoveWithOnOff = 0x05,
CommandStepWithOnOff = 0x06,
CommandStopWithOnOff = 0x07
};
Q_ENUM(Command)
enum MoveMode {
MoveModeUp = 0x00,
ModeModeDown = 0x01
};
Q_ENUM(MoveMode)
enum FadeMode {
FadeModeUp = 0x00,
FadeModeDown = 0x01
};
Q_ENUM(FadeMode)
explicit ZigbeeClusterLevelControl(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
ZigbeeClusterReply *commandMoveToLevel(quint8 level, quint16 transistionTime = 0xffff);
ZigbeeClusterReply *commandMove(MoveMode moveMode, quint8 rate = 0xff);
ZigbeeClusterReply *commandStep(FadeMode fadeMode, quint8 stepSize = 0x01, quint16 transistionTime = 0xffff);
ZigbeeClusterReply *commandStop();
// With on/off
ZigbeeClusterReply *commandMoveToLevelWithOnOff(quint8 level, quint16 transistionTime = 0xffff);
ZigbeeClusterReply *commandMoveWithOnOff(MoveMode moveMode, quint8 rate = 0xff);
ZigbeeClusterReply *commandStepWithOnOff(FadeMode fadeMode, quint8 stepSize = 0x01, quint16 transistionTime = 0xffff);
ZigbeeClusterReply *commandStopWithOnOff();
private:
void setAttribute(const ZigbeeClusterAttribute &attribute) override;
protected:
void processDataIndication(ZigbeeClusterLibrary::Frame frame) override;
signals:
void currentLevelChanged(quint8 level);
};
#endif // ZIGBEECLUSTERLEVELCONTROL_H

View File

@ -40,152 +40,17 @@ ZigbeeClusterOnOff::ZigbeeClusterOnOff(ZigbeeNetwork *network, ZigbeeNode *node,
ZigbeeClusterReply *ZigbeeClusterOnOff::commandOff()
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
// Note: for basic commands the frame control files has to be zero accoring to spec ZCL 2.4.1.1
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterOnOff::CommandOff;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
// there is no ZCL payload
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
return executeClusterCommand(ZigbeeClusterOnOff::CommandOff);
}
ZigbeeClusterReply *ZigbeeClusterOnOff::commandOn()
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
// Note: for basic commands the frame control files has to be zero accoring to spec ZCL 2.4.1.1
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterOnOff::CommandOn;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
// There is no ZCL payload
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
return executeClusterCommand(ZigbeeClusterOnOff::CommandOn);
}
ZigbeeClusterReply *ZigbeeClusterOnOff::commandToggle()
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
// Note: for basic commands the frame control files has to be zero accoring to spec ZCL 2.4.1.1
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterOnOff::CommandToggle;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
// There is no ZCL payload
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
return executeClusterCommand(ZigbeeClusterOnOff::CommandToggle);
}
void ZigbeeClusterOnOff::setAttribute(const ZigbeeClusterAttribute &attribute)
@ -240,13 +105,10 @@ void ZigbeeClusterOnOff::processDataIndication(ZigbeeClusterLibrary::Frame frame
qCWarning(dcZigbeeCluster()) << "Unhandled command sent from" << m_node << m_endpoint << this << command;
break;
}
return;
}
break;
case Server:
// keep it unhandled if not parsed yet in order to warn about the handled indication
qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame;
break;
}
qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame;
}

View File

@ -80,7 +80,6 @@ void ZigbeeClusterIasZone::processDataIndication(ZigbeeClusterLibrary::Frame fra
// Update the ZoneState attribute
setAttribute(ZigbeeClusterAttribute(AttributeZoneState, ZigbeeDataType(Zigbee::BitMap16, frame.payload.left(2))));
emit zoneStatusChanged(ZoneStatusFlags(zoneStatus), extendedStatus, zoneId, delay);
break;
}

View File

@ -43,7 +43,7 @@ ZigbeeCluster::ZigbeeCluster(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNod
m_clusterId(clusterId),
m_direction(direction)
{
qCDebug(dcZigbeeCluster()) << "Create cluster" << ZigbeeUtils::convertUint16ToHexString(clusterId) << direction;
//qCDebug(dcZigbeeCluster()) << "Create cluster" << ZigbeeUtils::convertUint16ToHexString(clusterId) << direction;
}
ZigbeeCluster::Direction ZigbeeCluster::direction() const
@ -162,6 +162,53 @@ ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest
return zclReply;
}
ZigbeeClusterReply *ZigbeeCluster::executeClusterCommand(quint8 command, const QByteArray &payload)
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame control
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// Build ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = command;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
// Build ZCL frame
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
frame.payload = payload;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
}
ZigbeeNetworkRequest ZigbeeCluster::createGeneralRequest()
{
// Build the request

View File

@ -90,31 +90,6 @@ public:
// Q_ENUM(PowerConfigurationAttribute)
// // Level cluster 0x0008
// enum LevelClusterAttribute {
// LevelClusterAttributeCurrentLevel = 0x0000,
// LevelClusterAttributeRemainingTime = 0x0001,
// LevelClusterAttributeOnOffTransitionTime = 0x0010,
// LevelClusterAttributeOnLevel = 0x0011,
// LevelClusterAttributeOnTransitionTime = 0x0012,
// LevelClusterAttributeOffTransitionTime = 0x0013,
// LevelClusterAttributeDefaultMoveRate = 0x0014
// };
// Q_ENUM(LevelClusterAttribute)
// enum LevelClusterCommand {
// LevelClusterCommandMoveToLevel = 0x00,
// LevelClusterCommandMove = 0x01,
// LevelClusterCommandStep = 0x02,
// LevelClusterCommandStop = 0x03,
// LevelClusterCommandMoveToLevelWithOnOff = 0x04,
// LevelClusterCommandMoveWithOnOff = 0x05,
// LevelClusterCommandStepWithOnOff = 0x06,
// LevelClusterCommandStopWithOnOff = 0x07,
// };
// Q_ENUM(LevelClusterCommand)
// // Color cluster 0x0300
// enum ColorControlClusterAttribute {
@ -170,11 +145,12 @@ protected:
Direction m_direction = Server;
QHash<quint16, ZigbeeClusterAttribute> m_attributes;
// Helper methods for sending cluster specific commands
ZigbeeNetworkRequest createGeneralRequest();
quint8 m_transactionSequenceNumber = 0;
QHash<quint8, ZigbeeClusterReply *> m_pendingReplies;
ZigbeeClusterReply *createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame);
ZigbeeClusterReply *executeClusterCommand(quint8 command, const QByteArray &payload = QByteArray());
bool verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetworkReply *networkReply);
void finishZclReply(ZigbeeClusterReply *zclReply);

View File

@ -30,6 +30,158 @@
#include <QDataStream>
ZigbeeDeviceProfile::NodeDescriptor ZigbeeDeviceProfile::parseNodeDescriptor(const QByteArray &payload)
{
NodeDescriptor nodeDescriptor;
nodeDescriptor.descriptorRawData = payload;
// Parse and set the node descriptor
QDataStream stream(payload);
stream.setByteOrder(QDataStream::LittleEndian);
quint8 typeDescriptorFlag = 0; quint8 frequencyFlag = 0; quint8 macCapabilitiesFlag = 0;
quint16 serverMaskFlag = 0; quint8 descriptorCapabilitiesFlag = 0;
stream >> typeDescriptorFlag >> frequencyFlag >> macCapabilitiesFlag >> nodeDescriptor.manufacturerCode >> nodeDescriptor.maximumBufferSize;
stream >> nodeDescriptor.maximumRxSize >> serverMaskFlag >> nodeDescriptor.maximumTxSize >> descriptorCapabilitiesFlag;
// 0-2 Bit = logical type, 0 = coordinator, 1 = router, 2 = end device
if (!ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) {
nodeDescriptor.nodeType = NodeTypeCoordinator;
} else if (!ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) {
nodeDescriptor.nodeType = NodeTypeRouter;
} else if (ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) {
nodeDescriptor.nodeType = NodeTypeEndDevice;
}
nodeDescriptor.complexDescriptorAvailable = (typeDescriptorFlag >> 3) & 0x0001;
nodeDescriptor.userDescriptorAvailable = (typeDescriptorFlag >> 4) & 0x0001;
// Frequency band, 5 bits
if (ZigbeeUtils::checkBitUint8(frequencyFlag, 3)) {
nodeDescriptor.frequencyBand = FrequencyBand868Mhz;
} else if (ZigbeeUtils::checkBitUint8(frequencyFlag, 5)) {
nodeDescriptor.frequencyBand = FrequencyBand902Mhz;
} else if (ZigbeeUtils::checkBitUint8(frequencyFlag, 6)) {
nodeDescriptor.frequencyBand = FrequencyBand2400Mhz;
}
nodeDescriptor.macCapabilities = parseMacCapabilities(macCapabilitiesFlag);
nodeDescriptor.serverMask = parseServerMask(serverMaskFlag);
nodeDescriptor.descriptorCapabilities = parseDescriptorCapabilities(descriptorCapabilitiesFlag);
return nodeDescriptor;
}
ZigbeeDeviceProfile::MacCapabilities ZigbeeDeviceProfile::parseMacCapabilities(quint8 macCapabilitiesFlag)
{
MacCapabilities capabilities;
capabilities.flag = macCapabilitiesFlag;
capabilities.alternatePanCoordinator = ((macCapabilitiesFlag >> 0) & 0x01);
if (((macCapabilitiesFlag >> 1) & 0x01)) {
capabilities.deviceType = DeviceTypeFullFunction;
} else {
capabilities.deviceType = DeviceTypeReducedFunction;
}
capabilities.powerSourceFlagMainPower = ((macCapabilitiesFlag >> 2) & 0x01);
capabilities.receiverOnWhenIdle = ((macCapabilitiesFlag >> 3) & 0x01);
capabilities.securityCapability = ((macCapabilitiesFlag >> 6) & 0x01);
capabilities.allocateAddress = ((macCapabilitiesFlag >> 7) & 0x01);
return capabilities;
}
ZigbeeDeviceProfile::ServerMask ZigbeeDeviceProfile::parseServerMask(quint16 serverMaskFlag)
{
ServerMask serverMask;
serverMask.serverMaskFlag = serverMaskFlag;
serverMask.primaryTrustCenter = ((serverMaskFlag >> 0) & 0x0001);
serverMask.backupTrustCenter = ((serverMaskFlag >> 1) & 0x0001);
serverMask.primaryBindingCache = ((serverMaskFlag >> 2) & 0x0001);
serverMask.backupBindingCache = ((serverMaskFlag >> 3) & 0x0001);
serverMask.primaryDiscoveryCache = ((serverMaskFlag >> 4) & 0x0001);
serverMask.backupDiscoveryCache = ((serverMaskFlag >> 5) & 0x0001);
serverMask.networkManager = ((serverMaskFlag >> 6) & 0x0001);
return serverMask;
}
ZigbeeDeviceProfile::DescriptorCapabilities ZigbeeDeviceProfile::parseDescriptorCapabilities(quint8 descriptorCapabilitiesFlag)
{
DescriptorCapabilities capabilities;
capabilities.descriptorCapabilitiesFlag = descriptorCapabilitiesFlag;
capabilities.extendedActiveEndpointListAvailable = ((descriptorCapabilitiesFlag >> 0) & 0x01);
capabilities.extendedSimpleDescriptorListAvailable = ((descriptorCapabilitiesFlag >> 1) & 0x01);
return capabilities;
}
ZigbeeDeviceProfile::PowerDescriptor ZigbeeDeviceProfile::parsePowerDescriptor(quint16 powerDescriptorFlag)
{
PowerDescriptor powerDescriptor;
powerDescriptor.powerDescriptoFlag = powerDescriptorFlag;
// Bit 0 - 3 Power mode
// 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor
// 0001: Receiver switched on periodically
// 0010: Receiver switched on when stimulated, e.g. by pressing a button
powerDescriptor.powerMode = ZigbeeDeviceProfile::PowerModeAlwaysOn;
if (!ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 1)) {
powerDescriptor.powerMode = ZigbeeDeviceProfile::PowerModeAlwaysOn;
} else if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 1)) {
powerDescriptor.powerMode = ZigbeeDeviceProfile::PowerModeOnPeriodically;
} else if (!ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 0) && ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 1)) {
powerDescriptor.powerMode = ZigbeeDeviceProfile::PowerModeOnWhenStimulated;
}
// Bit 4 - 7 Available power sources
// Bit 0: Permanent mains supply
// Bit 1: Rechargeable battery
// Bit 2: Disposable battery
// Bit 4: Reserved
if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 4)) {
powerDescriptor.availablePowerSources.append(ZigbeeDeviceProfile::PowerSourcePermanentMainSupply);
} else if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 5)) {
powerDescriptor.availablePowerSources.append(ZigbeeDeviceProfile::PowerSourceRecharchableBattery);
} else if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 6)) {
powerDescriptor.availablePowerSources.append(ZigbeeDeviceProfile::PowerSourceDisposableBattery);
}
// Bit 8 - 11 Active source: according to the same schema as available power sources
powerDescriptor.powerSource = ZigbeeDeviceProfile::PowerSourcePermanentMainSupply;
if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 8)) {
powerDescriptor.powerSource = ZigbeeDeviceProfile::PowerSourcePermanentMainSupply;
} else if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 9)) {
powerDescriptor.powerSource = ZigbeeDeviceProfile::PowerSourceRecharchableBattery;
} else if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 10)) {
powerDescriptor.powerSource = ZigbeeDeviceProfile::PowerSourceDisposableBattery;
}
// Bit 12 - 15: Battery level if available
// 0000: Critically low
// 0100: Approximately 33%
// 1000: Approximately 66%
// 1100: Approximately 100% (near fully charged)
if (!ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 14) && !ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 15)) {
powerDescriptor.powerLevel = ZigbeeDeviceProfile::PowerLevelCriticalLow;
} else if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 14) && !ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 15)) {
powerDescriptor.powerLevel = ZigbeeDeviceProfile::PowerLevelLow;
} else if (!ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 14) && ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 15)) {
powerDescriptor.powerLevel = ZigbeeDeviceProfile::PowerLevelOk;
} else if (ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 14) && ZigbeeUtils::checkBitUint16(powerDescriptorFlag, 15)) {
powerDescriptor.powerLevel = ZigbeeDeviceProfile::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;
return powerDescriptor;
}
ZigbeeDeviceProfile::Adpu ZigbeeDeviceProfile::parseAdpu(const QByteArray &adpu)
{
QDataStream stream(adpu);
@ -51,3 +203,62 @@ QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::Adpu &deviceAdpu)
debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")";
return debug.space();
}
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::NodeDescriptor &nodeDescriptor)
{
debug.nospace() << "NodeDescriptor(" << nodeDescriptor.nodeType << ")" << endl;
debug.nospace() << " Complex descriptor available: " << nodeDescriptor.complexDescriptorAvailable << endl;
debug.nospace() << " User descriptor available: " << nodeDescriptor.userDescriptorAvailable << endl;
debug.nospace() << " " << nodeDescriptor.frequencyBand << endl;
debug.nospace() << " " << nodeDescriptor.macCapabilities;
debug.nospace() << " Manufacturer code: " << ZigbeeUtils::convertUint16ToHexString(nodeDescriptor.manufacturerCode) << "(" << nodeDescriptor.manufacturerCode << ")" << endl;
debug.nospace() << " Maximum buffer size: " << nodeDescriptor.maximumBufferSize << endl;
debug.nospace() << " Maximum RX size: " << nodeDescriptor.maximumRxSize << endl;
debug.nospace() << " Maximum TX size: " << nodeDescriptor.maximumTxSize << endl;
debug.nospace() << " " << nodeDescriptor.serverMask;
debug.nospace() << " " << nodeDescriptor.descriptorCapabilities;
return debug;
}
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::MacCapabilities &macCapabilities)
{
debug.nospace() << "MacCapabilities(" << ZigbeeUtils::convertByteToHexString(macCapabilities.flag) << ")" << endl;
debug.nospace() << " Alternate PAN Coordinator: " << macCapabilities.alternatePanCoordinator << endl;
debug.nospace() << " " << macCapabilities.deviceType << endl;
debug.nospace() << " Power source main power: " << macCapabilities.powerSourceFlagMainPower << endl;
debug.nospace() << " Receiver on when idle: " << macCapabilities.receiverOnWhenIdle << endl;
debug.nospace() << " Security capability: " << macCapabilities.securityCapability << endl;
debug.nospace() << " Allocate address: " << macCapabilities.allocateAddress << endl;
return debug;
}
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::ServerMask &serverMask)
{
debug.nospace() << "ServerMask(" << ZigbeeUtils::convertUint16ToHexString(serverMask.serverMaskFlag) << ")" << endl;
debug.nospace() << " Primary trust center: " << serverMask.primaryTrustCenter << endl;
debug.nospace() << " Backup trust center: " << serverMask.backupTrustCenter << endl;
debug.nospace() << " Primary binding cache: " << serverMask.primaryBindingCache << endl;
debug.nospace() << " Backup binding cache: " << serverMask.backupBindingCache << endl;
debug.nospace() << " Primary discovery cache: " << serverMask.primaryDiscoveryCache << endl;
debug.nospace() << " Backup discovery cache: " << serverMask.backupDiscoveryCache << endl;
debug.nospace() << " Network manager: " << serverMask.networkManager << endl;
return debug;
}
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::DescriptorCapabilities &descriptorCapabilities)
{
debug.nospace() << "DescriptorCapabilities(" << ZigbeeUtils::convertByteToHexString(descriptorCapabilities.descriptorCapabilitiesFlag) << ")" << endl;
debug.nospace() << " Extended active endpoint list available: " << descriptorCapabilities.extendedActiveEndpointListAvailable << endl;
debug.nospace() << " Extended simple descriptor list available: " << descriptorCapabilities.extendedSimpleDescriptorListAvailable << endl;
return debug;
}
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::PowerDescriptor &powerDescriptor)
{
debug.nospace() << "PowerDescriptor(" << ZigbeeUtils::convertByteToHexString(powerDescriptor.powerDescriptoFlag) << ")" << endl;
debug.nospace() << " Power mode: " << powerDescriptor.powerMode << endl;
debug.nospace() << " Available power sources: " << powerDescriptor.availablePowerSources << endl;
debug.nospace() << " Power source: " << powerDescriptor.powerSource << endl;
debug.nospace() << " Power level: " << powerDescriptor.powerLevel << endl;
return debug;
}

View File

@ -174,8 +174,121 @@ public:
} Adpu;
static ZigbeeDeviceProfile::Adpu parseAdpu(const QByteArray &adpu);
// Node information
enum NodeType {
NodeTypeCoordinator = 0,
NodeTypeRouter = 1,
NodeTypeEndDevice = 2
};
Q_ENUM(NodeType)
enum FrequencyBand {
FrequencyBand868Mhz,
FrequencyBand902Mhz,
FrequencyBand2400Mhz
};
Q_ENUM(FrequencyBand)
enum DeviceType {
DeviceTypeFullFunction,
DeviceTypeReducedFunction
};
Q_ENUM(DeviceType)
enum Relationship {
Parent,
Child,
Sibling
};
Q_ENUM(Relationship)
enum PowerMode {
PowerModeAlwaysOn,
PowerModeOnPeriodically,
PowerModeOnWhenStimulated
};
Q_ENUM(PowerMode)
enum PowerSource {
PowerSourcePermanentMainSupply,
PowerSourceRecharchableBattery,
PowerSourceDisposableBattery
};
Q_ENUM(PowerSource)
enum PowerLevel {
PowerLevelCriticalLow,
PowerLevelLow,
PowerLevelOk,
PowerLevelFull
};
Q_ENUM(PowerLevel)
typedef struct MacCapabilities {
quint8 flag = 0x00; // For saving
bool alternatePanCoordinator = false;
DeviceType deviceType = DeviceTypeReducedFunction;
bool powerSourceFlagMainPower = false;
bool receiverOnWhenIdle = false;
bool securityCapability = false;
bool allocateAddress = false;
} MacCapabilities;
typedef struct DescriptorCapabilities {
quint8 descriptorCapabilitiesFlag = 0x00; // For saving
bool extendedActiveEndpointListAvailable = false;
bool extendedSimpleDescriptorListAvailable = false;
} DescriptorCapabilities;
typedef struct ServerMask {
quint16 serverMaskFlag = 0x0000; // For saving
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 {
QByteArray descriptorRawData; // For saving
NodeType nodeType = NodeTypeEndDevice;
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;
typedef struct PowerDescriptor {
quint16 powerDescriptoFlag = 0x0000;
PowerMode powerMode = PowerModeAlwaysOn;
QList<PowerSource> availablePowerSources;
PowerSource powerSource = PowerSourcePermanentMainSupply;
PowerLevel powerLevel = PowerLevelFull;
} PowerDescriptor;
static NodeDescriptor parseNodeDescriptor(const QByteArray &payload);
static MacCapabilities parseMacCapabilities(quint8 macCapabilitiesFlag);
static ServerMask parseServerMask(quint16 serverMaskFlag);
static DescriptorCapabilities parseDescriptorCapabilities(quint8 descriptorCapabilitiesFlag);
static PowerDescriptor parsePowerDescriptor(quint16 powerDescriptorFlag);
};
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::Adpu &deviceAdpu);
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::NodeDescriptor &nodeDescriptor);
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::MacCapabilities &macCapabilities);
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::ServerMask &serverMask);
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::DescriptorCapabilities &descriptorCapabilities);
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::PowerDescriptor &powerDescriptor);
#endif // ZIGBEEDEVICEPROFILE_H

View File

@ -28,6 +28,7 @@
#include "zigbeeutils.h"
#include "zigbeenetwork.h"
#include "loggingcategory.h"
#include "zdo/zigbeedeviceprofile.h"
#include <QSqlQuery>
@ -174,11 +175,6 @@ quint8 ZigbeeNetwork::generateSequenceNumber()
return m_sequenceNumber++;
}
quint8 ZigbeeNetwork::generateTranactionSequenceNumber()
{
return m_transactionSequenceNumber++;
}
QList<ZigbeeNode *> ZigbeeNetwork::nodes() const
{
return m_nodes;
@ -233,6 +229,28 @@ bool ZigbeeNetwork::hasNode(const ZigbeeAddress &address) const
return getZigbeeNode(address) != nullptr;
}
void ZigbeeNetwork::removeZigbeeNode(const ZigbeeAddress &address)
{
ZigbeeNode *node = getZigbeeNode(address);
if (!node) {
qCWarning(dcZigbeeNetwork()) << "Failed remove zigbee node since there is no node with" << address;
return;
}
qCDebug(dcZigbeeNetwork()) << "Removing" << node << "from the newtork";
ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestMgmtLeaveNetwork();
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [this, zdoReply, node](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeeNode()) << "Failed to send management leave request to" << node << zdoReply->error();
qCWarning(dcZigbeeNode()) << "This node is gonna be removed internally and tried to remove once it shows up the next time.";
}
removeNode(node);
});
}
void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node)
{
if (m_nodes.contains(node)) {
@ -272,7 +290,7 @@ ZigbeeNode *ZigbeeNetwork::createNode(quint16 shortAddress, const ZigbeeAddress
ZigbeeNode *ZigbeeNetwork::createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, quint8 macCapabilities, QObject *parent)
{
ZigbeeNode *node = createNode(shortAddress, extendedAddress, parent);
node->setMacCapabilitiesFlag(macCapabilities);
node->m_macCapabilities = ZigbeeDeviceProfile::parseMacCapabilities(macCapabilities);
return node;
}
@ -317,22 +335,9 @@ void ZigbeeNetwork::loadNetwork()
settings.beginGroup(ieeeAddressString);
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());
node->m_complexDescriptorAvailable = settings.value("complexDescriptor", false).toBool();
node->m_userDescriptorAvailable = settings.value("userDescriptor", false).toBool();
node->m_frequencyBand = static_cast<ZigbeeNode::FrequencyBand>(settings.value("frequencyBand", 0).toUInt());
node->setMacCapabilitiesFlag(static_cast<quint8>(settings.value("macCapabilitiesFlag", 0).toUInt()));
node->m_manufacturerCode = static_cast<quint16>(settings.value("manufacturerCode", 0).toUInt());
node->m_maximumBufferSize = static_cast<quint8>(settings.value("maximumBufferSize", 0).toUInt());
node->m_maximumRxSize = static_cast<quint16>(settings.value("maximumRxSize", 0).toUInt());
node->m_maximumTxSize = static_cast<quint16>(settings.value("maximumTxSize", 0).toUInt());
node->setServerMask(static_cast<quint16>(settings.value("serverMask", 0).toUInt()));
node->setDescriptorFlag(static_cast<quint8>(settings.value("descriptorCapabilities", 0).toUInt()));
// Power descriptor
node->setPowerDescriptorFlag(static_cast<quint16>(settings.value("powerDescriptorFlag", 0).toUInt()));
node->m_nodeDescriptor = ZigbeeDeviceProfile::parseNodeDescriptor(settings.value("nodeDescriptorRaw").toByteArray());
node->m_macCapabilities = node->nodeDescriptor().macCapabilities;
node->m_powerDescriptor = ZigbeeDeviceProfile::parsePowerDescriptor(static_cast<quint16>(settings.value("powerDescriptorFlag", 0).toUInt()));
int endpointsCount = settings.beginReadArray("endpoints");
//qCDebug(dcZigbeeNetwork()) << "loading endpoints" << endpointsCount << settings.childKeys() << settings.childGroups();
@ -399,7 +404,7 @@ void ZigbeeNetwork::clearSettings()
m_extendedPanId = 0;
m_channel = 0;
m_securityConfiguration.clear();
m_nodeType = ZigbeeNode::NodeTypeCoordinator;
m_nodeType = ZigbeeDeviceProfile::NodeTypeCoordinator;
}
void ZigbeeNetwork::saveNode(ZigbeeNode *node)
@ -412,20 +417,10 @@ void ZigbeeNetwork::saveNode(ZigbeeNode *node)
settings.setValue("nwkAddress", node->shortAddress());
// Node descriptor
settings.setValue("nodeType", node->m_nodeType);
settings.setValue("complexDescriptor", node->complexDescriptorAvailable());
settings.setValue("userDescriptor", node->userDescriptorAvailable());
settings.setValue("frequencyBand", node->frequencyBand());
settings.setValue("macCapabilitiesFlag", node->m_macCapabilitiesFlag);
settings.setValue("manufacturerCode", node->m_manufacturerCode);
settings.setValue("maximumBufferSize", node->m_maximumBufferSize);
settings.setValue("maximumRxSize", node->m_maximumRxSize);
settings.setValue("maximumTxSize", node->m_maximumTxSize);
settings.setValue("serverMask", node->m_serverMask);
settings.setValue("descriptorCapabilities", node->m_descriptorFlag);
settings.setValue("nodeDescriptorRaw", node->nodeDescriptor().descriptorRawData);
// Power descriptor
settings.setValue("powerDescriptorFlag", node->m_powerDescriptorFlag);
settings.setValue("powerDescriptorFlag", node->powerDescriptor().powerDescriptoFlag);
settings.beginWriteArray("endpoints");
for (int i = 0; i < node->endpoints().count(); i++) {
@ -603,53 +598,25 @@ void ZigbeeNetwork::onNodeClusterAttributeChanged(ZigbeeCluster *cluster, const
saveNode(node);
}
QDebug operator<<(QDebug debug, ZigbeeNetwork *network)
{
debug.nospace().noquote() << "ZigbeeNetwork (" << ZigbeeUtils::convertUint64ToHexString(network->extendedPanId())
<< ", Channel " << network->channel()
<< ")" << endl;
foreach (ZigbeeNode *node, network->nodes()) {
debug.nospace().noquote() << " - " << node << endl;
debug.nospace().noquote() << " Node type:" << node->nodeType() << endl;
debug.nospace().noquote() << " Manufacturer code: " << ZigbeeUtils::convertUint16ToHexString(node->manufacturerCode()) << endl;
debug.nospace().noquote() << " Maximum Rx size: " << ZigbeeUtils::convertUint16ToHexString(node->maximumRxSize()) << endl;
debug.nospace().noquote() << " Maximum Tx size: " << ZigbeeUtils::convertUint16ToHexString(node->maximumTxSize()) << endl;
debug.nospace().noquote() << " Maximum buffer size: " << ZigbeeUtils::convertByteToHexString(node->maximumBufferSize()) << endl;
debug.nospace().noquote() << " Primary Trust center: " << node->isPrimaryTrustCenter() << endl;
debug.nospace().noquote() << " Backup Trust center: " << node->isBackupTrustCenter() << endl;
debug.nospace().noquote() << " Primary Binding cache: " << node->isPrimaryBindingCache() << endl;
debug.nospace().noquote() << " Backup Binding cache: " << node->isBackupBindingCache() << endl;
debug.nospace().noquote() << " Primary Discovery cache: " << node->isPrimaryDiscoveryCache() << endl;
debug.nospace().noquote() << " Backup Discovery cache: " << node->isBackupDiscoveryCache() << endl;
debug.nospace().noquote() << " Network Manager: " << node->isNetworkManager() << endl;
debug.nospace().noquote() << " Extended active endpoint list available: " << node->extendedActiveEndpointListAvailable() << endl;
debug.nospace().noquote() << " Extended simple descriptor list available: " << node->extendedSimpleDescriptorListAvailable() << endl;
debug.nospace().noquote() << " Alternate PAN coordinator: " << node->alternatePanCoordinator() << endl;
debug.nospace().noquote() << " Device type: " << node->deviceType() << endl;
debug.nospace().noquote() << " Power source flag main power: " << node->powerSourceFlagMainPower() << endl;
debug.nospace().noquote() << " Receiver on when idle: " << node->receiverOnWhenIdle() << endl;
debug.nospace().noquote() << " Security capability: " << node->securityCapability() << endl;
debug.nospace().noquote() << " Allocate address: " << node->allocateAddress() << endl;
debug.nospace().noquote() << " Complex desciptor available: " << node->complexDescriptorAvailable() << endl;
debug.nospace().noquote() << " User desciptor available: " << node->userDescriptorAvailable() << endl;
debug.nospace().noquote() << " Power mode: " << node->powerMode() << endl;
debug.nospace().noquote() << " Available power sources:" << endl;
foreach (const ZigbeeNode::PowerSource &source, node->availablePowerSources()) {
debug.nospace().noquote() << " - " << source << endl;
}
debug.nospace().noquote() << " Power source: " << node->powerSource() << endl;
debug.nospace().noquote() << " Power level: " << node->powerLevel() << endl;
debug.nospace().noquote() << " Endpoints: " << node->endpoints().count() << endl;
debug.nospace().noquote() << " ---> " << node << endl;
debug.nospace().noquote() << " " << node->nodeDescriptor();
debug.nospace().noquote() << " " << node->powerDescriptor();
debug.nospace().noquote() << " Endpoints: " << node->endpoints().count() << endl;
foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
debug.nospace().noquote() << " - " << endpoint << endl;
debug.nospace().noquote() << " Input clusters:" << endl;
debug.nospace().noquote() << " - " << endpoint << endl;
debug.nospace().noquote() << " Input clusters:" << endl;
foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) {
debug.nospace().noquote() << " - " << cluster << endl;
debug.nospace().noquote() << " - " << cluster << endl;
}
debug.nospace().noquote() << " Output clusters:" << endl;
debug.nospace().noquote() << " Output clusters:" << endl;
foreach (ZigbeeCluster *cluster, endpoint->outputClusters()) {
debug.nospace().noquote() << " - " << cluster << endl;
debug.nospace().noquote() << " - " << cluster << endl;
}
}
}

View File

@ -98,7 +98,6 @@ public:
void setPermitJoining(bool permitJoining);
quint8 generateSequenceNumber();
quint8 generateTranactionSequenceNumber();
// Network nodes
QList<ZigbeeNode *> nodes() const;
@ -113,6 +112,8 @@ public:
virtual ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) = 0;
void removeZigbeeNode(const ZigbeeAddress &address);
private:
State m_state = StateUninitialized;
@ -120,15 +121,15 @@ private:
QString m_serialPortName = "/dev/ttyUSB0";
qint32 m_serialBaudrate = 115200;
// Continuouse ASP sequence number for network requests
quint8 m_sequenceNumber = 0;
quint8 m_transactionSequenceNumber = 0;
// Network configurations
quint16 m_panId = 0;
quint64 m_extendedPanId = 0;
quint32 m_channel = 0;
ZigbeeChannelMask m_channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels);
ZigbeeNode::NodeType m_nodeType = ZigbeeNode::NodeTypeCoordinator;
ZigbeeDeviceProfile::NodeType m_nodeType = ZigbeeDeviceProfile::NodeTypeCoordinator;
// Network storage
QString m_settingsFileName = "/etc/nymea/nymea-zigbee.conf";

View File

@ -87,144 +87,19 @@ ZigbeeNodeEndpoint *ZigbeeNode::getEndpoint(quint8 endpointId) const
return nullptr;
}
ZigbeeNode::NodeType ZigbeeNode::nodeType() const
ZigbeeDeviceProfile::NodeDescriptor ZigbeeNode::nodeDescriptor() const
{
return m_nodeType;
return m_nodeDescriptor;
}
ZigbeeNode::FrequencyBand ZigbeeNode::frequencyBand() const
ZigbeeDeviceProfile::MacCapabilities ZigbeeNode::macCapabilities() const
{
return m_frequencyBand;
return m_macCapabilities;
}
ZigbeeNode::Relationship ZigbeeNode::relationship() const
ZigbeeDeviceProfile::PowerDescriptor ZigbeeNode::powerDescriptor() const
{
return m_relationship;
}
quint16 ZigbeeNode::manufacturerCode() const
{
return m_manufacturerCode;
}
bool ZigbeeNode::complexDescriptorAvailable() const
{
return m_complexDescriptorAvailable;
}
bool ZigbeeNode::userDescriptorAvailable() const
{
return m_userDescriptorAvailable;
}
quint16 ZigbeeNode::maximumRxSize() const
{
return m_maximumRxSize;
}
quint16 ZigbeeNode::maximumTxSize() const
{
return m_maximumTxSize;
}
quint8 ZigbeeNode::maximumBufferSize() const
{
return m_maximumBufferSize;
}
bool ZigbeeNode::isPrimaryTrustCenter() const
{
return m_isPrimaryTrustCenter;
}
bool ZigbeeNode::isBackupTrustCenter() const
{
return m_isBackupTrustCenter;
}
bool ZigbeeNode::isPrimaryBindingCache() const
{
return m_isPrimaryBindingCache;
}
bool ZigbeeNode::isBackupBindingCache() const
{
return m_isBackupBindingCache;
}
bool ZigbeeNode::isPrimaryDiscoveryCache() const
{
return m_isPrimaryDiscoveryCache;
}
bool ZigbeeNode::isBackupDiscoveryCache() const
{
return m_isBackupDiscoveryCache;
}
bool ZigbeeNode::isNetworkManager() const
{
return m_isNetworkManager;
}
bool ZigbeeNode::extendedActiveEndpointListAvailable() const
{
return m_extendedActiveEndpointListAvailable;
}
bool ZigbeeNode::extendedSimpleDescriptorListAvailable() const
{
return m_extendedSimpleDescriptorListAvailable;
}
bool ZigbeeNode::alternatePanCoordinator() const
{
return m_alternatePanCoordinator;
}
ZigbeeNode::DeviceType ZigbeeNode::deviceType() const
{
return m_deviceType;
}
bool ZigbeeNode::powerSourceFlagMainPower() const
{
return m_powerSourceFlagMainPower;
}
bool ZigbeeNode::receiverOnWhenIdle() const
{
return m_receiverOnWhenIdle;
}
bool ZigbeeNode::securityCapability() const
{
return m_securityCapability;
}
bool ZigbeeNode::allocateAddress() const
{
return m_allocateAddress;
}
ZigbeeNode::PowerMode ZigbeeNode::powerMode() const
{
return m_powerMode;
}
ZigbeeNode::PowerSource ZigbeeNode::powerSource() const
{
return m_powerSource;
}
QList<ZigbeeNode::PowerSource> ZigbeeNode::availablePowerSources() const
{
return m_availablePowerSources;
}
ZigbeeNode::PowerLevel ZigbeeNode::powerLevel() const
{
return m_powerLevel;
return m_powerDescriptor;
}
void ZigbeeNode::setState(ZigbeeNode::State state)
@ -247,136 +122,6 @@ void ZigbeeNode::setConnected(bool connected)
emit connectedChanged(m_connected);
}
void ZigbeeNode::setShortAddress(const quint16 &shortAddress)
{
m_shortAddress = shortAddress;
}
void ZigbeeNode::setExtendedAddress(const ZigbeeAddress &extendedAddress)
{
m_extendedAddress = extendedAddress;
}
quint16 ZigbeeNode::serverMask() const
{
return m_serverMask;
}
void ZigbeeNode::setServerMask(quint16 serverMask)
{
m_serverMask = serverMask;
m_isPrimaryTrustCenter = ((m_serverMask >> 0) & 0x0001);
m_isBackupTrustCenter = ((m_serverMask >> 1) & 0x0001);
m_isPrimaryBindingCache = ((m_serverMask >> 2) & 0x0001);
m_isBackupBindingCache = ((m_serverMask >> 3) & 0x0001);
m_isPrimaryDiscoveryCache = ((m_serverMask >> 4) & 0x0001);
m_isBackupDiscoveryCache = ((m_serverMask >> 5) & 0x0001);
m_isNetworkManager = ((m_serverMask >> 6) & 0x0001);
}
quint8 ZigbeeNode::macCapabilitiesFlag() const
{
return m_macCapabilitiesFlag;
}
void ZigbeeNode::setMacCapabilitiesFlag(quint8 macFlag)
{
m_macCapabilitiesFlag = macFlag;
m_alternatePanCoordinator = ((m_macCapabilitiesFlag >> 0) & 0x01);
if (((m_macCapabilitiesFlag >> 1) & 0x01)) {
m_deviceType = DeviceTypeFullFunction;
} else {
m_deviceType = DeviceTypeReducedFunction;
}
m_powerSourceFlagMainPower = ((m_macCapabilitiesFlag >> 2) & 0x01);
m_receiverOnWhenIdle = ((m_macCapabilitiesFlag >> 3) & 0x01);
m_securityCapability = ((m_macCapabilitiesFlag >> 6) & 0x01);
m_allocateAddress = ((m_macCapabilitiesFlag >> 7) & 0x01);
}
void ZigbeeNode::setDescriptorFlag(quint8 descriptorFlag)
{
m_descriptorFlag = descriptorFlag;
m_extendedActiveEndpointListAvailable = ((m_descriptorFlag >> 0) & 0x01);
m_extendedSimpleDescriptorListAvailable = ((m_descriptorFlag >> 1) & 0x01);
}
quint16 ZigbeeNode::powerDescriptorFlag() const
{
return m_powerDescriptorFlag;
}
void ZigbeeNode::setPowerDescriptorFlag(quint16 powerDescriptorFlag)
{
m_powerDescriptorFlag = powerDescriptorFlag;
qCDebug(dcZigbeeNode()) << "Parse power descriptor flag" << ZigbeeUtils::convertUint16ToHexString(m_powerDescriptorFlag);
// Bit 0 - 3 Power mode
// 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor
// 0001: Receiver switched on periodically
// 0010: Receiver switched on when stimulated, e.g. by pressing a button
m_powerMode = PowerModeAlwaysOn;
if (!ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 1)) {
m_powerMode = PowerModeAlwaysOn;
} else if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 1)) {
m_powerMode = PowerModeOnPeriodically;
} else if (!ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 0) && ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 1)) {
m_powerMode = PowerModeOnWhenStimulated;
}
// Bit 4 - 7 Available power sources
// 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)) {
m_availablePowerSources.append(PowerSourcePermanentMainSupply);
} else if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 5)) {
m_availablePowerSources.append(PowerSourceRecharchableBattery);
} else if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 6)) {
m_availablePowerSources.append(PowerSourceDisposableBattery);
}
// Bit 8 - 11 Active source: according to the same schema as available power sources
m_powerSource = PowerSourcePermanentMainSupply;
if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 8)) {
m_powerSource = PowerSourcePermanentMainSupply;
} else if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 9)) {
m_powerSource = PowerSourceRecharchableBattery;
} else if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 10)) {
m_powerSource = PowerSourceDisposableBattery;
}
// Bit 12 - 15: Battery level if available
// 0000: Critically low
// 0100: Approximately 33%
// 1000: Approximately 66%
// 1100: Approximately 100% (near fully charged)
m_powerLevel = PowerLevelCriticalLow;
if (!ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 14) && !ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 15)) {
m_powerLevel = PowerLevelCriticalLow;
} else if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 14) && !ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 15)) {
m_powerLevel = PowerLevelLow;
} else if (!ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 14) && ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 15)) {
m_powerLevel = PowerLevelOk;
} else if (ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 14) && ZigbeeUtils::checkBitUint16(m_powerDescriptorFlag, 15)) {
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;
}
void ZigbeeNode::startInitialization()
{
setState(StateInitializing);
@ -421,72 +166,10 @@ void ZigbeeNode::initNodeDescriptor()
}
qCDebug(dcZigbeeNode()) << this << "reading node descriptor finished successfully.";
m_nodeDescriptor = ZigbeeDeviceProfile::parseNodeDescriptor(reply->responseAdpu().payload);
qCDebug(dcZigbeeNode()) << m_nodeDescriptor;
m_requestRetry = 0;
// 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();
});
@ -524,7 +207,8 @@ void ZigbeeNode::initPowerDescriptor()
stream.setByteOrder(QDataStream::LittleEndian);
quint16 powerDescriptorFlag = 0;
stream >> powerDescriptorFlag;
setPowerDescriptorFlag(powerDescriptorFlag);
m_powerDescriptor = ZigbeeDeviceProfile::parsePowerDescriptor(powerDescriptorFlag);
qCDebug(dcZigbeeNode()) << m_powerDescriptor;
// Continue with endpoint fetching
initEndpoints();

View File

@ -34,6 +34,7 @@
#include "zigbeeaddress.h"
#include "zigbeenodeendpoint.h"
#include "zdo/zigbeedeviceobject.h"
#include "zdo/zigbeedeviceprofile.h"
class ZigbeeNetwork;
@ -51,94 +52,6 @@ public:
};
Q_ENUM(State)
enum NodeType {
NodeTypeCoordinator = 0,
NodeTypeRouter = 1,
NodeTypeEndDevice = 2
};
Q_ENUM(NodeType)
enum FrequencyBand {
FrequencyBand868Mhz,
FrequencyBand902Mhz,
FrequencyBand2400Mhz
};
Q_ENUM(FrequencyBand)
enum DeviceType {
DeviceTypeFullFunction,
DeviceTypeReducedFunction
};
Q_ENUM(DeviceType)
enum Relationship {
Parent,
Child,
Sibling
};
Q_ENUM(Relationship)
enum PowerMode {
PowerModeAlwaysOn,
PowerModeOnPeriodically,
PowerModeOnWhenStimulated
};
Q_ENUM(PowerMode)
enum PowerSource {
PowerSourcePermanentMainSupply,
PowerSourceRecharchableBattery,
PowerSourceDisposableBattery
};
Q_ENUM(PowerSource)
enum PowerLevel {
PowerLevelCriticalLow,
PowerLevelLow,
PowerLevelOk,
PowerLevelFull
};
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 = NodeTypeEndDevice;
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;
@ -151,45 +64,16 @@ public:
bool hasEndpoint(quint8 endpointId) const;
ZigbeeNodeEndpoint *getEndpoint(quint8 endpointId) const;
// Information from node descriptor
NodeType nodeType() const;
FrequencyBand frequencyBand() const;
Relationship relationship() const;
quint16 manufacturerCode() const;
bool complexDescriptorAvailable() const;
bool userDescriptorAvailable() const;
quint16 maximumRxSize() const;
quint16 maximumTxSize() const;
quint8 maximumBufferSize() const;
// Server Mask
bool isPrimaryTrustCenter() const;
bool isBackupTrustCenter() const;
bool isPrimaryBindingCache() const;
bool isBackupBindingCache() const;
bool isPrimaryDiscoveryCache() const;
bool isBackupDiscoveryCache() const;
bool isNetworkManager() const;
// Descriptor capability
bool extendedActiveEndpointListAvailable() const;
bool extendedSimpleDescriptorListAvailable() const;
// Mac capabilities flag
bool alternatePanCoordinator() const;
DeviceType deviceType() const;
bool powerSourceFlagMainPower() const;
bool receiverOnWhenIdle() const;
bool securityCapability() const;
bool allocateAddress() const;
// Information from descriptors
ZigbeeDeviceProfile::NodeDescriptor nodeDescriptor() const;
ZigbeeDeviceProfile::MacCapabilities macCapabilities() const;
ZigbeeDeviceProfile::PowerDescriptor powerDescriptor() const;
// Information from node power descriptor
PowerMode powerMode() const;
PowerSource powerSource() const;
QList<PowerSource> availablePowerSources() const;
PowerLevel powerLevel() const;
ZigbeeDeviceProfile::PowerMode powerMode() const;
ZigbeeDeviceProfile::PowerSource powerSource() const;
QList<ZigbeeDeviceProfile::PowerSource> availablePowerSources() const;
ZigbeeDeviceProfile::PowerLevel powerLevel() const;
// This method starts the node initialization phase (read descriptors and endpoints)
void startInitialization();
@ -198,86 +82,26 @@ private:
ZigbeeNode(ZigbeeNetwork *network, quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent = nullptr);
ZigbeeNetwork *m_network;
quint16 m_shortAddress = 0;
ZigbeeAddress m_extendedAddress;
ZigbeeDeviceObject *m_deviceObject = nullptr;
QList<ZigbeeNodeEndpoint *> m_endpoints;
bool m_connected = false;
State m_state = StateUninitialized;
quint8 m_lqi = 0;
// Node descriptor information
QByteArray m_nodeDescriptorRawData;
NodeType m_nodeType = NodeTypeRouter;
FrequencyBand m_frequencyBand = FrequencyBand2400Mhz;
Relationship m_relationship = Parent;
quint16 m_manufacturerCode = 0;
bool m_complexDescriptorAvailable = false;
bool m_userDescriptorAvailable = false;
quint16 m_maximumRxSize = 0;
quint16 m_maximumTxSize = 0;
quint8 m_maximumBufferSize = 0;
// Node information
ZigbeeDeviceProfile::NodeDescriptor m_nodeDescriptor;
ZigbeeDeviceProfile::MacCapabilities m_macCapabilities;
ZigbeeDeviceProfile::PowerDescriptor m_powerDescriptor;
void setState(State state);
void setConnected(bool connected);
void setShortAddress(const quint16 &shortAddress);
void setExtendedAddress(const ZigbeeAddress &extendedAddress);
quint16 serverMask() const;
void setServerMask(quint16 serverMask);
// MAC capability raw data flag for settings
quint8 macCapabilitiesFlag() const;
void setMacCapabilitiesFlag(quint8 macFlag);
quint8 descriptorFlag() const;
void setDescriptorFlag(quint8 descriptorFlag);
// Power decriptor data
quint16 powerDescriptorFlag() const;
void setPowerDescriptorFlag(quint16 powerDescriptorFlag);
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
int m_requestRetry = 0;
QList<quint8> m_uninitializedEndpoints;
void initNodeDescriptor();
void initPowerDescriptor();
void initEndpoints();
@ -291,6 +115,7 @@ private:
signals:
void stateChanged(State state);
void lqiChanged(quint8 lqi);
void connectedChanged(bool connected);
void clusterAdded(ZigbeeCluster *cluster);
void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);

View File

@ -176,7 +176,11 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, Zi
case Zigbee::ClusterIdIdentify:
return new ZigbeeClusterIdentify(m_network, m_node, this, direction, this);
break;
// Measurement
case Zigbee::ClusterIdLevelControl:
return new ZigbeeClusterLevelControl(m_network, m_node, this, direction, this);
break;
// Measurement
case Zigbee::ClusterIdTemperatureMeasurement:
return new ZigbeeClusterTemperatureMeasurement(m_network, m_node, this, direction, this);
break;
@ -189,7 +193,8 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, Zi
case Zigbee::ClusterIdIlluminanceMeasurement:
return new ZigbeeClusterIlluminanceMeasurment(m_network, m_node, this, direction, this);
break;
// Security
// Security
case Zigbee::ClusterIdIasZone:
return new ZigbeeClusterIasZone(m_network, m_node, this, direction, this);
break;

View File

@ -40,6 +40,7 @@
#include "zcl/general/zigbeeclusterbasic.h"
#include "zcl/general/zigbeeclusteronoff.h"
#include "zcl/general/zigbeeclusteridentify.h"
#include "zcl/general/zigbeeclusterlevelcontrol.h"
#include "zcl/measurement/zigbeeclusteroccupancysensing.h"
#include "zcl/measurement/zigbeeclusterilluminancemeasurment.h"