Implement first ZDO call

This commit is contained in:
Simon Stürz 2020-04-08 21:34:05 +02:00
parent 4472700160
commit 118cdedc6a
22 changed files with 543 additions and 259 deletions

View File

@ -5,9 +5,16 @@ This repository contains the nymea-zigbee library and tools.
# Supported hardware # Supported hardware
Currently the only supported hardware is from NXP, but the tool will be designed to support also other hardware modules. Depending on your available hardware following gateway modules are supported
## NXP ## NXP
* JN5168 (SoM) * JN5168 (SoM)
* JN5169 (USB Stick) * JN5169 (USB Stick)
## deCONZ
* ConBee
* RaspBee
* ConBee II
* RaspBee II

View File

@ -224,7 +224,7 @@ void ZigbeeInterfaceDeconz::sendPackage(const QByteArray &package)
qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteArrayToHexString(data); qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteArrayToHexString(data);
} }
m_serialPort->flush(); //m_serialPort->flush();
} }
bool ZigbeeInterfaceDeconz::enable(const QString &serialPort, qint32 baudrate) bool ZigbeeInterfaceDeconz::enable(const QString &serialPort, qint32 baudrate)

View File

@ -60,8 +60,18 @@ void ZigbeeInterfaceDeconzReply::abort()
ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent) : ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent) :
QObject(parent), QObject(parent),
m_timer(new QTimer(this)),
m_command(command), m_command(command),
m_sequenceNumber(sequenceNumber) m_sequenceNumber(sequenceNumber)
{ {
m_timer->setInterval(2000);
m_timer->setSingleShot(true);
connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceDeconzReply::onTimeout);
}
void ZigbeeInterfaceDeconzReply::onTimeout()
{
m_timeout = true;
emit timeout();
emit finished();
} }

View File

@ -29,6 +29,7 @@
#define ZIGBEEINTERFACEDECONZREPLY_H #define ZIGBEEINTERFACEDECONZREPLY_H
#include <QObject> #include <QObject>
#include <QTimer>
#include "deconz.h" #include "deconz.h"
@ -47,12 +48,14 @@ public:
// Response content // Response content
Deconz::StatusCode statusCode() const; Deconz::StatusCode statusCode() const;
bool timeout() const;
bool aborted() const; bool aborted() const;
void abort(); void abort();
private: private:
explicit ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent = nullptr); explicit ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent = nullptr);
QTimer *m_timer = nullptr;
bool m_timeout = false;
bool m_aborted = false; bool m_aborted = false;
// Request content // Request content
@ -63,7 +66,11 @@ private:
Deconz::StatusCode m_statusCode = Deconz::StatusCodeError; Deconz::StatusCode m_statusCode = Deconz::StatusCodeError;
QByteArray m_responseData; QByteArray m_responseData;
private slots:
void onTimeout();
signals: signals:
void timeout();
void finished(); void finished();
}; };

View File

