Add read binding tables for testing
parent
6f04230028
commit
66637cc389
|
|
@ -29,6 +29,7 @@
|
||||||
#include "zigbeenetworkreply.h"
|
#include "zigbeenetworkreply.h"
|
||||||
#include "loggingcategory.h"
|
#include "loggingcategory.h"
|
||||||
#include "zigbeenetwork.h"
|
#include "zigbeenetwork.h"
|
||||||
|
#include "zigbeeutils.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
|
||||||
|
|
@ -124,8 +125,17 @@ void ZigbeeClusterOnOff::processDataIndication(ZigbeeClusterLibrary::Frame frame
|
||||||
case CommandToggle:
|
case CommandToggle:
|
||||||
emit commandSent(CommandToggle);
|
emit commandSent(CommandToggle);
|
||||||
break;
|
break;
|
||||||
|
case CommandOnWithTimedOff: {
|
||||||
|
QByteArray payload = frame.payload;
|
||||||
|
QDataStream payloadStream(&payload, QIODevice::ReadOnly);
|
||||||
|
payloadStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
quint8 acceptOnlyWhenOnInt = 0; quint16 onTime; quint16 offTime;
|
||||||
|
payloadStream >> acceptOnlyWhenOnInt >> onTime >> offTime;
|
||||||
|
emit commandOnWithTimedOffSent(static_cast<bool>(acceptOnlyWhenOnInt), onTime, offTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
qCWarning(dcZigbeeCluster()) << "Unhandled command sent from" << m_node << m_endpoint << this << command;
|
qCWarning(dcZigbeeCluster()) << "Unhandled command sent from" << m_node << m_endpoint << this << command << ZigbeeUtils::convertByteArrayToHexString(frame.payload);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,8 @@ signals:
|
||||||
|
|
||||||
// Client cluster signals
|
// Client cluster signals
|
||||||
void commandSent(Command command);
|
void commandSent(Command command);
|
||||||
|
// On and off time is in 1/10 seconds
|
||||||
|
void commandOnWithTimedOffSent(bool acceptOnlyWhenOn, quint16 onTime, quint16 offTime);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZIGBEECLUSTERONOFF_H
|
#endif // ZIGBEECLUSTERONOFF_H
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
#include "zigbeedeviceobject.h"
|
#include "zigbeedeviceobject.h"
|
||||||
#include "zigbeenetwork.h"
|
#include "zigbeenetwork.h"
|
||||||
#include "loggingcategory.h"
|
#include "loggingcategory.h"
|
||||||
|
#include "zigbeedeviceprofile.h"
|
||||||
|
#include "zigbeeutils.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
@ -41,7 +43,7 @@ ZigbeeDeviceObject::ZigbeeDeviceObject(ZigbeeNetwork *network, ZigbeeNode *node,
|
||||||
}
|
}
|
||||||
|
|
||||||
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestNodeDescriptor()
|
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestNodeDescriptor()
|
||||||
{
|
{
|
||||||
qCDebug(dcZigbeeDeviceObject()) << "Request node descriptor from" << m_node;
|
qCDebug(dcZigbeeDeviceObject()) << "Request node descriptor from" << m_node;
|
||||||
|
|
||||||
// Build APS request
|
// Build APS request
|
||||||
|
|
@ -396,7 +398,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLqi(quint8 startIndex)
|
||||||
QByteArray asdu;
|
QByteArray asdu;
|
||||||
QDataStream stream(&asdu, QIODevice::WriteOnly);
|
QDataStream stream(&asdu, QIODevice::WriteOnly);
|
||||||
stream.setByteOrder(QDataStream::LittleEndian);
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
stream << startIndex;
|
stream << transactionSequenceNumber << startIndex;
|
||||||
|
|
||||||
// Set the ZDO frame as APS request payload
|
// Set the ZDO frame as APS request payload
|
||||||
request.setAsdu(asdu);
|
request.setAsdu(asdu);
|
||||||
|
|
@ -431,6 +433,53 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLqi(quint8 startIndex)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
finishZdoReply(zdoReply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We received the confirmation but not yet the indication
|
||||||
|
});
|
||||||
|
|
||||||
|
return zdoReply;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtBind(quint8 startIndex)
|
||||||
|
{
|
||||||
|
qCDebug(dcZigbeeDeviceObject()) << "Request management bind table from" << m_node << "start index" << startIndex;
|
||||||
|
|
||||||
|
// Build APS request
|
||||||
|
ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::MgmtBindRequest);
|
||||||
|
|
||||||
|
// Generate a new transaction sequence number for this device object
|
||||||
|
quint8 transactionSequenceNumber = m_transactionSequenceNumber++;
|
||||||
|
|
||||||
|
QByteArray asdu;
|
||||||
|
QDataStream stream(&asdu, QIODevice::WriteOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
stream << transactionSequenceNumber << startIndex;
|
||||||
|
|
||||||
|
// Set the ZDO frame as APS request payload
|
||||||
|
request.setAsdu(asdu);
|
||||||
|
|
||||||
|
// Create the device object reply and wait for the response indication
|
||||||
|
ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber);
|
||||||
|
|
||||||
|
// Send the request, on finished read the confirm information
|
||||||
|
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
|
||||||
|
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){
|
||||||
|
if (!verifyNetworkError(zdoReply, networkReply)) {
|
||||||
|
qCWarning(dcZigbeeDeviceObject()) << "Failed to send request"
|
||||||
|
<< static_cast<ZigbeeDeviceProfile::ZdoCommand>(networkReply->request().clusterId())
|
||||||
|
<< m_node << networkReply->error()
|
||||||
|
<< networkReply->zigbeeApsStatus();
|
||||||
|
finishZdoReply(zdoReply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request was successfully sent to the device
|
||||||
|
// Now check if the expected indication response received already
|
||||||
|
if (zdoReply->isComplete()) {
|
||||||
|
qCDebug(dcZigbeeDeviceObject()) << "Successfully received response for" << static_cast<ZigbeeDeviceProfile::ZdoCommand>(networkReply->request().clusterId());
|
||||||
|
|
||||||
finishZdoReply(zdoReply);
|
finishZdoReply(zdoReply);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -536,5 +585,5 @@ void ZigbeeDeviceObject::processApsDataIndication(const Zigbee::ApsdeDataIndicat
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCWarning(dcZigbeeDeviceObject()) << "Unhandled ZDO indication" << m_node << asdu;
|
qCWarning(dcZigbeeDeviceObject()) << "Unhandled ZDO indication" << m_node << indication << asdu;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ public:
|
||||||
// Management request
|
// Management request
|
||||||
ZigbeeDeviceObjectReply *requestMgmtLeaveNetwork(bool rejoin = false, bool removeChildren = false);
|
ZigbeeDeviceObjectReply *requestMgmtLeaveNetwork(bool rejoin = false, bool removeChildren = false);
|
||||||
ZigbeeDeviceObjectReply *requestMgmtLqi(quint8 startIndex = 0x00);
|
ZigbeeDeviceObjectReply *requestMgmtLqi(quint8 startIndex = 0x00);
|
||||||
|
ZigbeeDeviceObjectReply *requestMgmtBind(quint8 startIndex = 0x00);
|
||||||
|
|
||||||
// TODO: write all requests
|
// TODO: write all requests
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::Adpu &deviceAdpu)
|
||||||
debug.nospace() << "DeviceAdpu(SQN: " << deviceAdpu.transactionSequenceNumber << ", ";
|
debug.nospace() << "DeviceAdpu(SQN: " << deviceAdpu.transactionSequenceNumber << ", ";
|
||||||
debug.nospace() << deviceAdpu.status << ", ";
|
debug.nospace() << deviceAdpu.status << ", ";
|
||||||
debug.nospace() << ZigbeeUtils::convertUint16ToHexString(deviceAdpu.addressOfInterest) << ", ";
|
debug.nospace() << ZigbeeUtils::convertUint16ToHexString(deviceAdpu.addressOfInterest) << ", ";
|
||||||
debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")";
|
debug.nospace() << "Payload: " << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")";
|
||||||
return debug.space();
|
return debug.space();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,3 +262,22 @@ QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::PowerDescriptor &powe
|
||||||
debug.nospace() << " Power level: " << powerDescriptor.powerLevel;
|
debug.nospace() << " Power level: " << powerDescriptor.powerLevel;
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::BindingTableListRecord &bindingTableListRecord)
|
||||||
|
{
|
||||||
|
debug.nospace() << "BindingTableListRecord(" << bindingTableListRecord.sourceAddress.toString() << ", ";
|
||||||
|
debug.nospace() << "source endpoint: " << bindingTableListRecord.sourceEndpoint << ", ";
|
||||||
|
debug.nospace() << "cluster: " << static_cast<ZigbeeClusterLibrary::ClusterId>(bindingTableListRecord.clusterId) << " --> ";
|
||||||
|
switch (bindingTableListRecord.destinationAddressMode) {
|
||||||
|
case Zigbee::DestinationAddressModeGroup:
|
||||||
|
debug.nospace() << "destination address (group): " << ZigbeeUtils::convertUint16ToHexString(bindingTableListRecord.destinationAddressShort) << ") ";
|
||||||
|
break;
|
||||||
|
case Zigbee::DestinationAddressModeIeeeAddress:
|
||||||
|
debug.nospace() << "destination address (unicast): " << bindingTableListRecord.destinationAddress.toString() << ", ";
|
||||||
|
debug.nospace() << "destination endpoint: " << bindingTableListRecord.destinationEndpoint << ") ";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "zigbee.h"
|
#include "zigbee.h"
|
||||||
|
#include "zigbeeaddress.h"
|
||||||
|
|
||||||
class ZigbeeDeviceProfile
|
class ZigbeeDeviceProfile
|
||||||
{
|
{
|
||||||
|
|
@ -276,6 +277,17 @@ public:
|
||||||
PowerLevel powerLevel = PowerLevelFull;
|
PowerLevel powerLevel = PowerLevelFull;
|
||||||
} PowerDescriptor;
|
} PowerDescriptor;
|
||||||
|
|
||||||
|
typedef struct BindingTableListRecord {
|
||||||
|
ZigbeeAddress sourceAddress;
|
||||||
|
quint8 sourceEndpoint;
|
||||||
|
quint16 clusterId;
|
||||||
|
Zigbee::DestinationAddressMode destinationAddressMode; // Note: group or unicast
|
||||||
|
quint16 destinationAddressShort; // Only for destination address 0x01
|
||||||
|
ZigbeeAddress destinationAddress; // Only for destination address 0x03
|
||||||
|
quint8 destinationEndpoint; // Only for destination address 0x03
|
||||||
|
} BindingTableListRecord;
|
||||||
|
|
||||||
|
|
||||||
static NodeDescriptor parseNodeDescriptor(const QByteArray &payload);
|
static NodeDescriptor parseNodeDescriptor(const QByteArray &payload);
|
||||||
static MacCapabilities parseMacCapabilities(quint8 macCapabilitiesFlag);
|
static MacCapabilities parseMacCapabilities(quint8 macCapabilitiesFlag);
|
||||||
static ServerMask parseServerMask(quint16 serverMaskFlag);
|
static ServerMask parseServerMask(quint16 serverMaskFlag);
|
||||||
|
|
@ -290,5 +302,6 @@ QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::MacCapabilities &macC
|
||||||
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::ServerMask &serverMask);
|
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::ServerMask &serverMask);
|
||||||
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::DescriptorCapabilities &descriptorCapabilities);
|
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::DescriptorCapabilities &descriptorCapabilities);
|
||||||
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::PowerDescriptor &powerDescriptor);
|
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::PowerDescriptor &powerDescriptor);
|
||||||
|
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::BindingTableListRecord &bindingTableListRecord);
|
||||||
|
|
||||||
#endif // ZIGBEEDEVICEPROFILE_H
|
#endif // ZIGBEEDEVICEPROFILE_H
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,58 @@ void ZigbeeNode::startInitialization()
|
||||||
initNodeDescriptor();
|
initNodeDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZigbeeNode::readBindingTableEntries()
|
||||||
|
{
|
||||||
|
ZigbeeDeviceObjectReply * reply = deviceObject()->requestMgmtBind();
|
||||||
|
connect(reply, &ZigbeeDeviceObjectReply::finished, this, [=](){
|
||||||
|
if (reply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||||
|
qCWarning(dcZigbeeDeviceObject()) << "Failed to read binding table" << reply->error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request finished, but we received a ZDP error.
|
||||||
|
if (reply->responseAdpu().status != ZigbeeDeviceProfile::StatusSuccess) {
|
||||||
|
qCWarning(dcZigbeeNode()) << this << "failed to read node descriptor" << reply->responseAdpu().status;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeDeviceObject()) << "Bind table payload" << ZigbeeUtils::convertByteArrayToHexString(reply->responseData());
|
||||||
|
QByteArray response = reply->responseData();
|
||||||
|
QDataStream stream(&response, QIODevice::ReadOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
quint8 sqn; quint8 statusInt; quint8 entriesCount; quint8 startIndex; quint8 bindingTableListCount;
|
||||||
|
stream >> sqn >> statusInt >> entriesCount >> startIndex >> bindingTableListCount;
|
||||||
|
ZigbeeDeviceProfile::Status status = static_cast<ZigbeeDeviceProfile::Status>(statusInt);
|
||||||
|
qCDebug(dcZigbeeDeviceObject()) << "SQN:" << sqn << status << "entries:" << entriesCount << "index:" << startIndex << "list count:" << bindingTableListCount;
|
||||||
|
|
||||||
|
QList<ZigbeeDeviceProfile::BindingTableListRecord> bindingTableRecords;
|
||||||
|
for (int i = 0; i < bindingTableListCount; i++) {
|
||||||
|
quint64 sourceAddress; quint8 addressMode;
|
||||||
|
ZigbeeDeviceProfile::BindingTableListRecord record;
|
||||||
|
stream >> sourceAddress;
|
||||||
|
record.sourceAddress = ZigbeeAddress(sourceAddress);
|
||||||
|
|
||||||
|
stream >> record.sourceEndpoint >> record.clusterId >> addressMode;
|
||||||
|
record.destinationAddressMode = static_cast<Zigbee::DestinationAddressMode>(addressMode);
|
||||||
|
|
||||||
|
if (addressMode == Zigbee::DestinationAddressModeGroup) {
|
||||||
|
stream >> record.destinationAddressShort;
|
||||||
|
} else if (addressMode == Zigbee::DestinationAddressModeIeeeAddress) {
|
||||||
|
quint64 destinationAddressIeee;
|
||||||
|
stream >> destinationAddressIeee >> record.destinationEndpoint;
|
||||||
|
record.destinationAddress = ZigbeeAddress(destinationAddressIeee);
|
||||||
|
} else {
|
||||||
|
qCWarning(dcZigbeeDeviceObject()) << "Invalid destination address mode in binding table record.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
qCDebug(dcZigbeeDeviceObject()) << record;
|
||||||
|
bindingTableRecords << record;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: continue reading if there are more entries
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void ZigbeeNode::initNodeDescriptor()
|
void ZigbeeNode::initNodeDescriptor()
|
||||||
{
|
{
|
||||||
qCDebug(dcZigbeeNode()) << "Requst node descriptor from" << this;
|
qCDebug(dcZigbeeNode()) << "Requst node descriptor from" << this;
|
||||||
|
|
@ -636,6 +688,6 @@ QDebug operator<<(QDebug debug, ZigbeeNode *node)
|
||||||
{
|
{
|
||||||
debug.nospace().noquote() << "ZigbeeNode(" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress());
|
debug.nospace().noquote() << "ZigbeeNode(" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress());
|
||||||
debug.nospace().noquote() << ", " << node->extendedAddress().toString();
|
debug.nospace().noquote() << ", " << node->extendedAddress().toString();
|
||||||
debug.nospace().noquote() << ") ";
|
debug.nospace().noquote() << ")";
|
||||||
return debug;
|
return debug.space().quote();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,8 @@ public:
|
||||||
// This method starts the node initialization phase (read descriptors and endpoints)
|
// This method starts the node initialization phase (read descriptors and endpoints)
|
||||||
void startInitialization();
|
void startInitialization();
|
||||||
|
|
||||||
|
void readBindingTableEntries();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ZigbeeNode(ZigbeeNetwork *network, quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent = nullptr);
|
ZigbeeNode(ZigbeeNetwork *network, quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue