Fix indication matching and rely handling in network instance
This commit is contained in:
parent
118cdedc6a
commit
882023198a
@ -64,7 +64,10 @@ public:
|
||||
CommandVersion = 0x0D,
|
||||
CommandApsDataRequest = 0x12,
|
||||
CommandApsDataConfirm = 0x04,
|
||||
CommandApsDataIndication = 0x17
|
||||
CommandApsDataIndication = 0x17,
|
||||
CommandGreenPower = 0x19,
|
||||
CommandMacPoll = 0x1C,
|
||||
CommandSimplifiedBeacon = 0x1F
|
||||
};
|
||||
Q_ENUM(Command)
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(¶meterData, 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()
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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());
|
||||
|
||||
Reference in New Issue
Block a user