@ -28,6 +28,7 @@
#include "zigbeebridgecontrollerdeconz.h" #include "zigbeebridgecontrollerdeconz.h"
#include "loggingcategory.h" #include "loggingcategory.h"
#include "zigbeeutils.h" #include "zigbeeutils.h"
#include "zigbeedeviceprofile.h"
#include <QDataStream> #include <QDataStream>
@ -219,7 +220,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestQuerySendDataCo
return createReply(Deconz::CommandApsDataConfirm, sequenceNumber, this); return createReply(Deconz::CommandApsDataConfirm, sequenceNumber, this);
} }
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius) ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius)
{ {
quint8 sequenceNumber = generateSequenceNumber(); quint8 sequenceNumber = generateSequenceNumber();
qCDebug(dcZigbeeController()) << "Request enqueue send data to group" << ZigbeeUtils::convertUint16ToHexString(groupAddress) qCDebug(dcZigbeeController()) << "Request enqueue send data to group" << ZigbeeUtils::convertUint16ToHexString(groupAddress)
@ -240,13 +241,13 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
stream << static_cast<quint8>(sequenceNumber); stream << static_cast<quint8>(sequenceNumber);
stream << static_cast<quint8>(0); // Reserverd stream << static_cast<quint8>(0); // Reserverd
stream << static_cast<quint16>(7 + payloadLength); // Frame length stream << static_cast<quint16>(7 + payloadLength); // Frame length
stream << static_cast<quint16>(payloadLength); stream << payloadLength;
stream << requestId; stream << requestId;
stream << static_cast<quint8>(0); // Flags stream << static_cast<quint8>(0); // Flags
stream << static_cast<quint8>(Zigbee::DestinationAddressModeGroup); stream << static_cast<quint8>(Zigbee::DestinationAddressModeGroup);
stream << groupAddress << destinationEndpoint; stream << groupAddress << destinationEndpoint;
stream << static_cast<quint16>(profileId); stream << profileId;
stream << static_cast<quint16>(clusterId); stream << clusterId;
stream << sourceEndpoint; stream << sourceEndpoint;
stream << static_cast<quint16>(asdu.length()); stream << static_cast<quint16>(asdu.length());
for (int i = 0; i < asdu.length(); i++) { for (int i = 0; i < asdu.length(); i++) {
@ -260,7 +261,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this);
} }
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId 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, quint8 radius)
{ {
quint8 sequenceNumber = generateSequenceNumber(); quint8 sequenceNumber = generateSequenceNumber();
qCDebug(dcZigbeeController()) << "Request enqueue send data to short address" << ZigbeeUtils::convertUint16ToHexString(shortAddress) qCDebug(dcZigbeeController()) << "Request enqueue send data to short address" << ZigbeeUtils::convertUint16ToHexString(shortAddress)
@ -281,13 +282,13 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
stream << static_cast<quint8>(sequenceNumber); stream << static_cast<quint8>(sequenceNumber);
stream << static_cast<quint8>(0); // Reserverd stream << static_cast<quint8>(0); // Reserverd
stream << static_cast<quint16>(7 + payloadLength); // Frame length stream << static_cast<quint16>(7 + payloadLength); // Frame length
stream << static_cast<quint16>(payloadLength); stream << payloadLength;
stream << requestId; stream << requestId;
stream << static_cast<quint8>(0); // Flags stream << static_cast<quint8>(0); // Flags
stream << static_cast<quint8>(Zigbee::DestinationAddressModeShortAddress); stream << static_cast<quint8>(Zigbee::DestinationAddressModeShortAddress);
stream << shortAddress << destinationEndpoint; stream << shortAddress << destinationEndpoint;
stream << static_cast<quint16>(profileId); stream << profileId;
stream << static_cast<quint16>(clusterId); stream << clusterId;
stream << sourceEndpoint; stream << sourceEndpoint;
stream << static_cast<quint16>(asdu.length()); stream << static_cast<quint16>(asdu.length());
for (int i = 0; i < asdu.length(); i++) { for (int i = 0; i < asdu.length(); i++) {
@ -301,7 +302,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this);
} }
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId 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, quint8 radius)
{ {
quint8 sequenceNumber = generateSequenceNumber(); quint8 sequenceNumber = generateSequenceNumber();
qCDebug(dcZigbeeController()) << "Request enqueue send data to IEEE address" << ieeeAddress.toString() qCDebug(dcZigbeeController()) << "Request enqueue send data to IEEE address" << ieeeAddress.toString()
@ -322,13 +323,13 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
stream << static_cast<quint8>(sequenceNumber); stream << static_cast<quint8>(sequenceNumber);
stream << static_cast<quint8>(0); // Reserverd stream << static_cast<quint8>(0); // Reserverd
stream << static_cast<quint16>(7 + payloadLength); // Frame length stream << static_cast<quint16>(7 + payloadLength); // Frame length
stream << static_cast<quint16>(payloadLength); stream << payloadLength;
stream << requestId; stream << requestId;
stream << static_cast<quint8>(0); // Flags stream << static_cast<quint8>(0); // Flags
stream << static_cast<quint8>(Zigbee::DestinationAddressModeIeeeAddress); stream << static_cast<quint8>(Zigbee::DestinationAddressModeIeeeAddress);
stream << ieeeAddress.toUInt64() << destinationEndpoint; stream << ieeeAddress.toUInt64() << destinationEndpoint;
stream << static_cast<quint16>(profileId); stream << profileId;
stream << static_cast<quint16>(clusterId); stream << clusterId;
stream << sourceEndpoint; stream << sourceEndpoint;
stream << static_cast<quint16>(asdu.length()); stream << static_cast<quint16>(asdu.length());
for (int i = 0; i < asdu.length(); i++) { for (int i = 0; i < asdu.length(); i++) {
@ -342,6 +343,30 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this);
} }
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(const ZigbeeNetworkRequest &request)
{
ZigbeeInterfaceDeconzReply *interfaceReply = nullptr;
switch (request.destinationAddressMode()) {
case Zigbee::DestinationAddressModeGroup:
interfaceReply = requestEnqueueSendDataGroup(request.requestId(), request.destinationShortAddress(),
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.radius());
break;
case Zigbee::DestinationAddressModeShortAddress:
interfaceReply = requestEnqueueSendDataShortAddress(request.requestId(), request.destinationShortAddress(),
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.radius());
break;
case Zigbee::DestinationAddressModeIeeeAddress:
interfaceReply = requestEnqueueSendDataIeeeAddress(request.requestId(), request.destinationIeeeAddress(),
request.destinationEndpoint(), request.profileId(), request.clusterId(),
request.sourceEndpoint(), request.asdu(), request.radius());
break;
}
return interfaceReply;
}
quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber() quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber()
{ {
return m_sequenceNumber++; return m_sequenceNumber++;
@ -358,6 +383,9 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Co
// Add it to the pending list // Add it to the pending list
m_pendingReplies.insert(sequenceNumber, reply); m_pendingReplies.insert(sequenceNumber, reply);
// Fixme: start the timer once actually sent to the interface
reply->m_timer->start();
return reply; return reply;
} }
@ -712,6 +740,38 @@ DeconzDeviceState ZigbeeBridgeControllerDeconz::parseDeviceStateFlag(quint8 devi
return state; return state;
} }
void ZigbeeBridgeControllerDeconz::readDataIndication()
{
ZigbeeInterfaceDeconzReply *reply = requestReadReceivedDataIndication();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read data indication." << reply->statusCode();
// FIXME: set an appropriate error
return;
}
// ASP data indication received, process the content
qCDebug(dcZigbeeController()) << "Reading data indication finished successfully";
processDataIndication(reply->responseData());
});
}
void ZigbeeBridgeControllerDeconz::readDataConfirm()
{
ZigbeeInterfaceDeconzReply *reply = requestQuerySendDataConfirm();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read data confirm." << reply->statusCode();
// FIXME: set an appropriate error
return;
}
// ASP data indication received, process the content
qCDebug(dcZigbeeController()) << "Reading data confirm finished successfully";
processDataConfirm(reply->responseData());
});
}
void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceState) void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceState)
{ {
qCDebug(dcZigbeeController()) << deviceState; qCDebug(dcZigbeeController()) << deviceState;
@ -732,36 +792,16 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt
if (m_networkState != Deconz::NetworkStateConnected) if (m_networkState != Deconz::NetworkStateConnected)
return; return;
// Note: read a data indication before a confirmation since the confirmation arrives after a related indication normally
// Check if we have to read a data indication message // Check if we have to read a data indication message
if (deviceState.aspDataIndication) { if (deviceState.aspDataIndication) {
ZigbeeInterfaceDeconzReply *reply = requestReadReceivedDataIndication(); readDataIndication();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read data indication." << reply->statusCode();
// FIXME: set an appropriate error
return;
}
// ASP data indication received, process the content
qCDebug(dcZigbeeController()) << "Reading data indication finished successfully";
processDataIndication(reply->responseData());
});
} }
// Check if we have a response to read for a request // Check if we have a response to read for a request
if (deviceState.aspDataConfirm) { if (deviceState.aspDataConfirm) {
ZigbeeInterfaceDeconzReply *reply = requestQuerySendDataConfirm(); readDataConfirm();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read data indication." << reply->statusCode();
// FIXME: set an appropriate error
return;
}
// ASP data indication received, process the content
qCDebug(dcZigbeeController()) << "Reading data confirm finished successfully";
processDataConfirm(reply->responseData());
});
} }
} }
@ -771,104 +811,76 @@ void ZigbeeBridgeControllerDeconz::processDataIndication(const QByteArray &data)
// ASP data indication // ASP data indication
QDataStream stream(data); QDataStream stream(data);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 destinationAddressModeFlag = 0; quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 reserved = 0; quint16 asduLength = 0;
quint16 destinationShortAddress = 0; quint64 destinationIeeeAddress = 0; quint8 destinationEndpoint = 0;
quint8 sourceAddressModeFlag = 0; quint16 sourceShortAddress = 0; quint64 sourceIeeeAddress = 0; quint8 sourceEndpoint = 0;
quint16 profileId = 0; quint16 clusterId = 0; quint16 asduLength = 0; QByteArray asdu; quint8 reserved = 0;
quint8 lqi = 0; qint8 rssi = 0;
stream >> payloadLenght >> deviceStateFlag >> destinationAddressModeFlag; DeconzApsDataIndication indication;
Zigbee::DestinationAddressMode destinationAddressMode = static_cast<Zigbee::DestinationAddressMode>(destinationAddressModeFlag); stream >> payloadLenght >> deviceStateFlag;
stream >> indication.destinationAddressMode;
Zigbee::DestinationAddressMode destinationAddressMode = static_cast<Zigbee::DestinationAddressMode>(indication.destinationAddressMode);
if (destinationAddressMode == Zigbee::DestinationAddressModeGroup || destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) if (destinationAddressMode == Zigbee::DestinationAddressModeGroup || destinationAddressMode == Zigbee::DestinationAddressModeShortAddress)
stream >> destinationShortAddress; stream >> indication.destinationShortAddress;
if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress)
stream >> destinationIeeeAddress; stream >> indication.destinationIeeeAddress;
stream >> destinationEndpoint >> sourceAddressModeFlag; stream >> indication.destinationEndpoint >> indication.sourceAddressMode;
Zigbee::SourceAddressMode sourceAddressMode = static_cast<Zigbee::SourceAddressMode>(sourceAddressModeFlag); Zigbee::SourceAddressMode sourceAddressMode = static_cast<Zigbee::SourceAddressMode>(indication.sourceAddressMode);
if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress)
stream >> sourceShortAddress; stream >> indication.sourceShortAddress;
if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress)
stream >> sourceIeeeAddress; stream >> indication.sourceIeeeAddress;
stream >> sourceEndpoint >> profileId >> clusterId >> asduLength;
stream >> indication.sourceEndpoint >> indication.profileId >> indication.clusterId >> asduLength;
// Fill asdu data // Fill asdu data
for (int i = 0; i < asduLength; i++) { for (int i = 0; i < asduLength; i++) {
quint8 byte = 0; quint8 byte = 0;
stream >> byte; stream >> byte;
asdu.append(static_cast<char>(byte)); indication.asdu.append(static_cast<char>(byte));
} }
stream >> reserved >> reserved >> lqi >> reserved >> reserved >> reserved >> reserved >> rssi; stream >> reserved >> reserved >> indication.lqi >> reserved >> reserved >> reserved >> reserved >> indication.rssi;
// Print the information for debugging // Print the information for debugging
qCDebug(dcZigbeeController()) << "Data indication received:"; qCDebug(dcZigbeeController()) << indication;
qCDebug(dcZigbeeController()) << " Destination address mode:" << destinationAddressMode;
if (destinationAddressMode == Zigbee::DestinationAddressModeGroup)
qCDebug(dcZigbeeController()) << " Destination address (group):" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress);
if (destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) emit aspDataIndicationReceived(indication);
qCDebug(dcZigbeeController()) << " Destination short address:" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress);
if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) // Process the device state in order to check if we have to request another indication
qCDebug(dcZigbeeController()) << " Destination IEEE address:" << ZigbeeAddress(destinationIeeeAddress).toString(); DeconzDeviceState deviceState = parseDeviceStateFlag(deviceStateFlag);
if (deviceState.aspDataIndication) {
qCDebug(dcZigbeeController()) << " Destination endpoint" << ZigbeeUtils::convertByteToHexString(destinationEndpoint); readDataIndication();
}
qCDebug(dcZigbeeController()) << " Source address mode:" << sourceAddressMode;
if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress)
qCDebug(dcZigbeeController()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceShortAddress);
if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress)
qCDebug(dcZigbeeController()) << " Source IEEE address:" << ZigbeeAddress(sourceIeeeAddress).toString();
qCDebug(dcZigbeeController()) << " Source endpoint:" << ZigbeeUtils::convertByteToHexString(sourceEndpoint);
qCDebug(dcZigbeeController()) << " Profile:" << static_cast<Zigbee::ZigbeeProfile>(profileId);
qCDebug(dcZigbeeController()) << " Cluster:" << static_cast<Zigbee::ClusterId>(clusterId);
qCDebug(dcZigbeeController()) << " ASDU:" << ZigbeeUtils::convertByteArrayToHexString(asdu);
qCDebug(dcZigbeeController()) << " LQI:" << lqi;
qCDebug(dcZigbeeController()) << " RSSI:" << rssi << "dBm";
processDeviceState(parseDeviceStateFlag(deviceStateFlag));
} }
void ZigbeeBridgeControllerDeconz::processDataConfirm(const QByteArray &data) void ZigbeeBridgeControllerDeconz::processDataConfirm(const QByteArray &data)
{ {
QDataStream stream(data); QDataStream stream(data);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 requestId = 0; quint8 destinationAddressMode = 0; DeconzApsDataConfirm confirm;
quint16 destinationShortAddress = 0; quint64 destinationIeeeAddress = 0; quint8 destinationEndpoint = 0; quint16 payloadLenght = 0; quint8 deviceStateFlag = 0;
quint8 sourceEndpoint = 0; quint8 zigbeeConfirmStatus = 0; stream >> payloadLenght >> deviceStateFlag;
stream >> confirm.requestId >> confirm.destinationAddressMode;
stream >> payloadLenght >> deviceStateFlag >> requestId >> destinationAddressMode; if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeGroup || confirm.destinationAddressMode == Zigbee::DestinationAddressModeShortAddress)
if (destinationAddressMode == Zigbee::DestinationAddressModeGroup || destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) stream >> confirm.destinationShortAddress;
stream >> destinationShortAddress;
if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress)
stream >> destinationIeeeAddress; stream >> confirm.destinationIeeeAddress;
stream >> destinationEndpoint >> sourceEndpoint >> zigbeeConfirmStatus; stream >> confirm.destinationEndpoint >> confirm.sourceEndpoint >> confirm.zigbeeStatusCode;
// Print the information for debugging // Print the information for debugging
qCDebug(dcZigbeeController()) << "Data confirm received: Request" << requestId; qCDebug(dcZigbeeController()) << confirm;
qCDebug(dcZigbeeController()) << " Destination address mode:" << destinationAddressMode;
if (destinationAddressMode == Zigbee::DestinationAddressModeGroup)
qCDebug(dcZigbeeController()) << " Destination address (group):" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress);
if (destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) emit aspDataConfirmReceived(confirm);
qCDebug(dcZigbeeController()) << " Destination short address:" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress);
if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) // Process the device state in order to check if we have to request another indication
qCDebug(dcZigbeeController()) << " Destination IEEE address:" << ZigbeeAddress(destinationIeeeAddress).toString(); DeconzDeviceState deviceState = parseDeviceStateFlag(deviceStateFlag);
if (deviceState.aspDataConfirm) {
qCDebug(dcZigbeeController()) << " Destination endpoint" << ZigbeeUtils::convertByteToHexString(destinationEndpoint); readDataConfirm();
qCDebug(dcZigbeeController()) << " Source endpoint" << ZigbeeUtils::convertByteToHexString(sourceEndpoint); }
qCDebug(dcZigbeeController()) << " Confirm status" << static_cast<Zigbee::ZigbeeStatus>(zigbeeConfirmStatus);
} }
void ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged(bool available) void ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged(bool available)
@ -899,8 +911,8 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
QByteArray data = package.right(package.length() - 5); QByteArray data = package.right(package.length() - 5);
Deconz::Command command = static_cast<Deconz::Command>(commandInt); Deconz::Command command = static_cast<Deconz::Command>(commandInt);
Deconz::StatusCode status = static_cast<Deconz::StatusCode>(statusInt); Deconz::StatusCode status = static_cast<Deconz::StatusCode>(statusInt);
qCDebug(dcZigbeeController()) << "Interface message received" << command << "SQN:" << sequenceNumber //qCDebug(dcZigbeeController()) << "Interface message received" << command << "SQN:" << sequenceNumber
<< status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data); // << status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data);
// Check if this is an interface response for a pending reply // Check if this is an interface response for a pending reply
if (m_pendingReplies.contains(sequenceNumber) && m_pendingReplies.value(sequenceNumber)->command() == command) { if (m_pendingReplies.contains(sequenceNumber) && m_pendingReplies.value(sequenceNumber)->command() == command) {
@ -982,3 +994,59 @@ QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState)
debug.nospace() << "CanSend=" << deviceState.aspDataRequestFreeSlots << ")"; debug.nospace() << "CanSend=" << deviceState.aspDataRequestFreeSlots << ")";
return debug.space(); return debug.space();
} }
QDebug operator<<(QDebug debug, const DeconzApsDataConfirm &confirm)
{
debug.nospace() << "ASP.Confirm(";
debug.nospace() << "Request ID: " << confirm.requestId << ", ";
if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeGroup)
debug.nospace() << "Group address:" << ZigbeeUtils::convertUint16ToHexString(confirm.destinationShortAddress) << ", ";
if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeShortAddress)
debug.nospace() << "NWK address:" << ZigbeeUtils::convertUint16ToHexString(confirm.destinationShortAddress) << ", ";
if (confirm.destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress)
debug.nospace() << "IEEE address:" << ZigbeeAddress(confirm.destinationIeeeAddress).toString() << ", ";
debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(confirm.destinationEndpoint) << ", ";
debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(confirm.sourceEndpoint) << ", ";
debug.nospace() << static_cast<Zigbee::ZigbeeStatus>(confirm.zigbeeStatusCode);
debug.nospace() << ")";
return debug.space();
}
QDebug operator<<(QDebug debug, const DeconzApsDataIndication &indication)
{
debug.nospace() << "ASP.Indication(";
if (indication.destinationAddressMode == Zigbee::DestinationAddressModeGroup)
debug.nospace() << "Group address:" << ZigbeeUtils::convertUint16ToHexString(indication.destinationShortAddress) << ", ";
if (indication.destinationAddressMode == Zigbee::DestinationAddressModeShortAddress)
debug.nospace() << "NWK address:" << ZigbeeUtils::convertUint16ToHexString(indication.destinationShortAddress) << ", ";
if (indication.destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress)
debug.nospace() << "IEEE address:" << ZigbeeAddress(indication.destinationIeeeAddress).toString() << ", ";
debug.nospace() << "Destination EP:" << ZigbeeUtils::convertByteToHexString(indication.destinationEndpoint) << ", ";
debug.nospace() << "Source EP:" << ZigbeeUtils::convertByteToHexString(indication.sourceEndpoint) << ", ";
if (indication.sourceAddressMode == Zigbee::SourceAddressModeShortAddress || indication.sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress)
debug.nospace() << "Source NWK address:" << ZigbeeUtils::convertUint16ToHexString(indication.sourceShortAddress) << ", ";
if (indication.sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || indication.sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress)
debug.nospace() << "Source IEEE address:" << ZigbeeAddress(indication.sourceIeeeAddress).toString() << ", ";
debug.nospace() << static_cast<Zigbee::ZigbeeProfile>(indication.profileId) << ", ";
if (indication.profileId == static_cast<quint16>(Zigbee::ZigbeeProfileDevice)) {
debug.nospace() << static_cast<ZigbeeDeviceProfile::ZdoCommand>(indication.clusterId) << ", ";
} else {
debug.nospace() << static_cast<Zigbee::ClusterId>(indication.clusterId) << ", ";
}
debug.nospace() << "ASDU: " << ZigbeeUtils::convertByteArrayToHexString(indication.asdu) << ", ";
debug.nospace() << "LQI: " << indication.lqi << ", ";
debug.nospace() << "RSSI: " << indication.rssi << "dBm)";
return debug.space();
}

View File

@ -35,6 +35,7 @@
#include "zigbee.h" #include "zigbee.h"
#include "zigbeeaddress.h" #include "zigbeeaddress.h"
#include "zigbeenetworkkey.h" #include "zigbeenetworkkey.h"
#include "zigbeenetworkrequest.h"
#include "zigbeebridgecontroller.h" #include "zigbeebridgecontroller.h"
#include "interface/deconz.h" #include "interface/deconz.h"
@ -70,6 +71,34 @@ typedef struct DeconzDeviceState {
bool aspDataRequestFreeSlots = false; bool aspDataRequestFreeSlots = false;
} DeconzDeviceState; } DeconzDeviceState;
// Basic struct for interface data. Default Response
typedef struct DeconzApsDataConfirm {
quint8 requestId = 0;
quint8 destinationAddressMode = Zigbee::DestinationAddressModeShortAddress;
quint16 destinationShortAddress = 0;
quint64 destinationIeeeAddress;
quint8 destinationEndpoint = 0;
quint8 sourceEndpoint = 0;
quint8 zigbeeStatusCode = 0;
} DeconzApsDataConfirm;
typedef struct DeconzApsDataIndication {
quint8 destinationAddressMode = 0;
quint16 destinationShortAddress = 0;
quint64 destinationIeeeAddress = 0;
quint8 destinationEndpoint = 0;
quint8 sourceAddressMode = 0;
quint16 sourceShortAddress = 0;
quint64 sourceIeeeAddress = 0;
quint8 sourceEndpoint = 0;
quint16 profileId = 0;
quint16 clusterId = 0;
QByteArray asdu;
quint8 lqi = 0;
qint8 rssi = 0;
} DeconzApsDataIndication;
class ZigbeeBridgeControllerDeconz : public ZigbeeBridgeController class ZigbeeBridgeControllerDeconz : public ZigbeeBridgeController
{ {
Q_OBJECT Q_OBJECT
@ -96,9 +125,11 @@ public:
ZigbeeInterfaceDeconzReply *requestQuerySendDataConfirm(); ZigbeeInterfaceDeconzReply *requestQuerySendDataConfirm();
// Send data // Send data
ZigbeeInterfaceDeconzReply *requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); 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, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId 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, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId 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 *requestSendRequest(const ZigbeeNetworkRequest &request);
private: private:
ZigbeeInterfaceDeconz *m_interface = nullptr; ZigbeeInterfaceDeconz *m_interface = nullptr;
@ -122,8 +153,11 @@ private:
// Device state helper // Device state helper
DeconzDeviceState parseDeviceStateFlag(quint8 deviceStateFlag); DeconzDeviceState parseDeviceStateFlag(quint8 deviceStateFlag);
void processDeviceState(DeconzDeviceState deviceState);
void readDataIndication();
void readDataConfirm();
void processDeviceState(DeconzDeviceState deviceState);
void processDataIndication(const QByteArray &data); void processDataIndication(const QByteArray &data);
void processDataConfirm(const QByteArray &data); void processDataConfirm(const QByteArray &data);
@ -131,6 +165,9 @@ signals:
void networkStateChanged(Deconz::NetworkState networkState); void networkStateChanged(Deconz::NetworkState networkState);
void networkConfigurationParameterChanged(const DeconzNetworkConfiguration &networkConfiguration); void networkConfigurationParameterChanged(const DeconzNetworkConfiguration &networkConfiguration);
void aspDataConfirmReceived(const DeconzApsDataConfirm &confirm);
void aspDataIndicationReceived(const DeconzApsDataIndication &indication);
private slots: private slots:
void onInterfaceAvailableChanged(bool available); void onInterfaceAvailableChanged(bool available);
void onInterfacePackageReceived(const QByteArray &package); void onInterfacePackageReceived(const QByteArray &package);
@ -143,6 +180,8 @@ public slots:
}; };
QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState); QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState);
QDebug operator<<(QDebug debug, const DeconzApsDataConfirm &confirm);
QDebug operator<<(QDebug debug, const DeconzApsDataIndication &indication);
#endif // ZIGBEEBRIDGECONTROLLERDECONZ_H #endif // ZIGBEEBRIDGECONTROLLERDECONZ_H

