Fix indication matching and rely handling in network instance

This commit is contained in:
Simon Stürz 2020-04-13 13:46:11 +02:00
parent 118cdedc6a
commit 882023198a
16 changed files with 605 additions and 67 deletions

View File

@ -64,7 +64,10 @@ public:
CommandVersion = 0x0D,
CommandApsDataRequest = 0x12,
CommandApsDataConfirm = 0x04,
CommandApsDataIndication = 0x17
CommandApsDataIndication = 0x17,
CommandGreenPower = 0x19,
CommandMacPoll = 0x1C,
CommandSimplifiedBeacon = 0x1F
};
Q_ENUM(Command)

View File

@ -172,6 +172,7 @@ void ZigbeeInterfaceDeconz::onReadyRead()
}
// Checksum verified, we got valid data
qCDebug(dcZigbeeInterface()) << "Received frame" << ZigbeeUtils::convertByteArrayToHexString(frame);
emit packageReceived(package);
}
m_dataBuffer.clear();
@ -206,6 +207,8 @@ void ZigbeeInterfaceDeconz::sendPackage(const QByteArray &package)
frameStream.setByteOrder(QDataStream::LittleEndian);
frameStream << checksum;
qCDebug(dcZigbeeInterface()) << "Send frame" << ZigbeeUtils::convertByteArrayToHexString(frame);
// Escape data according to SLIP for transfere
QByteArray serializedData = escapeData(frame);

View File

@ -25,10 +25,11 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeebridgecontrollerdeconz.h"
#include "loggingcategory.h"
#include "zigbeeutils.h"
#include "loggingcategory.h"
#include "zigbeechannelmask.h"
#include "zigbeedeviceprofile.h"
#include "zigbeebridgecontrollerdeconz.h"
#include <QDataStream>
@ -220,19 +221,19 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestQuerySendDataCo
return createReply(Deconz::CommandApsDataConfirm, sequenceNumber, this);
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius)
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius)
{
quint8 sequenceNumber = generateSequenceNumber();
qCDebug(dcZigbeeController()) << "Request enqueue send data to group" << ZigbeeUtils::convertUint16ToHexString(groupAddress)
<< "SQN:" << sequenceNumber
<< ZigbeeUtils::convertByteToHexString(destinationEndpoint)
<< profileId << clusterId
<< static_cast<Zigbee::ZigbeeProfile>(profileId)
<< ZigbeeUtils::convertUint16ToHexString(clusterId)
<< ZigbeeUtils::convertByteToHexString(sourceEndpoint);
Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes");
// Note: 15 protocol bytes + asdu package length
quint16 payloadLength = static_cast<quint16>(15 + asdu.length());
// Note: 14 protocol bytes + asdu package length
quint16 payloadLength = static_cast<quint16>(14 + asdu.length());
QByteArray message;
QDataStream stream(&message, QIODevice::WriteOnly);
@ -245,7 +246,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
stream << requestId;
stream << static_cast<quint8>(0); // Flags
stream << static_cast<quint8>(Zigbee::DestinationAddressModeGroup);
stream << groupAddress << destinationEndpoint;
stream << groupAddress;
stream << profileId;
stream << clusterId;
stream << sourceEndpoint;
@ -253,7 +254,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
for (int i = 0; i < asdu.length(); i++) {
stream << static_cast<quint8>(asdu.at(i));
}
stream << static_cast<quint8>(0x04); // TX Options: Use ASP ACKs
stream << static_cast<quint8>(txOptions);
stream << radius;
m_interface->sendPackage(message);
@ -261,13 +262,14 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this);
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius)
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius)
{
quint8 sequenceNumber = generateSequenceNumber();
qCDebug(dcZigbeeController()) << "Request enqueue send data to short address" << ZigbeeUtils::convertUint16ToHexString(shortAddress)
<< "SQN:" << sequenceNumber
<< ZigbeeUtils::convertByteToHexString(destinationEndpoint)
<< profileId << clusterId
<< static_cast<Zigbee::ZigbeeProfile>(profileId)
<< ZigbeeUtils::convertUint16ToHexString(clusterId)
<< ZigbeeUtils::convertByteToHexString(sourceEndpoint);
Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes");
@ -294,7 +296,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
for (int i = 0; i < asdu.length(); i++) {
stream << static_cast<quint8>(asdu.at(i));
}
stream << static_cast<quint8>(0x04); // TX Options: Use ASP ACKs
stream << static_cast<quint8>(txOptions); // TX Options: Use ASP ACKs
stream << radius;
m_interface->sendPackage(message);
@ -302,7 +304,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this);
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius)
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius)
{
quint8 sequenceNumber = generateSequenceNumber();
qCDebug(dcZigbeeController()) << "Request enqueue send data to IEEE address" << ieeeAddress.toString()
@ -335,7 +337,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
for (int i = 0; i < asdu.length(); i++) {
stream << static_cast<quint8>(asdu.at(i));
}
stream << static_cast<quint8>(0x04); // TX Options: Use ASP ACKs
stream << static_cast<quint8>(txOptions); // TX Options: Use ASP ACKs
stream << radius;
m_interface->sendPackage(message);
@ -349,18 +351,18 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(con
switch (request.destinationAddressMode()) {
case Zigbee::DestinationAddressModeGroup:
interfaceReply = requestEnqueueSendDataGroup(request.requestId(), request.destinationShortAddress(),
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.radius());
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.radius());
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.radius());
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.txOptions(), request.radius());
break;
}
@ -936,6 +938,14 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
processDeviceState(parseDeviceStateFlag(deviceStateFlag));
break;
}
case Deconz::CommandMacPoll: {
// FIXME: parse the data and print info
break;
}
case Deconz::CommandSimplifiedBeacon: {
// FIXME: parse the data and print info
break;
}
default:
qCWarning(dcZigbeeController()) << "Unhandled interface package received" << command << "SQN:" << sequenceNumber
<< status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data);
@ -1050,3 +1060,22 @@ QDebug operator<<(QDebug debug, const DeconzApsDataIndication &indication)
debug.nospace() << "RSSI: " << indication.rssi << "dBm)";
return debug.space();
}
QDebug operator<<(QDebug debug, const DeconzNetworkConfiguration &configuration)
{
debug.nospace() << "Network configuration:" << endl;
debug.nospace() << " - Node type:" << configuration.nodeType << endl;
debug.nospace() << " - IEEE address:" << configuration.ieeeAddress.toString() << endl;
debug.nospace() << " - NWK address:" << ZigbeeUtils::convertUint16ToHexString(configuration.shortAddress) << endl;
debug.nospace() << " - PAN ID:" << ZigbeeUtils::convertUint16ToHexString(configuration.panId) << endl;
debug.nospace() << " - Extended PAN ID:" << ZigbeeUtils::convertUint64ToHexString(configuration.extendedPanId) << endl;
debug.nospace() << " - ASP Extended PAN ID:" << ZigbeeUtils::convertUint64ToHexString(configuration.apsExtendedPanId) << endl;
debug.nospace() << " - Trust center IEEE address:" << configuration.trustCenterAddress.toString() << endl;
debug.nospace() << " - Channel mask:" << ZigbeeChannelMask(configuration.channelMask) << endl;
debug.nospace() << " - Channel:" << configuration.currentChannel << endl;
debug.nospace() << " - Security mode:" << configuration.securityMode << endl;
debug.nospace() << " - Protocol version:" << ZigbeeUtils::convertUint16ToHexString(configuration.protocolVersion) << endl;
debug.nospace() << " - Network update ID:" << ZigbeeUtils::convertByteToHexString(configuration.networkUpdateId) << endl;
debug.nospace() << " - Watchdog TTL:" << configuration.watchdogTimeout << endl;
return debug.space();
}

