Add read binding tables for testing

pull/10/head
Simon Stürz 2020-11-23 18:26:19 +01:00
parent 6f04230028
commit 66637cc389
8 changed files with 155 additions and 9 deletions

View File

@ -29,6 +29,7 @@
#include "zigbeenetworkreply.h"
#include "loggingcategory.h"
#include "zigbeenetwork.h"
#include "zigbeeutils.h"
#include <QDataStream>
@ -124,8 +125,17 @@ void ZigbeeClusterOnOff::processDataIndication(ZigbeeClusterLibrary::Frame frame
case CommandToggle:
emit commandSent(CommandToggle);
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:
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;
}
}

View File

@ -95,7 +95,8 @@ signals:
// Client cluster signals
void commandSent(Command command);
// On and off time is in 1/10 seconds
void commandOnWithTimedOffSent(bool acceptOnlyWhenOn, quint16 onTime, quint16 offTime);
};
#endif // ZIGBEECLUSTERONOFF_H

View File

@ -28,6 +28,8 @@
#include "zigbeedeviceobject.h"
#include "zigbeenetwork.h"
#include "loggingcategory.h"
#include "zigbeedeviceprofile.h"
#include "zigbeeutils.h"
#include <QDataStream>
#include <QPointer>
@ -396,7 +398,7 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLqi(quint8 startIndex)
QByteArray asdu;
QDataStream stream(&asdu, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << startIndex;
stream << transactionSequenceNumber << startIndex;
// Set the ZDO frame as APS request payload
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);
return;
}
@ -536,5 +585,5 @@ void ZigbeeDeviceObject::processApsDataIndication(const Zigbee::ApsdeDataIndicat
return;
}
qCWarning(dcZigbeeDeviceObject()) << "Unhandled ZDO indication" << m_node << asdu;
qCWarning(dcZigbeeDeviceObject()) << "Unhandled ZDO indication" << m_node << indication << asdu;
}

View File

@ -57,7 +57,7 @@ public:
// Management request
ZigbeeDeviceObjectReply *requestMgmtLeaveNetwork(bool rejoin = false, bool removeChildren = false);
ZigbeeDeviceObjectReply *requestMgmtLqi(quint8 startIndex = 0x00);
ZigbeeDeviceObjectReply *requestMgmtBind(quint8 startIndex = 0x00);
// TODO: write all requests

View File

@ -200,7 +200,7 @@ QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::Adpu &deviceAdpu)
debug.nospace() << "DeviceAdpu(SQN: " << deviceAdpu.transactionSequenceNumber << ", ";
debug.nospace() << deviceAdpu.status << ", ";
debug.nospace() << ZigbeeUtils::convertUint16ToHexString(deviceAdpu.addressOfInterest) << ", ";
debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")";
debug.nospace() << "Payload: " << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")";
return debug.space();
}
@ -262,3 +262,22 @@ QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::PowerDescriptor &powe
debug.nospace() << " Power level: " << powerDescriptor.powerLevel;
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;
}

View File

@ -32,6 +32,7 @@
#include <QObject>
#include "zigbee.h"
#include "zigbeeaddress.h"
class ZigbeeDeviceProfile
{
@ -276,6 +277,17 @@ public:
PowerLevel powerLevel = PowerLevelFull;
} 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 MacCapabilities parseMacCapabilities(quint8 macCapabilitiesFlag);
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::DescriptorCapabilities &descriptorCapabilities);
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::PowerDescriptor &powerDescriptor);
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::BindingTableListRecord &bindingTableListRecord);
#endif // ZIGBEEDEVICEPROFILE_H

View File

@ -154,6 +154,58 @@ void ZigbeeNode::startInitialization()
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()
{
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() << ", " << node->extendedAddress().toString();
debug.nospace().noquote() << ") ";
return debug;
debug.nospace().noquote() << ")";
return debug.space().quote();
}

View File

@ -85,6 +85,8 @@ public:
// This method starts the node initialization phase (read descriptors and endpoints)
void startInitialization();
void readBindingTableEntries();
private:
ZigbeeNode(ZigbeeNetwork *network, quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent = nullptr);