View File

@ -26,6 +26,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeenetworkdeconz.h" #include "zigbeenetworkdeconz.h"
#include "zigbeedeviceprofile.h"
#include "loggingcategory.h" #include "loggingcategory.h"
#include "zigbeeutils.h" #include "zigbeeutils.h"
@ -37,6 +38,8 @@ ZigbeeNetworkDeconz::ZigbeeNetworkDeconz(QObject *parent) :
m_controller = new ZigbeeBridgeControllerDeconz(this); m_controller = new ZigbeeBridgeControllerDeconz(this);
//connect(m_controller, &ZigbeeBridgeControllerDeconz::messageReceived, this, &ZigbeeNetworkDeconz::onMessageReceived); //connect(m_controller, &ZigbeeBridgeControllerDeconz::messageReceived, this, &ZigbeeNetworkDeconz::onMessageReceived);
connect(m_controller, &ZigbeeBridgeControllerDeconz::availableChanged, this, &ZigbeeNetworkDeconz::onControllerAvailableChanged); connect(m_controller, &ZigbeeBridgeControllerDeconz::availableChanged, this, &ZigbeeNetworkDeconz::onControllerAvailableChanged);
connect(m_controller, &ZigbeeBridgeControllerDeconz::aspDataConfirmReceived, this, &ZigbeeNetworkDeconz::onAspDataConfirmReceived);
connect(m_controller, &ZigbeeBridgeControllerDeconz::aspDataIndicationReceived, this, &ZigbeeNetworkDeconz::onAspDataIndicationReceived);
m_pollNetworkStateTimer = new QTimer(this); m_pollNetworkStateTimer = new QTimer(this);
m_pollNetworkStateTimer->setInterval(1000); m_pollNetworkStateTimer->setInterval(1000);
@ -52,6 +55,30 @@ ZigbeeBridgeController *ZigbeeNetworkDeconz::bridgeController() const
return nullptr; return nullptr;
} }
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);
ZigbeeInterfaceDeconzReply *interfaceReply = m_controller->requestSendRequest(request);
connect(interfaceReply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply, interfaceReply](){
if (interfaceReply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could send request to controller. SQN:" << interfaceReply->sequenceNumber() << interfaceReply->statusCode();
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorInterfaceError);
return;
}
});
return reply;
}
quint8 ZigbeeNetworkDeconz::generateSequenceNumber()
{
return m_sequenceNumber++;
}
void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetworkState state) void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetworkState state)
{ {
if (m_createState == state) if (m_createState == state)
@ -68,11 +95,13 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->requestChangeNetworkState(Deconz::NetworkStateOffline); ZigbeeInterfaceDeconzReply *reply = m_controller->requestChangeNetworkState(Deconz::NetworkStateOffline);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not stop network for creating a new one." << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not stop network for creating a new one. SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Stop network finished successfully. SQN:" << reply->sequenceNumber();
// Start polling the device state, should be Online -> Leaving -> Offline // Start polling the device state, should be Online -> Leaving -> Offline
m_pollNetworkStateTimer->start(); m_pollNetworkStateTimer->start();
}); });
@ -94,12 +123,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNodeType, paramData); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNodeType, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterNodeType << Deconz::NodeTypeCoordinator << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterNodeType << Deconz::NodeTypeCoordinator << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Configured successfully bridge to" << Deconz::NodeTypeCoordinator; qCDebug(dcZigbeeNetwork()) << "Configured successfully bridge to" << Deconz::NodeTypeCoordinator << "SQN:" << reply->sequenceNumber();
QByteArray paramData; QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly); QDataStream stream(&paramData, QIODevice::WriteOnly);
@ -109,12 +138,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterChannelMask, paramData); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterChannelMask, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterChannelMask << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterChannelMask << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Configured channel mask successfully"; qCDebug(dcZigbeeNetwork()) << "Configured channel mask successfully. SQN:" << reply->sequenceNumber();
QByteArray paramData; QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly); QDataStream stream(&paramData, QIODevice::WriteOnly);
@ -124,12 +153,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterApsExtendedPanId, paramData); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterApsExtendedPanId, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterApsExtendedPanId << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterApsExtendedPanId << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Configured APS extended PANID successfully"; qCDebug(dcZigbeeNetwork()) << "Configured APS extended PANID successfully. SQN:" << reply->sequenceNumber();
QByteArray paramData; QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly); QDataStream stream(&paramData, QIODevice::WriteOnly);
@ -139,12 +168,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterTrustCenterAddress, paramData); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterTrustCenterAddress, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterTrustCenterAddress << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterTrustCenterAddress << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Configured trust center address successfully"; qCDebug(dcZigbeeNetwork()) << "Configured trust center address successfully. SQN:" << reply->sequenceNumber();
QByteArray paramData; QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly); QDataStream stream(&paramData, QIODevice::WriteOnly);
@ -154,7 +183,7 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterSecurityMode, paramData); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterSecurityMode, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterSecurityMode << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterSecurityMode << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
@ -166,12 +195,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNetworkKey, securityConfiguration().networkKey().toByteArray()); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNetworkKey, securityConfiguration().networkKey().toByteArray());
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterNetworkKey << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterNetworkKey << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
// Note: writing the network key fails all the time... // Note: writing the network key fails all the time...
//return; //return;
} else { } else {
qCDebug(dcZigbeeNetwork()) << "Configured network key successfully"; qCDebug(dcZigbeeNetwork()) << "Configured network key successfully. SQN:" << reply->sequenceNumber();
} }
// Configuration finished, lets start the network // Configuration finished, lets start the network
@ -188,11 +217,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->requestChangeNetworkState(Deconz::NetworkStateConnected); ZigbeeInterfaceDeconzReply *reply = m_controller->requestChangeNetworkState(Deconz::NetworkStateConnected);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not start network for creating a new one." << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not start network for creating a new one. SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Start network finished successfully. SQN:" << reply->sequenceNumber();
// Start polling the device state, should be Online -> Leaving -> Offline // Start polling the device state, should be Online -> Leaving -> Offline
m_pollNetworkStateTimer->start(); m_pollNetworkStateTimer->start();
}); });
@ -203,12 +233,12 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters(); ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up." << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully."; qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully. SQN:" << reply->sequenceNumber();
setPanId(m_controller->networkConfiguration().panId); setPanId(m_controller->networkConfiguration().panId);
setExtendedPanId(m_controller->networkConfiguration().extendedPanId); setExtendedPanId(m_controller->networkConfiguration().extendedPanId);
@ -224,22 +254,53 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
coordinatorNode->setShortAddress(m_controller->networkConfiguration().shortAddress); coordinatorNode->setShortAddress(m_controller->networkConfiguration().shortAddress);
coordinatorNode->setExtendedAddress(m_controller->networkConfiguration().ieeeAddress); coordinatorNode->setExtendedAddress(m_controller->networkConfiguration().ieeeAddress);
addUnitializedNode(coordinatorNode);
coordinatorNode->startInitialization();
// TODO: done when when node initialized // TODO: done when when node initialized
m_coordinatorNode = coordinatorNode;
addNode(coordinatorNode);
setCreateNetworkState(CreateNetworkStateIdle);
setState(StateRunning);
//addUnitializedNode(coordinatorNode);
//coordinatorNode->startInitialization();
} }
} }
} }
void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const DeconzApsDataIndication &indication)
{
if (indication.clusterId == ZigbeeDeviceProfile::DeviceAnnounce) {
QDataStream stream(indication.asdu);
stream.setByteOrder(QDataStream::LittleEndian);
quint8 sequenceNumber = 0; quint16 shortAddress = 0; quint64 ieeeAddress = 0; quint8 macFlag = 0;
stream >> sequenceNumber >> shortAddress >> ieeeAddress >> macFlag;
onDeviceAnnounced(shortAddress, ZigbeeAddress(ieeeAddress), macFlag);
return;
}
// Check if this is a response for a ZDO request
foreach (ZigbeeNetworkReply *reply, m_pendingReplies) {
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()) {
// We found the correct reply
// Set the response payload of the
qCDebug(dcZigbeeNetwork()) << "Indication response for ZDO request received"
<< static_cast<ZigbeeDeviceProfile::ZdoCommand>(reply->request().clusterId())
<< "-->"
<< static_cast<ZigbeeDeviceProfile::ZdoCommand>(indication.clusterId)
<< deviceAdpu;
setReplyResponseData(reply, indication.asdu);
return;
}
}
}
}
}
ZigbeeNode *ZigbeeNetworkDeconz::createNode(QObject *parent) ZigbeeNode *ZigbeeNetworkDeconz::createNode(QObject *parent)
{ {
return new ZigbeeNodeDeconz(m_controller, parent); return new ZigbeeNodeDeconz(this, parent);
} }
void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining) void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining)
@ -271,7 +332,6 @@ void ZigbeeNetworkDeconz::startNetworkInternally()
qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().networkKey() << "network link key"; qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().networkKey() << "network link key";
qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().globalTrustCenterLinkKey() << "global trust center link key"; qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().globalTrustCenterLinkKey() << "global trust center link key";
// - Read the firmware version // - Read the firmware version
// - Read the network configuration parameters // - Read the network configuration parameters
// - Read the network state // - Read the network state
@ -313,12 +373,12 @@ void ZigbeeNetworkDeconz::startNetworkInternally()
ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState(); ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read device state during network start up." << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not read device state during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully. SQN:" << reply->sequenceNumber();
QDataStream stream(reply->responseData()); QDataStream stream(reply->responseData());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint8 deviceStateFlag = 0; quint8 deviceStateFlag = 0;
@ -328,11 +388,19 @@ void ZigbeeNetworkDeconz::startNetworkInternally()
if (m_createNewNetwork) { if (m_createNewNetwork) {
setCreateNetworkState(CreateNetworkStateStopNetwork); setCreateNetworkState(CreateNetworkStateStopNetwork);
// Set offline
// Write configurations
// Set online
// Read configurations
// Create and initialize coordinator node
// Done. Save network
} else { } else {
// Get the network state and start the network if required // Get the network state and start the network if required
if (m_controller->networkState() == Deconz::NetworkStateConnected) { if (m_controller->networkState() == Deconz::NetworkStateConnected) {
qCDebug(dcZigbeeNetwork()) << "The network is already running."; qCDebug(dcZigbeeNetwork()) << "The network is already running.";
setState(StateRunning); setState(StateRunning);
} else {
startNetwork();
} }
} }
}); });
@ -340,20 +408,6 @@ void ZigbeeNetworkDeconz::startNetworkInternally()
}); });
} }
void ZigbeeNetworkDeconz::createNetwork()
{
// Set offline
setCreateNetworkState(CreateNetworkStateStopNetwork);
// Write configurations
// Set online
// Read configurations
// Create and initialize coordinator node
}
void ZigbeeNetworkDeconz::onControllerAvailableChanged(bool available) void ZigbeeNetworkDeconz::onControllerAvailableChanged(bool available)
{ {
qCDebug(dcZigbeeNetwork()) << "Hardware controller is" << (available ? "now available" : "not available"); qCDebug(dcZigbeeNetwork()) << "Hardware controller is" << (available ? "now available" : "not available");
@ -387,7 +441,7 @@ void ZigbeeNetworkDeconz::onPollNetworkStateTimeout()
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; //qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully";
QDataStream stream(reply->responseData()); QDataStream stream(reply->responseData());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint8 deviceStateFlag = 0; quint8 deviceStateFlag = 0;
@ -409,12 +463,12 @@ void ZigbeeNetworkDeconz::onPollNetworkStateTimeout()
ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState(); ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read device state during network start up." << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not read device state during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; //qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully. SQN:" << reply->sequenceNumber();
QDataStream stream(reply->responseData()); QDataStream stream(reply->responseData());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint8 deviceStateFlag = 0; quint8 deviceStateFlag = 0;
@ -442,6 +496,42 @@ void ZigbeeNetworkDeconz::onPollNetworkStateTimeout()
} }
} }
void ZigbeeNetworkDeconz::onAspDataConfirmReceived(const DeconzApsDataConfirm &confirm)
{
qCDebug(dcZigbeeNetwork()) << confirm;
ZigbeeNetworkReply *reply = m_pendingReplies.take(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));
}
void ZigbeeNetworkDeconz::onAspDataIndicationReceived(const DeconzApsDataIndication &indication)
{
qCDebug(dcZigbeeNetwork()) << indication;
// Check if this indocation is related to any pending reply
if (indication.profileId == Zigbee::ZigbeeProfileDevice) {
handleZigbeeDeviceProfileIndication(indication);
return;
}
// Find reply finish it
qCDebug(dcZigbeeNetwork()) << "Unhandled indication" << indication;
}
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
}
void ZigbeeNetworkDeconz::startNetwork() void ZigbeeNetworkDeconz::startNetwork()
{ {
loadNetwork(); loadNetwork();
@ -466,12 +556,12 @@ void ZigbeeNetworkDeconz::stopNetwork()
setState(StateStopping); setState(StateStopping);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not leave network." << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not leave network. SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Network left successfully"; qCDebug(dcZigbeeNetwork()) << "Network left successfully. SQN:" << reply->sequenceNumber();
setState(StateOffline); setState(StateOffline);
}); });
} }