View File

@ -125,9 +125,9 @@ public:
ZigbeeInterfaceDeconzReply *requestQuerySendDataConfirm();
// Send data
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0);
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0);
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0);
ZigbeeInterfaceDeconzReply *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);
@ -182,6 +182,7 @@ public slots:
QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState);
QDebug operator<<(QDebug debug, const DeconzApsDataConfirm &confirm);
QDebug operator<<(QDebug debug, const DeconzApsDataIndication &indication);
QDebug operator<<(QDebug debug, const DeconzNetworkConfiguration &configuration);
#endif // ZIGBEEBRIDGECONTROLLERDECONZ_H

View File

@ -45,6 +45,11 @@ ZigbeeNetworkDeconz::ZigbeeNetworkDeconz(QObject *parent) :
m_pollNetworkStateTimer->setInterval(1000);
m_pollNetworkStateTimer->setSingleShot(false);
connect(m_pollNetworkStateTimer, &QTimer::timeout, this, &ZigbeeNetworkDeconz::onPollNetworkStateTimeout);
m_permitJoinRefreshTimer = new QTimer(this);
m_permitJoinRefreshTimer->setInterval(250 * 1000);
m_permitJoinRefreshTimer->setSingleShot(false);
connect(m_permitJoinRefreshTimer, &QTimer::timeout, this, &ZigbeeNetworkDeconz::onPermitJoinRefreshTimout);
}
ZigbeeBridgeController *ZigbeeNetworkDeconz::bridgeController() const
@ -58,10 +63,13 @@ ZigbeeBridgeController *ZigbeeNetworkDeconz::bridgeController() const
ZigbeeNetworkReply *ZigbeeNetworkDeconz::sendRequest(const ZigbeeNetworkRequest &request)
{
ZigbeeNetworkReply *reply = createNetworkReply(request);
// Send the request, and keep the reply until transposrt, zigbee trasmission and response arrived
m_pendingReplies.insert(request.requestId(), reply);
connect(reply, &ZigbeeNetworkReply::finished, this, [this, request](){
m_pendingReplies.remove(request.requestId());
});
qCDebug(dcZigbeeNetwork()) << "Send request" << request;
ZigbeeInterfaceDeconzReply *interfaceReply = m_controller->requestSendRequest(request);
connect(interfaceReply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply, interfaceReply](){
if (interfaceReply->statusCode() != Deconz::StatusCodeSuccess) {
@ -74,6 +82,32 @@ ZigbeeNetworkReply *ZigbeeNetworkDeconz::sendRequest(const ZigbeeNetworkRequest
return reply;
}
ZigbeeNetworkReply *ZigbeeNetworkDeconz::setPermitJoin(quint16 shortAddress, quint8 duration)
{
// Get the power descriptor
ZigbeeNetworkRequest request;
request.setRequestId(generateSequenceNumber());
request.setDestinationAddressMode(Zigbee::DestinationAddressModeGroup);
request.setDestinationShortAddress(static_cast<quint16>(shortAddress));
request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP
request.setClusterId(ZigbeeDeviceProfile::MgmtPermitJoinRequest);
request.setSourceEndpoint(0); // ZDO
request.setRadius(10);
// Build ASDU
QByteArray asdu;
QDataStream stream(&asdu, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << request.requestId();
stream << duration;
stream << static_cast<quint8>(0x01); // TrustCenter significance, always force to 1 according to Spec.
request.setTxOptions(Zigbee::ZigbeeTxOptions(nullptr)); // no ACK for broadcasts
request.setAsdu(asdu);
qCDebug(dcZigbeeNetwork()) << "Send permit join request" << ZigbeeUtils::convertUint16ToHexString(request.destinationShortAddress()) << duration << "s";
return sendRequest(request);
}
quint8 ZigbeeNetworkDeconz::generateSequenceNumber()
{
return m_sequenceNumber++;
@ -253,16 +287,26 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeNodeDeconz *coordinatorNode = qobject_cast<ZigbeeNodeDeconz *>(createNode(this));
coordinatorNode->setShortAddress(m_controller->networkConfiguration().shortAddress);
coordinatorNode->setExtendedAddress(m_controller->networkConfiguration().ieeeAddress);
m_coordinatorNode = coordinatorNode;
// Network creation done when coordinator node is initialized
connect(coordinatorNode, &ZigbeeNodeDeconz::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){
if (state == ZigbeeNode::StateInitialized) {
qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode;
setState(StateRunning);
return;
}
});
addUnitializedNode(coordinatorNode);
coordinatorNode->startInitialization();
// TODO: done when when node initialized
addUnitializedNode(coordinatorNode);
}
}
}
void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const DeconzApsDataIndication &indication)
{
// Check if this is a device announcement
if (indication.clusterId == ZigbeeDeviceProfile::DeviceAnnounce) {
QDataStream stream(indication.asdu);
stream.setByteOrder(QDataStream::LittleEndian);
@ -273,15 +317,14 @@ void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const DeconzApsDat
}
// Check if this is a response for a ZDO request
foreach (ZigbeeNetworkReply *reply, m_pendingReplies) {
foreach (ZigbeeNetworkReply *reply, m_pendingReplies.values()) {
if (reply->request().profileId() == Zigbee::ZigbeeProfileDevice) {
// We have a reply which is waiting for a ZDO response, lets check if they match
// Check if this is the response to the sent request command
if (indication.clusterId == (reply->request().clusterId() | 0x8000)) {
// Now check if the id matches, if so set the ADPU as response to the reply, otherwise this is not the message for this reply
ZigbeeDeviceProfileAdpu deviceAdpu = ZigbeeDeviceProfile::parseAdpu(indication.asdu);
if (deviceAdpu.sequenceNumber == reply->request().requestId() && deviceAdpu.addressOfInterest == reply->request().destinationShortAddress()) {
if (deviceAdpu.sequenceNumber == reply->request().requestId()) {
// We found the correct reply
// Set the response payload of the
@ -296,6 +339,8 @@ void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const DeconzApsDat
}
}
}
qCWarning(dcZigbeeNetwork()) << "Unhandled ZDO indication" << indication;
}
ZigbeeNode *ZigbeeNetworkDeconz::createNode(QObject *parent)
@ -305,8 +350,52 @@ ZigbeeNode *ZigbeeNetworkDeconz::createNode(QObject *parent)
void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining)
{
//FIXME
Q_UNUSED(permitJoining)
quint8 duration = 0;
if (permitJoining == true) {
duration = 254;
}
// Note: since compliance version >= 21 the value 255 is not any more endless.
// we need to refresh the command on timeout
ZigbeeNetworkReply *reply = setPermitJoin(Zigbee::BroadcastAddressAllRouters, duration);
connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply, permitJoining, duration](){
if (reply->zigbeeStatus() != Zigbee::ZigbeeStatusSuccess) {
qCDebug(dcZigbeeNetwork()) << "Could not set permit join to" << duration;
m_permitJoining = false;
emit permitJoiningChanged(m_permitJoining);
return;
}
qCDebug(dcZigbeeNetwork()) << "Permit join request finished successfully";
if (permitJoining) {
m_permitJoinRefreshTimer->start();
} else {
m_permitJoinRefreshTimer->stop();
}
if (m_permitJoining != permitJoining) {
m_permitJoining = permitJoining;
emit permitJoiningChanged(m_permitJoining);
}
// Set the permit joining timeout network configuration parameter
QByteArray parameterData;
QDataStream stream(&parameterData, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << duration;
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterPermitJoin, parameterData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode();
// FIXME: set an appropriate error
return;
}
qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode();
});
});
}
void ZigbeeNetworkDeconz::startNetworkInternally()
@ -370,6 +459,8 @@ void ZigbeeNetworkDeconz::startNetworkInternally()
m_controller->setFirmwareVersionString(QString("%1 - %2").arg(firmwareVersion).arg(protocolVersion));
qCDebug(dcZigbeeNetwork()) << m_controller->networkConfiguration();
ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
@ -496,17 +587,22 @@ void ZigbeeNetworkDeconz::onPollNetworkStateTimeout()
}
}
void ZigbeeNetworkDeconz::onPermitJoinRefreshTimout()
{
setPermitJoiningInternal(true);
}
void ZigbeeNetworkDeconz::onAspDataConfirmReceived(const DeconzApsDataConfirm &confirm)
{
qCDebug(dcZigbeeNetwork()) << confirm;
ZigbeeNetworkReply *reply = m_pendingReplies.take(confirm.requestId);
ZigbeeNetworkReply *reply = m_pendingReplies.value(confirm.requestId);
if (!reply) {
qCWarning(dcZigbeeNetwork()) << "Received confirmation but could not find any reply. Ignoring the confirmation";
return;
}
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorNoError, static_cast<Zigbee::ZigbeeStatus>(confirm.zigbeeStatusCode));
setReplyResponseError(reply, static_cast<Zigbee::ZigbeeStatus>(confirm.zigbeeStatusCode));
}
void ZigbeeNetworkDeconz::onAspDataIndicationReceived(const DeconzApsDataIndication &indication)
@ -519,7 +615,7 @@ void ZigbeeNetworkDeconz::onAspDataIndicationReceived(const DeconzApsDataIndicat
return;
}
// Find reply finish it
// FIXME: handle it
qCDebug(dcZigbeeNetwork()) << "Unhandled indication" << indication;
}
@ -527,9 +623,18 @@ void ZigbeeNetworkDeconz::onAspDataIndicationReceived(const DeconzApsDataIndicat
void ZigbeeNetworkDeconz::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities)
{
qCDebug(dcZigbeeNetwork()) << "Device announced" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << ieeeAddress.toString() << ZigbeeUtils::convertByteToHexString(macCapabilities);
// Create node and initialize it
if (hasNode(ieeeAddress)) {
qCWarning(dcZigbeeNetwork()) << "Already known device announced. FIXME: Ignoring announcement" << ieeeAddress.toString();
return;
}
ZigbeeNodeDeconz *node = static_cast<ZigbeeNodeDeconz *>(createNode(this));
node->setExtendedAddress(ieeeAddress);
node->setShortAddress(shortAddress);
node->setMacCapabilitiesFlag(macCapabilities);
addUnitializedNode(node);
node->startInitialization();
}
void ZigbeeNetworkDeconz::startNetwork()

View File

@ -55,6 +55,8 @@ public:
ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) override;
ZigbeeNetworkReply *setPermitJoin(quint16 shortAddress, quint8 duration);
quint8 generateSequenceNumber();
private:
@ -63,6 +65,8 @@ private:
CreateNetworkState m_createState = CreateNetworkStateIdle;
bool m_createNewNetwork = false;
QTimer *m_permitJoinRefreshTimer = nullptr;
QHash<quint8, ZigbeeNetworkReply *> m_pendingReplies;
quint8 m_sequenceNumber = 0;
@ -83,6 +87,7 @@ protected:
private slots:
void onControllerAvailableChanged(bool available);
void onPollNetworkStateTimeout();
void onPermitJoinRefreshTimout();
void onAspDataConfirmReceived(const DeconzApsDataConfirm &confirm);
void onAspDataIndicationReceived(const DeconzApsDataIndication &indication);

View File

@ -25,6 +25,7 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeeutils.h"
#include "zigbeenodedeconz.h"
#include "zigbeedeviceprofile.h"
#include "zigbeenetworkdeconz.h"
@ -39,21 +40,8 @@ ZigbeeNodeDeconz::ZigbeeNodeDeconz(ZigbeeNetworkDeconz *network, QObject *parent
}
void ZigbeeNodeDeconz::leaveNetworkRequest(bool rejoin, bool removeChildren)
ZigbeeNetworkReply *ZigbeeNodeDeconz::requestNodeDescriptor()
{
Q_UNUSED(rejoin)
Q_UNUSED(removeChildren)
}
void ZigbeeNodeDeconz::setClusterAttributeReport(const ZigbeeClusterAttributeReport &report)
{
Q_UNUSED(report)
}
void ZigbeeNodeDeconz::startInitialization()
{
setState(StateInitializing);
// Get the node descriptor
ZigbeeNetworkRequest request;
request.setRequestId(m_network->generateSequenceNumber());
@ -71,20 +59,97 @@ void ZigbeeNodeDeconz::startInitialization()
stream << request.requestId() << request.destinationShortAddress();
request.setAsdu(asdu);
ZigbeeNetworkReply *reply = m_network->sendRequest(request);
connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){
// TODO: check reply error
// We expect an indication with the response and the confirmation
request.setExpectIndication(true);
return m_network->sendRequest(request);
}
ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData());
qCDebug(dcZigbeeNode()) << "Node descriptor request finished" << adpu;
setNodeDescriptorRawData(reply->responseData());
ZigbeeNetworkReply *ZigbeeNodeDeconz::requestPowerDescriptor()
{
// Get the power descriptor
ZigbeeNetworkRequest request;
request.setRequestId(m_network->generateSequenceNumber());
request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress);
request.setDestinationShortAddress(shortAddress());
request.setDestinationEndpoint(0); // ZDO
request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP
request.setClusterId(ZigbeeDeviceProfile::PowerDescriptorRequest);
request.setSourceEndpoint(0); // ZDO
QDataStream stream(adpu.payload);
stream.setByteOrder(QDataStream::LittleEndian);
// Build ASDU
QByteArray asdu;
QDataStream stream(&asdu, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << request.requestId() << request.destinationShortAddress();
request.setAsdu(asdu);
// We expect an indication with the response and the confirmation
request.setExpectIndication(true);
return m_network->sendRequest(request);
}
ZigbeeNetworkReply *ZigbeeNodeDeconz::requestActiveEndpoints()
{
// Get the power descriptor
ZigbeeNetworkRequest request;
request.setRequestId(m_network->generateSequenceNumber());
request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress);
request.setDestinationShortAddress(shortAddress());
request.setDestinationEndpoint(0); // ZDO
request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP
request.setClusterId(ZigbeeDeviceProfile::ActiveEndpointsRequest);
request.setSourceEndpoint(0); // ZDO
});
// Build ASDU
QByteArray asdu;
QDataStream stream(&asdu, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << request.requestId() << request.destinationShortAddress();
request.setAsdu(asdu);
// We expect an indication with the response and the confirmation
request.setExpectIndication(true);
return m_network->sendRequest(request);
}
ZigbeeNetworkReply *ZigbeeNodeDeconz::requestSimpleDescriptor(quint8 endpoint)
{
// Get the power descriptor
ZigbeeNetworkRequest request;
request.setRequestId(m_network->generateSequenceNumber());
request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress);
request.setDestinationShortAddress(shortAddress());
request.setDestinationEndpoint(0); // ZDO
request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP
request.setClusterId(ZigbeeDeviceProfile::SimpleDescriptorRequest);
request.setSourceEndpoint(0); // ZDO
// Build ASDU
QByteArray asdu;
QDataStream stream(&asdu, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << request.requestId() << request.destinationShortAddress() << endpoint;
request.setAsdu(asdu);
// We expect an indication with the response and the confirmation
request.setExpectIndication(true);
return m_network->sendRequest(request);
}
void ZigbeeNodeDeconz::leaveNetworkRequest(bool rejoin, bool removeChildren)
{
Q_UNUSED(rejoin)
Q_UNUSED(removeChildren)
}
void ZigbeeNodeDeconz::setClusterAttributeReport(const ZigbeeClusterAttributeReport &report)
{
Q_UNUSED(report)
}
void ZigbeeNodeDeconz::startInitialization()
{
setState(StateInitializing);
/* Node initialisation steps (sequentially)
* - Node descriptor
@ -97,6 +162,187 @@ void ZigbeeNodeDeconz::startInitialization()
*/
ZigbeeNetworkReply *reply = requestNodeDescriptor();
connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){
// TODO: check reply error
ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData());
qCDebug(dcZigbeeNode()) << "Node descriptor request finished" << adpu;
QDataStream stream(adpu.payload);
stream.setByteOrder(QDataStream::LittleEndian);
quint8 typeDescriptorFlag = 0; quint8 frequencyFlag = 0; quint8 macCapabilities = 0;
quint16 serverMask = 0;
quint8 descriptorCapabilities = 0;
stream >> typeDescriptorFlag >> frequencyFlag >> macCapabilities >> m_manufacturerCode >> m_maximumBufferSize;
stream >> m_maximumRxSize >> serverMask >> m_maximumTxSize >> descriptorCapabilities;
// 0-2 Bit = logical type, 0 = coordinator, 1 = router, 2 = end device
if (!ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) {
m_nodeType = NodeTypeCoordinator;
} else if (!ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) {
m_nodeType = NodeTypeRouter;
} else if (ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 0) && !ZigbeeUtils::checkBitUint8(typeDescriptorFlag, 1)) {
m_nodeType = NodeTypeEndDevice;
}
m_complexDescriptorAvailable = (typeDescriptorFlag >> 3) & 0x0001;
m_userDescriptorAvailable = (typeDescriptorFlag >> 4) & 0x0001;
// Frequency band, 5 bits
if (ZigbeeUtils::checkBitUint8(frequencyFlag, 3)) {
m_frequencyBand = FrequencyBand868Mhz;
} else if (ZigbeeUtils::checkBitUint8(frequencyFlag, 5)) {
m_frequencyBand = FrequencyBand902Mhz;
} else if (ZigbeeUtils::checkBitUint8(frequencyFlag, 6)) {
m_frequencyBand = FrequencyBand2400Mhz;
}
setMacCapabilitiesFlag(macCapabilities);
setServerMask(serverMask);
setDescriptorFlag(descriptorCapabilities);
qCDebug(dcZigbeeNode()) << "Node descriptor:" << ZigbeeUtils::convertUint16ToHexString(shortAddress()) << extendedAddress().toString();
qCDebug(dcZigbeeNode()) << " Node type:" << nodeType();
qCDebug(dcZigbeeNode()) << " Complex desciptor available:" << complexDescriptorAvailable();
qCDebug(dcZigbeeNode()) << " User desciptor available:" << userDescriptorAvailable();
qCDebug(dcZigbeeNode()) << " Frequency band:" << frequencyBand();
qCDebug(dcZigbeeNode()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(m_manufacturerCode);
qCDebug(dcZigbeeNode()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximumRxSize) << "(" << m_maximumRxSize << ")";
qCDebug(dcZigbeeNode()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximumTxSize) << "(" << m_maximumTxSize << ")";
qCDebug(dcZigbeeNode()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(m_maximumBufferSize) << "(" << m_maximumBufferSize << ")";
qCDebug(dcZigbeeNode()) << " Server mask:" << ZigbeeUtils::convertUint16ToHexString(serverMask);
qCDebug(dcZigbeeNode()) << " Primary Trust center:" << isPrimaryTrustCenter();
qCDebug(dcZigbeeNode()) << " Backup Trust center:" << isBackupTrustCenter();
qCDebug(dcZigbeeNode()) << " Primary Binding cache:" << isPrimaryBindingCache();
qCDebug(dcZigbeeNode()) << " Backup Binding cache:" << isBackupBindingCache();
qCDebug(dcZigbeeNode()) << " Primary Discovery cache:" << isPrimaryDiscoveryCache();
qCDebug(dcZigbeeNode()) << " Backup Discovery cache:" << isBackupDiscoveryCache();
qCDebug(dcZigbeeNode()) << " Network Manager:" << isNetworkManager();
qCDebug(dcZigbeeNode()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorCapabilities);
qCDebug(dcZigbeeNode()) << " Extended active endpoint list available:" << extendedActiveEndpointListAvailable();
qCDebug(dcZigbeeNode()) << " Extended simple descriptor list available:" << extendedSimpleDescriptorListAvailable();
qCDebug(dcZigbeeNode()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macCapabilities);
qCDebug(dcZigbeeNode()) << " Alternate PAN coordinator:" << alternatePanCoordinator();
qCDebug(dcZigbeeNode()) << " Device type:" << deviceType();
qCDebug(dcZigbeeNode()) << " Power source flag main power:" << powerSourceFlagMainPower();
qCDebug(dcZigbeeNode()) << " Receiver on when idle:" << receiverOnWhenIdle();
qCDebug(dcZigbeeNode()) << " Security capability:" << securityCapability();
qCDebug(dcZigbeeNode()) << " Allocate address:" << allocateAddress();
// Power descriptor
ZigbeeNetworkReply *reply = requestPowerDescriptor();
connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){
// TODO: check reply error
ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData());
qCDebug(dcZigbeeNode()) << "Power descriptor request finished" << this << adpu;
QDataStream stream(adpu.payload);
stream.setByteOrder(QDataStream::LittleEndian);
quint16 powerDescriptorFlag = 0;
stream >> powerDescriptorFlag;
setPowerDescriptorFlag(powerDescriptorFlag);
ZigbeeNetworkReply *reply = requestActiveEndpoints();
connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){
// TODO: check reply error
ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData());
qCDebug(dcZigbeeNode()) << "Active endpoints request finished" << this << adpu;
QDataStream stream(adpu.payload);
stream.setByteOrder(QDataStream::LittleEndian);
quint8 endpointCount = 0;
m_uninitializedEndpoints.clear();
stream >> endpointCount;
for (int i = 0; i < endpointCount; i++) {
quint8 endpoint = 0;
stream >> endpoint;
m_uninitializedEndpoints.append(endpoint);
}
qCDebug(dcZigbeeNode()) << "Endpoints" << endpointCount;
for (int i = 0; i < m_uninitializedEndpoints.count(); i++) {
qCDebug(dcZigbeeNode()) << " -" << ZigbeeUtils::convertByteToHexString(m_uninitializedEndpoints.at(i));
}
// Read simple descriptor for each endpoint
if (m_uninitializedEndpoints.isEmpty()) {
setState(StateInitialized);
}
for (int i = 0; i < m_uninitializedEndpoints.count(); i++) {
quint8 endpointId = m_uninitializedEndpoints.at(i);
qCDebug(dcZigbeeNode()) << "Read simple descriptor of endpoint" << ZigbeeUtils::convertByteToHexString(endpointId);
ZigbeeNetworkReply *reply = requestSimpleDescriptor(endpointId);
connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply, endpointId](){
// TODO: check reply error
ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData());
qCDebug(dcZigbeeNode()) << "Simple descriptor request finished" << this << endpointId << adpu;
QDataStream stream(adpu.payload);
stream.setByteOrder(QDataStream::LittleEndian);
quint8 length = 0;
quint8 endpoint = 0;
quint16 profileId = 0;
quint16 deviceId = 0;
quint8 deviceVersion = 0;
quint8 inputClusterCount = 0;
quint8 outputClusterCount = 0;
QList<quint16> inputClusters;
QList<quint16> outputClusters;
stream >> length >> endpoint >> profileId >> deviceId >> deviceVersion >> inputClusterCount;
qCDebug(dcZigbeeNode()) << "Node endpoint simple descriptor:";
qCDebug(dcZigbeeNode()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length);
qCDebug(dcZigbeeNode()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endpoint);
qCDebug(dcZigbeeNode()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
if (profileId == Zigbee::ZigbeeProfileLightLink) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::LightLinkDevice>(deviceId);
} else if (profileId == Zigbee::ZigbeeProfileHomeAutomation) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::HomeAutomationDevice>(deviceId);
} else if (profileId == Zigbee::ZigbeeProfileGreenPower) {
qCDebug(dcZigbeeNode()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::GreenPowerDevice>(deviceId);
}
qCDebug(dcZigbeeNode()) << " Device version:" << ZigbeeUtils::convertByteToHexString(deviceVersion);
qCDebug(dcZigbeeNode()) << " Input clusters: (" << inputClusterCount << ")";
for (int i = 0; i < inputClusterCount; i++) {
quint16 clusterId = 0;
stream >> clusterId;
inputClusters.append(clusterId);
qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
}
stream >> outputClusterCount;
qCDebug(dcZigbeeNode()) << " Output clusters: (" << outputClusterCount << ")";
for (int i = 0; i < outputClusterCount; i++) {
quint16 clusterId = 0;
stream >> clusterId;
outputClusters.append(clusterId);
qCDebug(dcZigbeeNode()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
}
m_uninitializedEndpoints.removeAll(endpointId);
// Create endpoint
if (m_uninitializedEndpoints.isEmpty()) {
setState(StateInitialized);
}
});
}
});
});
});
}
ZigbeeNodeEndpoint *ZigbeeNodeDeconz::createNodeEndpoint(quint8 endpointId, QObject *parent)