View File

@ -53,7 +53,9 @@ public:
ZigbeeBridgeController *bridgeController() const override; ZigbeeBridgeController *bridgeController() const override;
ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) override;
quint8 generateSequenceNumber();
private: private:
ZigbeeBridgeControllerDeconz *m_controller = nullptr; ZigbeeBridgeControllerDeconz *m_controller = nullptr;
@ -61,9 +63,16 @@ private:
CreateNetworkState m_createState = CreateNetworkStateIdle; CreateNetworkState m_createState = CreateNetworkStateIdle;
bool m_createNewNetwork = false; bool m_createNewNetwork = false;
QHash<quint8, ZigbeeNetworkReply *> m_pendingReplies;
quint8 m_sequenceNumber = 0;
QTimer *m_pollNetworkStateTimer = nullptr; QTimer *m_pollNetworkStateTimer = nullptr;
void setCreateNetworkState(CreateNetworkState state); void setCreateNetworkState(CreateNetworkState state);
void handleZigbeeDeviceProfileIndication(const DeconzApsDataIndication &indication);
protected: protected:
ZigbeeNode *createNode(QObject *parent) override; ZigbeeNode *createNode(QObject *parent) override;
@ -71,12 +80,15 @@ protected:
void startNetworkInternally(); void startNetworkInternally();
void createNetwork();
private slots: private slots:
void onControllerAvailableChanged(bool available); void onControllerAvailableChanged(bool available);
void onPollNetworkStateTimeout(); void onPollNetworkStateTimeout();
void onAspDataConfirmReceived(const DeconzApsDataConfirm &confirm);
void onAspDataIndicationReceived(const DeconzApsDataIndication &indication);
void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities);
public slots: public slots:
void startNetwork() override; void startNetwork() override;
void stopNetwork() override; void stopNetwork() override;