View File

@ -44,11 +44,19 @@ class ZigbeeNodeDeconz : public ZigbeeNode
public:
explicit ZigbeeNodeDeconz(ZigbeeNetworkDeconz *network, QObject *parent = nullptr);
ZigbeeNetworkReply *requestNodeDescriptor();
ZigbeeNetworkReply *requestPowerDescriptor();
ZigbeeNetworkReply *requestActiveEndpoints();
ZigbeeNetworkReply *requestSimpleDescriptor(quint8 endpoint);
void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) override;
private:
ZigbeeNetworkDeconz *m_network = nullptr;
QList<quint8> m_uninitializedEndpoints;
QList<quint16> m_uninitalizedBasicClusterAttributes;
void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override;
protected:

View File

@ -535,6 +535,13 @@ public:
};
Q_ENUM(DataType)
enum BroadcastAddress {
BroadcastAddressAllNodes = 0xffff,
BroadcastAddressAllNonSleepingNodes = 0xfffd,
BroadcastAddressAllRouters = 0xfffc
};
Q_ENUM(BroadcastAddress)
enum DestinationAddressMode {
DestinationAddressModeGroup = 0x01,
DestinationAddressModeShortAddress = 0x02,

View File

@ -295,8 +295,21 @@ void ZigbeeNetwork::loadNetwork()
ZigbeeNode *node = createNode(this);
node->setExtendedAddress(ZigbeeAddress(ieeeAddressString));
node->setShortAddress(static_cast<quint16>(settings.value("nwkAddress", 0).toUInt()));
// 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->setNodeDescriptorRawData(settings.value("nodeDescriptorRawData", QByteArray()).toByteArray());
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()));
int endpointsCount = settings.beginReadArray("endpoints");
@ -377,11 +390,21 @@ void ZigbeeNetwork::saveNode(ZigbeeNode *node)
// Save this node
settings.beginGroup(node->extendedAddress().toString());
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("nodeDescriptorRawData", node->m_nodeDescriptorRawData);
// Power descriptor
settings.setValue("powerDescriptorFlag", node->m_powerDescriptorFlag);
settings.beginWriteArray("endpoints");
@ -505,12 +528,33 @@ ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest
void ZigbeeNetwork::setReplyResponseData(ZigbeeNetworkReply *reply, const QByteArray &responseData)
{
reply->m_responseData = responseData;
if (reply->isComplete()) {
if (reply->m_zigbeeStatus == Zigbee::ZigbeeStatusSuccess) {
finishNetworkReply(reply);
} else {
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeStatusError);
}
}
}
void ZigbeeNetwork::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error, Zigbee::ZigbeeStatus zigbeeStatus)
void ZigbeeNetwork::setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeStatus zigbeeStatus)
{
reply->m_error = error;
reply->m_zigbeeStatus = zigbeeStatus;
reply->m_zigbeeConfirmArrived = true;
if (reply->isComplete()) {
if (reply->m_zigbeeStatus == Zigbee::ZigbeeStatusSuccess) {
finishNetworkReply(reply);
} else {
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeStatusError);
}
}
}
void ZigbeeNetwork::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error)
{
qCDebug(dcZigbeeNetwork()) << "Reply finished" << error << reply->request();
reply->m_error = error;
reply->finished();
}