View File

@ -26,10 +26,15 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeenodedeconz.h" #include "zigbeenodedeconz.h"
#include "zigbeedeviceprofile.h"
#include "zigbeenetworkdeconz.h"
#include "loggingcategory.h"
ZigbeeNodeDeconz::ZigbeeNodeDeconz(ZigbeeBridgeControllerDeconz *controller, QObject *parent) : #include <QDataStream>
ZigbeeNodeDeconz::ZigbeeNodeDeconz(ZigbeeNetworkDeconz *network, QObject *parent) :
ZigbeeNode(parent), ZigbeeNode(parent),
m_controller(controller) m_network(network)
{ {
} }
@ -47,6 +52,40 @@ void ZigbeeNodeDeconz::setClusterAttributeReport(const ZigbeeClusterAttributeRep
void ZigbeeNodeDeconz::startInitialization() void ZigbeeNodeDeconz::startInitialization()
{ {
setState(StateInitializing);
// Get the node 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::NodeDescriptorRequest);
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);
ZigbeeNetworkReply *reply = m_network->sendRequest(request);
connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){
// TODO: check reply error
ZigbeeDeviceProfileAdpu adpu = ZigbeeDeviceProfile::parseAdpu(reply->responseData());
qCDebug(dcZigbeeNode()) << "Node descriptor request finished" << adpu;
setNodeDescriptorRawData(reply->responseData());
QDataStream stream(adpu.payload);
stream.setByteOrder(QDataStream::LittleEndian);
});
/* Node initialisation steps (sequentially) /* Node initialisation steps (sequentially)
* - Node descriptor * - Node descriptor
* - Power descriptor * - Power descriptor

View File

@ -32,7 +32,8 @@
#include "zigbee.h" #include "zigbee.h"
#include "zigbeenode.h" #include "zigbeenode.h"
#include "zigbeebridgecontrollerdeconz.h"
class ZigbeeNetworkDeconz;
class ZigbeeNodeDeconz : public ZigbeeNode class ZigbeeNodeDeconz : public ZigbeeNode
{ {
@ -41,12 +42,12 @@ class ZigbeeNodeDeconz : public ZigbeeNode
friend class ZigbeeNetworkDeconz; friend class ZigbeeNetworkDeconz;
public: public:
explicit ZigbeeNodeDeconz(ZigbeeBridgeControllerDeconz *controller, QObject *parent = nullptr); explicit ZigbeeNodeDeconz(ZigbeeNetworkDeconz *network, QObject *parent = nullptr);
void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) override; void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) override;
private: private:
ZigbeeBridgeControllerDeconz *m_controller = nullptr; ZigbeeNetworkDeconz *m_network = nullptr;
void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override; void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override;

View File

@ -23,7 +23,6 @@ SOURCES += \
zigbeechannelmask.cpp \ zigbeechannelmask.cpp \
zigbeecluster.cpp \ zigbeecluster.cpp \
zigbeeclusterattribute.cpp \ zigbeeclusterattribute.cpp \
zigbeedeviceobject.cpp \
zigbeedeviceprofile.cpp \ zigbeedeviceprofile.cpp \
zigbeemanufacturer.cpp \ zigbeemanufacturer.cpp \
zigbeenetwork.cpp \ zigbeenetwork.cpp \
@ -60,7 +59,6 @@ HEADERS += \
zigbeechannelmask.h \ zigbeechannelmask.h \
zigbeecluster.h \ zigbeecluster.h \
zigbeeclusterattribute.h \ zigbeeclusterattribute.h \
zigbeedeviceobject.h \
zigbeedeviceprofile.h \ zigbeedeviceprofile.h \
zigbeemanufacturer.h \ zigbeemanufacturer.h \
zigbeenetwork.h \ zigbeenetwork.h \

View File

@ -265,6 +265,13 @@ void ZigbeeNetworkNxp::readPermitJoinStatus()
}); });
} }
ZigbeeNetworkReply *ZigbeeNetworkNxp::sendRequest(const ZigbeeNetworkRequest &request)
{
Q_UNUSED(request)
qCCritical(dcZigbeeNetwork()) << "Cannot send request. Not implemented for this backend";
return nullptr;
}
ZigbeeNode *ZigbeeNetworkNxp::createNode(QObject *parent) ZigbeeNode *ZigbeeNetworkNxp::createNode(QObject *parent)
{ {
return new ZigbeeNodeNxp(m_controller, parent); return new ZigbeeNodeNxp(m_controller, parent);

View File

@ -62,6 +62,9 @@ private:
void readControllerVersion(); void readControllerVersion();
void readPermitJoinStatus(); void readPermitJoinStatus();
ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) override;
protected: protected:
ZigbeeNode *createNode(QObject *parent) override; ZigbeeNode *createNode(QObject *parent) override;
void setPermitJoiningInternal(bool permitJoining) override; void setPermitJoiningInternal(bool permitJoining) override;

View File

@ -1,33 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea-zigbee.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeedeviceobject.h"
ZigbeeDeviceObject::ZigbeeDeviceObject(QObject *parent) : QObject(parent)
{
}

View File

@ -1,43 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea-zigbee.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef ZIGBEEDEVICEOBJECT_H
#define ZIGBEEDEVICEOBJECT_H
#include <QObject>
class ZigbeeDeviceObject : public QObject
{
Q_OBJECT
public:
explicit ZigbeeDeviceObject(QObject *parent = nullptr);
signals:
};
#endif // ZIGBEEDEVICEOBJECT_H

View File

@ -26,3 +26,28 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeedeviceprofile.h" #include "zigbeedeviceprofile.h"
#include "zigbeeutils.h"
#include <QDataStream>
ZigbeeDeviceProfileAdpu ZigbeeDeviceProfile::parseAdpu(const QByteArray &adpu)
{
QDataStream stream(adpu);
stream.setByteOrder(QDataStream::LittleEndian);
ZigbeeDeviceProfileAdpu deviceAdpu;
quint8 statusFlag = 0;
stream >> deviceAdpu.sequenceNumber >> statusFlag >> deviceAdpu.addressOfInterest;
deviceAdpu.status = static_cast<Zigbee::ZigbeeStatus>(statusFlag);
deviceAdpu.payload = adpu.right(adpu.length() - 4);
return deviceAdpu;
}
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfileAdpu &deviceAdpu)
{
debug.nospace() << "DeviceAdpu(SQN: " << deviceAdpu.sequenceNumber << ", ";
debug.nospace() << deviceAdpu.status << ", ";
debug.nospace() << ZigbeeUtils::convertUint16ToHexString(deviceAdpu.addressOfInterest) << ", ";
debug.nospace() << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")";
return debug.space();
}

View File

@ -28,14 +28,23 @@
#ifndef ZIGBEEDEVICEPROFILE_H #ifndef ZIGBEEDEVICEPROFILE_H
#define ZIGBEEDEVICEPROFILE_H #define ZIGBEEDEVICEPROFILE_H
#include <QDebug>
#include <QObject> #include <QObject>
#include "zigbee.h"
typedef struct ZigbeeDeviceProfileAdpu {
quint8 sequenceNumber = 0;
Zigbee::ZigbeeStatus status = Zigbee::ZigbeeStatusSuccess;
quint16 addressOfInterest = 0;
QByteArray payload;
} ZigbeeDeviceProfileAdpu;
class ZigbeeDeviceProfile class ZigbeeDeviceProfile
{ {
Q_GADGET Q_GADGET
public: public:
enum ZdoCommand { enum ZdoCommand {
/* Requests */ /* Requests */
/*Device and service discovery */ /*Device and service discovery */
@ -136,9 +145,11 @@ public:
MgmtCacheResponse = 0x8037, MgmtCacheResponse = 0x8037,
MgmtNetworkUpdateResponse = 0x8038 MgmtNetworkUpdateResponse = 0x8038
}; };
Q_ENUM(ZdoCommand)
static ZigbeeDeviceProfileAdpu parseAdpu(const QByteArray &adpu);
}; };
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfileAdpu &deviceAdpu);
#endif // ZIGBEEDEVICEPROFILE_H #endif // ZIGBEEDEVICEPROFILE_H