View File

@ -157,7 +157,8 @@ protected:
// Network reply methods
ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest());
void setReplyResponseData(ZigbeeNetworkReply *reply, const QByteArray &responseData);
void finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error = ZigbeeNetworkReply::ErrorNoError, Zigbee::ZigbeeStatus zigbeeStatus = Zigbee::ZigbeeStatusSuccess);
void setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeStatus zigbeeStatus = Zigbee::ZigbeeStatusSuccess);
void finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error = ZigbeeNetworkReply::ErrorNoError);
signals:
void settingsFileNameChanged(const QString &settingsFileName);

View File

@ -47,6 +47,26 @@ QByteArray ZigbeeNetworkReply::responseData() const
return m_responseData;
}
bool ZigbeeNetworkReply::isComplete() const
{
// If we expect indication and confirmation
if (m_request.expectConfirmation() && m_request.expectIndication()) {
if (m_zigbeeConfirmArrived && !m_responseData.isEmpty()) {
return true;
} else {
return false;
}
}
// If we expect only a confirmation
if (m_request.expectConfirmation() && !m_request.expectIndication()) {
return m_zigbeeConfirmArrived;
}
// If we don't expect any response...
return true;
}
ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent) :
QObject(parent),
m_request(request)

View File

@ -51,18 +51,20 @@ public:
};
Q_ENUM(Error)
Error error() const;
ZigbeeNetworkRequest request() const;
Zigbee::ZigbeeStatus zigbeeStatus() const;
QByteArray responseData() const;
bool isComplete() const;
private:
explicit ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr);
ZigbeeNetworkRequest m_request;
bool m_finished = false;
Error m_error = ErrorNoError;
bool m_zigbeeConfirmArrived = false;
Zigbee::ZigbeeStatus m_zigbeeStatus = Zigbee::ZigbeeStatusSuccess;
QByteArray m_responseData;