View File

@ -378,6 +378,9 @@ void ZigbeeNetwork::saveNode(ZigbeeNode *node)
settings.beginGroup(node->extendedAddress().toString()); settings.beginGroup(node->extendedAddress().toString());
settings.setValue("nwkAddress", node->shortAddress()); settings.setValue("nwkAddress", node->shortAddress());
settings.setValue("macCapabilitiesFlag", node->m_macCapabilitiesFlag); settings.setValue("macCapabilitiesFlag", node->m_macCapabilitiesFlag);
settings.setValue("manufacturerCode", node->m_manufacturerCode);
settings.setValue("nodeDescriptorRawData", node->m_nodeDescriptorRawData); settings.setValue("nodeDescriptorRawData", node->m_nodeDescriptorRawData);
settings.setValue("powerDescriptorFlag", node->m_powerDescriptorFlag); settings.setValue("powerDescriptorFlag", node->m_powerDescriptorFlag);
@ -491,6 +494,26 @@ bool ZigbeeNetwork::networkConfigurationAvailable() const
return m_extendedPanId != 0 && m_channel != 0; return m_extendedPanId != 0 && m_channel != 0;
} }
ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest &request)
{
ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this);
// Make sure the reply will be deleted
connect(reply, &ZigbeeNetworkReply::finished, reply, &ZigbeeNetworkReply::deleteLater);
return reply;
}
void ZigbeeNetwork::setReplyResponseData(ZigbeeNetworkReply *reply, const QByteArray &responseData)
{
reply->m_responseData = responseData;
}
void ZigbeeNetwork::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error, Zigbee::ZigbeeStatus zigbeeStatus)
{
reply->m_error = error;
reply->m_zigbeeStatus = zigbeeStatus;
reply->finished();
}
void ZigbeeNetwork::onNodeStateChanged(ZigbeeNode::State state) void ZigbeeNetwork::onNodeStateChanged(ZigbeeNode::State state)
{ {
ZigbeeNode *node = qobject_cast<ZigbeeNode *>(sender()); ZigbeeNode *node = qobject_cast<ZigbeeNode *>(sender());

View File

@ -94,6 +94,8 @@ public:
bool permitJoining() const; bool permitJoining() const;
void setPermitJoining(bool permitJoining); void setPermitJoining(bool permitJoining);
// Network nodes
QList<ZigbeeNode *> nodes() const; QList<ZigbeeNode *> nodes() const;
ZigbeeNode *coordinatorNode() const; ZigbeeNode *coordinatorNode() const;
@ -150,6 +152,13 @@ protected:
bool networkConfigurationAvailable() const; bool networkConfigurationAvailable() const;
virtual ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) = 0;
// 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);
signals: signals:
void settingsFileNameChanged(const QString &settingsFileName); void settingsFileNameChanged(const QString &settingsFileName);
void serialPortNameChanged(const QString &serialPortName); void serialPortNameChanged(const QString &serialPortName);

View File

@ -42,6 +42,11 @@ Zigbee::ZigbeeStatus ZigbeeNetworkReply::zigbeeStatus() const
return m_zigbeeStatus; return m_zigbeeStatus;
} }
QByteArray ZigbeeNetworkReply::responseData() const
{
return m_responseData;
}
ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent) : ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent) :
QObject(parent), QObject(parent),
m_request(request) m_request(request)

View File

@ -37,20 +37,25 @@ class ZigbeeNetworkReply : public QObject
{ {
Q_OBJECT Q_OBJECT
friend class ZigbeeNetwork;
friend class ZigbeeNodeEndpoint; friend class ZigbeeNodeEndpoint;
public: public:
enum Error { enum Error {
ErrorNoError, ErrorNoError,
ErrorZigbeeStatusError, ErrorZigbeeStatusError,
ErrorInterfaceError,
ErrorNetworkOffline, ErrorNetworkOffline,
ErrorNetworkNotImplemented,
ErrorUnknown ErrorUnknown
}; };
Q_ENUM(Error) Q_ENUM(Error)
Error error() const; Error error() const;
ZigbeeNetworkRequest request() const; ZigbeeNetworkRequest request() const;
Zigbee::ZigbeeStatus zigbeeStatus() const; Zigbee::ZigbeeStatus zigbeeStatus() const;
QByteArray responseData() const;
private: private:
explicit ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr); explicit ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr);
@ -59,6 +64,7 @@ private:
bool m_finished = false; bool m_finished = false;
Error m_error = ErrorNoError; Error m_error = ErrorNoError;
Zigbee::ZigbeeStatus m_zigbeeStatus = Zigbee::ZigbeeStatusSuccess; Zigbee::ZigbeeStatus m_zigbeeStatus = Zigbee::ZigbeeStatusSuccess;
QByteArray m_responseData;
signals: signals:
void finished(); void finished();

View File

@ -156,20 +156,6 @@ private:
quint16 m_shortAddress = 0; quint16 m_shortAddress = 0;
ZigbeeAddress m_extendedAddress; ZigbeeAddress m_extendedAddress;
// Node descriptor information
QByteArray m_nodeDescriptorRawData;
NodeType m_nodeType = NodeTypeRouter;
FrequencyBand m_frequencyBand = FrequencyBand2400Mhz;
Relationship m_relationship = Parent;
quint16 m_manufacturerCode = 0;
bool m_complexDescriptorAvailable = false;
bool m_userDescriptorAvailable = false;
quint16 m_maximumRxSize = 0;
quint16 m_maximumTxSize = 0;
quint8 m_maximumBufferSize = 0;
// Server Mask // Server Mask
quint16 m_serverMask = 0; quint16 m_serverMask = 0;
bool m_isPrimaryTrustCenter = false; bool m_isPrimaryTrustCenter = false;
@ -208,6 +194,20 @@ protected:
QList<ZigbeeNodeEndpoint *> m_endpoints; QList<ZigbeeNodeEndpoint *> m_endpoints;
// Node descriptor information
QByteArray m_nodeDescriptorRawData;
NodeType m_nodeType = NodeTypeRouter;
FrequencyBand m_frequencyBand = FrequencyBand2400Mhz;
Relationship m_relationship = Parent;
quint16 m_manufacturerCode = 0;
bool m_complexDescriptorAvailable = false;
bool m_userDescriptorAvailable = false;
quint16 m_maximumRxSize = 0;
quint16 m_maximumTxSize = 0;
quint8 m_maximumBufferSize = 0;
void setState(State state); void setState(State state);
void setConnected(bool connected); void setConnected(bool connected);