View File

@ -26,6 +26,8 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeenetworkrequest.h"
#include "zigbeedeviceprofile.h"
#include "zigbeeutils.h"
ZigbeeNetworkRequest::ZigbeeNetworkRequest()
{
@ -141,3 +143,51 @@ void ZigbeeNetworkRequest::setRadius(quint8 radius)
{
m_radius = radius;
}
bool ZigbeeNetworkRequest::expectIndication() const
{
return m_expectIndication;
}
void ZigbeeNetworkRequest::setExpectIndication(bool expectIndication)
{
m_expectIndication = expectIndication;
}
bool ZigbeeNetworkRequest::expectConfirmation() const
{
return m_expectConfirmation;
}
void ZigbeeNetworkRequest::setExpectConfirmation(bool expectConfirmation)
{
m_expectConfirmation = expectConfirmation;
}
QDebug operator<<(QDebug debug, const ZigbeeNetworkRequest &request)
{
debug.nospace() << "Request(ID:" << request.requestId() << ", ";
debug.nospace() << static_cast<Zigbee::ZigbeeProfile>(request.profileId()) << ", ";
if (request.profileId() == Zigbee::ZigbeeProfileDevice) {
debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(request.clusterId()) << ", ";
} else {
debug.nospace() << static_cast<Zigbee::ClusterId>(request.clusterId()) << ", ";
}
if (request.destinationAddressMode() == Zigbee::DestinationAddressModeGroup)
debug.nospace() << "Group address:" << ZigbeeUtils::convertUint16ToHexString(request.destinationShortAddress()) << ", ";
if (request.destinationAddressMode() == Zigbee::DestinationAddressModeShortAddress)
debug.nospace() << "NWK address:" << ZigbeeUtils::convertUint16ToHexString(request.destinationShortAddress()) << ", ";
if (request.destinationAddressMode() == Zigbee::DestinationAddressModeIeeeAddress)
debug.nospace() << "IEEE address:" << ZigbeeAddress(request.destinationIeeeAddress()).toString() << ", ";
debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(request.destinationEndpoint()) << ", ";
debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(request.sourceEndpoint()) << ", ";
debug.nospace() << "Radius:" << request.radius() << ", ";
debug.nospace() << request.txOptions() << ", ";
debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(request.asdu()) << ", ";
debug.nospace() << ")";
return debug.space();
}

View File

@ -28,6 +28,7 @@
#ifndef ZIGBEENETWORKREQUEST_H
#define ZIGBEENETWORKREQUEST_H
#include <QDebug>
#include <QObject>
#include "zigbee.h"
@ -71,6 +72,13 @@ public:
quint8 radius() const;
void setRadius(quint8 radius);
// Response expectations
bool expectIndication() const;
void setExpectIndication(bool expectIndication);
bool expectConfirmation() const;
void setExpectConfirmation(bool expectConfirmation);
private:
quint8 m_requestId = 0;
Zigbee::DestinationAddressMode m_destinationAddressMode = Zigbee::DestinationAddressModeShortAddress;
@ -83,6 +91,12 @@ private:
QByteArray m_asdu;
Zigbee::ZigbeeTxOptions m_txOptions = Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission);
quint8 m_radius = 0;
bool m_expectIndication = false;
bool m_expectConfirmation = true;
};
QDebug operator<<(QDebug debug, const ZigbeeNetworkRequest &request);
#endif // ZIGBEENETWORKREQUEST_H

View File

@ -307,9 +307,9 @@ void ZigbeeNode::setNodeDescriptorRawData(const QByteArray nodeDescriptorRawData
m_userDescriptorAvailable = (bitField >> 4) & 0x0001;
qCDebug(dcZigbeeNode()) << "Node descriptor:";
qCDebug(dcZigbeeNode()) << " Node type:" << nodeType();
qCDebug(dcZigbeeNode()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbeeNode()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
qCDebug(dcZigbeeNode()) << " Node type:" << nodeType();
qCDebug(dcZigbeeNode()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNode()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode);
qCDebug(dcZigbeeNode()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(maximumRxSize());