This repository has been archived on 2026-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
powersync-zigbee/libnymea-zigbee/zigbeenetworkmanager.cpp
2020-02-27 19:08:58 +01:00

1413 lines
60 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* 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 "zigbeenetworkmanager.h"
#include "loggingcategory.h"
#include "zigbeeutils.h"
#include <QDateTime>
#include <QDataStream>
#include <QSettings>
ZigbeeNetworkManager::ZigbeeNetworkManager(QObject *parent) :
QObject(parent)
{
}
QString ZigbeeNetworkManager::controllerFirmwareVersion() const
{
return m_controllerFirmwareVersion;
}
ZigbeeBridgeController *ZigbeeNetworkManager::controller() const
{
return m_controller;
}
bool ZigbeeNetworkManager::networkRunning() const
{
return state() == ZigbeeNetwork::StateRunning;
}
bool ZigbeeNetworkManager::permitJoining() const
{
return m_permitJoining;
}
void ZigbeeNetworkManager::setPermitJoining(bool permitJoining)
{
if (m_permitJoining == permitJoining)
return;
ZigbeeInterfaceReply *reply = m_controller->commandPermitJoin(0, (permitJoining ? 255 : 0));
connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply, permitJoining](){
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully." << permitJoining;
// Read the permit joining status back in order to update the state
readPermitJoinStatus();
});
}
void ZigbeeNetworkManager::resetController()
{
ZigbeeInterfaceReply *reply = m_controller->commandResetController();
connect(reply, &ZigbeeInterfaceReply::finished, this, [reply](){
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
});
}
void ZigbeeNetworkManager::setStartingState(ZigbeeNetworkManager::StartingState state)
{
if (m_startingState == state)
return;
m_startingState = state;
switch (m_startingState) {
case StartingStateNone:
break;
case StartingStateErase: {
m_networkRunning = false;
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Erase persistant data";
ZigbeeInterfaceReply *reply = m_controller->commandErasePersistantData();
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandErasePersistentDataFinished);
break;
}
case StartingStateReset: {
m_networkRunning = false;
// qCDebug(dcZigbeeNetwork()) << "";
// ZigbeeInterfaceReply *reply = m_controller->commandSoftResetController();
// connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply](){
// reply->deleteLater();
// });
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Reset controller";
ZigbeeInterfaceReply *reply = m_controller->commandResetController();
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandResetControllerFinished);
break;
}
case StartingStateGetVersion: {
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Get controller version";
readControllerVersion();
break;
}
case StartingStateSetPanId: {
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Set PAN ID";
if (extendedPanId() == 0) {
setExtendedPanId(ZigbeeUtils::generateRandomPanId());
}
ZigbeeInterfaceReply *reply = m_controller->commandSetExtendedPanId(extendedPanId());
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSetExtendedPanIdFinished);
break;
}
case StartingStateSetChannel: {
// Create channel mask
// Note: normal number passed, that specific channel will be used || Bitfield: all channels would be 0x07FFF800
// 0x07fff800 select from all channels 11 - 26
// 0x02108800 primary zigbee light link channels 11, 15, 20, 25
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Set channel mask";
ZigbeeInterfaceReply *reply = nullptr;
if (channel() == 0) {
qCDebug(dcZigbeeNetwork()) << "Autoselect quitest channel for the zigbee network. FIXME: currently hardcoded to 13 due to firmware error.";
quint32 channelMask = 0;
channelMask |= 1 << (13);
reply = m_controller->commandSetChannelMask(channelMask);
} else {
quint32 channelMask = 0;
channelMask |= 1 << (channel());
qCDebug(dcZigbeeNetwork()) << "Using channel" << channel() << "for the zigbee network.";
reply = m_controller->commandSetChannelMask(channelMask);
}
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSetChannelMaskFinished);
break;
}
case StartingStateSetSecurity: {
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Set security configuration";
ZigbeeInterfaceReply *reply = m_controller->commandSetSecurityStateAndKey(4, 0, 1, "5A6967426565416C6C69616E63653039");
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSetSecurityFinished);
break;
}
case StartingStateSetNodeType: {
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Set node type";
ZigbeeInterfaceReply *reply = m_controller->commandSetNodeType(ZigbeeNode::NodeTypeCoordinator);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSetNodeTypeFinished);
break;
}
case StartingStateStartNetwork: {
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Starting network";
ZigbeeInterfaceReply *reply = m_controller->commandStartNetwork();
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandStartNetworkFinished);
break;
}
case StartingStateGetPermitJoinStatus: {
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Get permit join status";
readPermitJoinStatus();
break;
}
case StartingStateReadeNodeDescriptor: {
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Read coordinator node descriptor";
ZigbeeInterfaceReply *reply = m_controller->commandNodeDescriptorRequest(shortAddress());
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished);
break;
}
case StartingStateReadPowerDescriptor: {
qCDebug(dcZigbeeNetwork()) << "Starting state changed: Read coordinator power descriptor";
ZigbeeInterfaceReply *reply = m_controller->commandPowerDescriptorRequest(shortAddress());
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished);
break;
}
}
}
void ZigbeeNetworkManager::readControllerVersion()
{
ZigbeeInterfaceReply *reply = m_controller->commandGetVersion();
connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply](){
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
if (reply->additionalMessage().data().count() != 4) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << ":" << "Invalid payload size";
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
// Parse version
quint16 majorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(0, 2));
quint16 minorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(2, 2));
m_controllerFirmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
qCDebug(dcZigbeeNetwork()) << "Controller version:" << m_controllerFirmwareVersion;
if (m_startingState == StartingStateGetVersion) setStartingState(StartingStateSetPanId);
});
}
void ZigbeeNetworkManager::readPermitJoinStatus()
{
ZigbeeInterfaceReply *reply = m_controller->commandGetPermitJoinStatus();
connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply](){
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
m_permitJoining = static_cast<bool>(reply->additionalMessage().data().at(0));
emit permitJoiningChanged(m_permitJoining);
if (m_startingState == StartingStateGetPermitJoinStatus) setStartingState(StartingStateReadeNodeDescriptor);
});
}
//void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile)
//{
// // TargetAddress profile InputClusterCount InputClusterList OutputClusterCount OutputClusterList
// Q_UNUSED(profile)
// QByteArray data;
// QDataStream stream(&data, QIODevice::WriteOnly);
// stream << shortAddress;
// stream << static_cast<quint16>(0xFFFF);
// stream << static_cast<quint8>(0);
// stream << static_cast<quint16>(0);
// stream << static_cast<quint8>(0);
// stream << static_cast<quint16>(0);
// ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeMatchDescriptorRequest, data));
// request.setExpectedAdditionalMessageType(Zigbee::MessageTypeMatchDescriptorResponse);
// request.setDescription("Request match descriptors " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
// request.setTimoutIntervall(5000);
// ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestMatchDescriptorFinished);
//}
void ZigbeeNetworkManager::onCommandResetControllerFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
}
void ZigbeeNetworkManager::onCommandSoftResetControllerFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
}
void ZigbeeNetworkManager::onCommandErasePersistentDataFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
m_factoryResetting = false;
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
if (m_startingState == StartingStateErase) {
setStartingState(StartingStateReset);
}
}
void ZigbeeNetworkManager::onCommandSetExtendedPanIdFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
if (m_startingState == StartingStateSetPanId) setStartingState(StartingStateSetChannel);
}
void ZigbeeNetworkManager::onCommandSetChannelMaskFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeNetwork()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
if (m_startingState == StartingStateSetChannel) setStartingState(StartingStateSetSecurity);
}
void ZigbeeNetworkManager::onCommandSetNodeTypeFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
if (m_startingState == StartingStateSetNodeType) setStartingState(StartingStateStartNetwork);
}
void ZigbeeNetworkManager::onCommandStartNetworkFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeNetwork()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
processNetworkFormed(reply->additionalMessage());
if (m_startingState == StartingStateStartNetwork) setStartingState(StartingStateGetPermitJoinStatus);
}
void ZigbeeNetworkManager::onCommandStartScanFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
processNetworkFormed(reply->additionalMessage());
}
void ZigbeeNetworkManager::onCommandRequestMatchDescriptorFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
}
void ZigbeeNetworkManager::onCommandSetSecurityFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
if (m_startingState == StartingStateSetSecurity) setStartingState(StartingStateSetNodeType);
}
void ZigbeeNetworkManager::onCommandNetworkAddressRequestFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
quint8 statusCode = static_cast<quint8>(reply->additionalMessage().data().at(1));
quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(2, 8));
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(10, 2));
quint8 deviceCount = static_cast<quint8>(reply->additionalMessage().data().at(12));
quint8 startIndex = static_cast<quint8>(reply->additionalMessage().data().at(13));
qCDebug(dcZigbeeNetwork()) << "Network address response:";
qCDebug(dcZigbeeNetwork()) << " SQN:" << sequenceNumber;
qCDebug(dcZigbeeNetwork()) << " Status:" << statusCode;
qCDebug(dcZigbeeNetwork()) << " Address:" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress);
qCDebug(dcZigbeeNetwork()) << " Deice count:" << deviceCount;
qCDebug(dcZigbeeNetwork()) << " Start index:" << startIndex;
}
void ZigbeeNetworkManager::onCommandAuthenticateDeviceFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint64 gatewayIeeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(0, 8));
QString encryptedKey = reply->additionalMessage().data().mid(8, 16).toHex();
QByteArray mic = reply->additionalMessage().data().mid(24, 4);
quint64 initiatorIeeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(28, 8));
quint8 activeKeySequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(36));
quint8 channel = static_cast<quint8>(reply->additionalMessage().data().at(37));
quint16 shortPan = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(38, 2));
quint64 extendedPanId = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(40, 8));
qCDebug(dcZigbeeNetwork()) << "Authentication response:";
qCDebug(dcZigbeeNetwork()) << " Gateways address:" << ZigbeeAddress(gatewayIeeeAddress);
qCDebug(dcZigbeeNetwork()) << " Key:" << encryptedKey;
qCDebug(dcZigbeeNetwork()) << " MIC:" << mic.toHex();
qCDebug(dcZigbeeNetwork()) << " Initiator address:" << ZigbeeAddress(initiatorIeeeAddress);
qCDebug(dcZigbeeNetwork()) << " Active key sequence number:" << activeKeySequenceNumber;
qCDebug(dcZigbeeNetwork()) << " Channel:" << channel;
qCDebug(dcZigbeeNetwork()) << " Short PAN ID:" << ZigbeeUtils::convertUint16ToHexString(shortPan);
qCDebug(dcZigbeeNetwork()) << " Extended PAN ID:" << extendedPanId << ZigbeeUtils::convertUint64ToHexString(extendedPanId);
}
void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &message)
{
// Parse network status
QByteArray data = message.data();
quint8 networkStatus = static_cast<quint8>(data.at(0));
QString networkStatusString;
bool success = false;
if (networkStatus == 0) {
networkStatusString = "joined";
success = true;
} else if (networkStatus == 1) {
networkStatusString = "created";
success = true;
}
if (!success) {
qCWarning(dcZigbeeNetwork()) << "Forming network failed" << networkStatus << static_cast<Zigbee::ZigbeeNwkLayerStatus>(networkStatus);
setError(ErrorZigbeeError);
setStartingState(StartingStateNone);
setState(StateDisconnected);
m_networkRunning = false;
return;
}
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(data.mid(1, 2));
quint64 extendedAddress = ZigbeeUtils::convertByteArrayToUint64(data.mid(3, 8));
// Parse network channel
quint8 channel = static_cast<quint8>(data.at(11));
qCDebug(dcZigbeeNetwork()).noquote() << "Network" << networkStatusString;
qCDebug(dcZigbeeNetwork()) << " Extended PAN ID:" << extendedPanId();
qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(extendedAddress);
qCDebug(dcZigbeeNetwork()) << " Channel:" << channel;
qCDebug(dcZigbeeNetwork()) << " Permit joining:" << permitJoining();
m_networkRunning = true;
// Set the node information
setShortAddress(shortAddress);
setExtendedAddress(ZigbeeAddress(extendedAddress));
setChannel(channel);
if (!hasNode(this->shortAddress()))
addUnitializedNode(this);
}
void ZigbeeNetworkManager::onCommandEnableWhitelistFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
}
void ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished()
{
// ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
// reply->deleteLater();
// if (reply->status() != ZigbeeInterfaceReply::Success) {
// qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
// return;
// }
// qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
// qCDebug(dcZigbeeController()) << reply->additionalMessage();
// QByteArray data = reply->additionalMessage().data();
// quint8 sequenceNumber = 0;
// quint8 status = 0;
// quint16 shortAddress = 0;
// quint16 manufacturerCode = 0;
// quint16 maximalRxSize = 0;
// quint16 maximalTxSize = 0;
// quint16 serverMask = 0;
// quint8 descriptorFlag = 0;
// quint8 macFlags = 0;
// quint8 maxBufferSize = 0;
// quint16 bitField = 0;
// QDataStream stream(&data, QIODevice::ReadOnly);
// stream >> sequenceNumber;
// stream >> status;
// stream >> shortAddress;
// stream >> manufacturerCode;
// stream >> maximalRxSize;
// stream >> maximalTxSize;
// stream >> serverMask;
// stream >> descriptorFlag;
// stream >> macFlags;
// stream >> maxBufferSize;
// stream >> bitField;
// // Get node object
// ZigbeeNode *node = getZigbeeNode(shortAddress);
// if (!node) {
// qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
// return;
// }
// // Set node data
// node->setManufacturerCode(manufacturerCode);
// node->setMaximumRxSize(maximalRxSize);
// node->setMaximumTxSize(maximalTxSize);
// node->setMaximumBufferSize(maxBufferSize);
// node->setServerMask(serverMask);
// node->setMacCapabilitiesFlag(macFlags);
// node->setDescriptorFlag(descriptorFlag);
// // Parse bit field
// // 0-2 Bit = logical type, 0 = coordinator, 1 = router, 2 = end device
// if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
// node->setNodeType(NodeTypeCoordinator);
// } else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) {
// node->setNodeType(NodeTypeRouter);
// } else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
// node->setNodeType(NodeTypeEndDevice);
// }
// node->setComplexDescriptorAvailable((bitField >> 3) & 0x0001);
// node->setUserDescriptorAvailable((bitField >> 4) & 0x0001);
// qCDebug(dcZigbeeNetwork()) << "Node descriptor:";
// qCDebug(dcZigbeeNetwork()) << " Node type:" << node->nodeType();
// qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
// qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
// qCDebug(dcZigbeeNetwork()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
// qCDebug(dcZigbeeNetwork()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode);
// qCDebug(dcZigbeeNetwork()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(node->maximumRxSize());
// qCDebug(dcZigbeeNetwork()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(node->maximumTxSize());
// qCDebug(dcZigbeeNetwork()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(node->maximumBufferSize());
// qCDebug(dcZigbeeNetwork()) << " Server mask:" << ZigbeeUtils::convertUint16ToHexString(serverMask);
// qCDebug(dcZigbeeNetwork()) << " Primary Trust center:" << node->isPrimaryTrustCenter();
// qCDebug(dcZigbeeNetwork()) << " Backup Trust center:" << node->isBackupTrustCenter();
// qCDebug(dcZigbeeNetwork()) << " Primary Binding cache:" << node->isPrimaryBindingCache();
// qCDebug(dcZigbeeNetwork()) << " Backup Binding cache:" << node->isBackupBindingCache();
// qCDebug(dcZigbeeNetwork()) << " Primary Discovery cache:" << node->isPrimaryDiscoveryCache();
// qCDebug(dcZigbeeNetwork()) << " Backup Discovery cache:" << node->isBackupDiscoveryCache();
// qCDebug(dcZigbeeNetwork()) << " Network Manager:" << node->isNetworkManager();
// qCDebug(dcZigbeeNetwork()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorFlag);
// qCDebug(dcZigbeeNetwork()) << " Extended active endpoint list available:" << node->extendedActiveEndpointListAvailable();
// qCDebug(dcZigbeeNetwork()) << " Extended simple descriptor list available:" << node->extendedSimpleDescriptorListAvailable();
// qCDebug(dcZigbeeNetwork()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macFlags);
// qCDebug(dcZigbeeNetwork()) << " Alternate PAN coordinator:" << node->alternatePanCoordinator();
// qCDebug(dcZigbeeNetwork()) << " Device type:" << node->deviceType();
// qCDebug(dcZigbeeNetwork()) << " Power source flag main power:" << node->powerSourceFlagMainPower();
// qCDebug(dcZigbeeNetwork()) << " Receiver on when idle:" << node->receiverOnWhenIdle();
// qCDebug(dcZigbeeNetwork()) << " Security capability:" << node->securityCapability();
// qCDebug(dcZigbeeNetwork()) << " Allocate address:" << node->allocateAddress();
// qCDebug(dcZigbeeNetwork()) << " Bit field:" << ZigbeeUtils::convertUint16ToHexString(bitField);
// qCDebug(dcZigbeeNetwork()) << " Complex desciptor available:" << node->complexDescriptorAvailable();
// qCDebug(dcZigbeeNetwork()) << " User desciptor available:" << node->userDescriptorAvailable();
// if (m_startingState == StartingStateReadeNodeDescriptor) setStartingState(StartingStateReadPowerDescriptor);
}
void ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
QByteArray data = reply->additionalMessage().data();
quint8 sequenceNumber = 0;
quint8 status = 0;
quint16 shortAddress = 0;
quint8 length = 0;
quint8 endPoint = 0;
quint16 profileId = 0;
quint16 deviceId = 0;
quint8 bitField = 0;
quint8 inputClusterCount = 0;
quint8 outputClusterCount = 0;
QDataStream stream(&data, QIODevice::ReadOnly);
stream >> sequenceNumber;
stream >> status;
stream >> shortAddress;
stream >> length;
if (length == 0) {
qCWarning(dcZigbeeNetwork()) << "Simple node descriptior has a length of 0.";
return;
}
stream >> endPoint;
stream >> profileId;
stream >> deviceId;
stream >> bitField;
qCDebug(dcZigbeeNetwork()) << "Node simple descriptor:";
qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
qCDebug(dcZigbeeNetwork()) << " Nwk address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNetwork()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length);
qCDebug(dcZigbeeNetwork()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endPoint);
qCDebug(dcZigbeeNetwork()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
if (profileId == Zigbee::ZigbeeProfileLightLink) {
qCDebug(dcZigbeeNetwork()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::LightLinkDevice>(deviceId);
} else {
qCDebug(dcZigbeeNetwork()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast<Zigbee::HomeAutomationDevice>(deviceId);
}
qCDebug(dcZigbeeNetwork()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField);
stream >> inputClusterCount;
qCDebug(dcZigbeeNetwork()) << " Input clusters: (" << inputClusterCount << ")";
for (int i = 0; i < inputClusterCount; i+=1) {
quint16 clusterId = 0;
stream >> clusterId;
qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
}
stream >> outputClusterCount;
qCDebug(dcZigbeeNetwork()) << " Output clusters: (" << outputClusterCount << ")";
for (int i = 0; i < outputClusterCount; i+=1) {
if (stream.atEnd()) {
qCWarning(dcZigbeeNode()) << "Data stream already at the end but more data expected. Looks like the firmware doesn't provide more data.";
break;
}
quint16 clusterId = 0;
stream >> clusterId;
qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
}
// Get node object
ZigbeeNode *node = getZigbeeNode(shortAddress);
if (!node) {
qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
return;
}
// // Set node data
// node->setEndPoint(endPoint);
// node->setZigbeeProfile(static_cast<Zigbee::ZigbeeProfile>(profileId));
// node->setDeviceId(deviceId);
}
void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished()
{
// ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
// reply->deleteLater();
// // Note: get the short address from the request data
// QByteArray requestData = reply->request().message().data();
// quint16 shortAddress;
// QDataStream stream(&requestData, QIODevice::ReadOnly);
// stream >> shortAddress;
// if (reply->status() != ZigbeeInterfaceReply::Success) {
// qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
// // Note: the power descriptor is the last request from the initialization
// ZigbeeNode *node = getZigbeeNode(shortAddress);
// if (!node) {
// qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
// return;
// }
// if (node->state() != ZigbeeNode::StateInitialized) {
// node->setState(ZigbeeNode::StateInitialized);
// }
// return;
// }
// qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
// qCDebug(dcZigbeeController()) << reply->additionalMessage();
// quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
// quint8 status = static_cast<quint8>(reply->additionalMessage().data().at(1));
// quint16 bitField = static_cast<quint16>(reply->additionalMessage().data().at(2));
// bitField <<= 8;
// bitField |= static_cast<quint8>(reply->additionalMessage().data().at(3));
// // Bit 0 - 3 Power mode
// // 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor
// // 0001: Receiver switched on periodically
// // 0010: Receiver switched on when stimulated, e.g. by pressing a button
// ZigbeeNode::PowerMode powerMode = PowerModeAlwaysOn;
// if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
// powerMode = PowerModeAlwaysOn;
// } else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
// powerMode = PowerModeOnPeriodically;
// } else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) {
// powerMode = PowerModeOnWhenStimulated;
// }
// // Bit 4 - 7 Available power sources
// // Bit 0: Permanent mains supply
// // Bit 1: Rechargeable battery
// // Bit 2: Disposable battery
// // Bit 4: Reserved
// QList<ZigbeeNode::PowerSource> availablePowerSources;
// if (ZigbeeUtils::checkBitUint16(bitField, 4)) {
// availablePowerSources.append(PowerSourcePermanentMainSupply);
// } else if (ZigbeeUtils::checkBitUint16(bitField, 5)) {
// availablePowerSources.append(PowerSourceRecharchableBattery);
// } else if (ZigbeeUtils::checkBitUint16(bitField, 6)) {
// availablePowerSources.append(PowerSourceDisposableBattery);
// }
// // Bit 8 - 11 Active source: according to the same schema as available power sources
// ZigbeeNode::PowerSource powerSource = PowerSourcePermanentMainSupply;
// if (ZigbeeUtils::checkBitUint16(bitField, 8)) {
// powerSource = PowerSourcePermanentMainSupply;
// } else if (ZigbeeUtils::checkBitUint16(bitField, 9)) {
// powerSource = PowerSourceRecharchableBattery;
// } else if (ZigbeeUtils::checkBitUint16(bitField, 10)) {
// powerSource = PowerSourceDisposableBattery;
// }
// // Bit 12 - 15: Battery level if available
// // 0000: Critically low
// // 0100: Approximately 33%
// // 1000: Approximately 66%
// // 1100: Approximately 100% (near fully charged)
// ZigbeeNode::PowerLevel powerLevel = PowerLevelCriticalLow;
// if (!ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) {
// powerLevel = PowerLevelCriticalLow;
// } else if (ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) {
// powerLevel = PowerLevelLow;
// } else if (!ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) {
// powerLevel = PowerLevelOk;
// } else if (ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) {
// powerLevel = PowerLevelFull;
// }
// qCDebug(dcZigbeeNetwork()) << "Node power descriptor:";
// qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
// qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
// qCDebug(dcZigbeeNetwork()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField);
// qCDebug(dcZigbeeNetwork()) << " Power mode:" << m_powerMode;
// qCDebug(dcZigbeeNetwork()) << " Available power sources:";
// foreach (const PowerSource &source, availablePowerSources) {
// qCDebug(dcZigbeeNetwork()) << " " << source;
// }
// qCDebug(dcZigbeeNetwork()) << " Power source:" << powerSource;
// qCDebug(dcZigbeeNetwork()) << " Power level:" << powerLevel;
// // Get node object
// ZigbeeNode *node = getZigbeeNode(shortAddress);
// if (!node) {
// qCWarning(dcZigbeeNetwork()) << "Could not find node for address" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
// return;
// }
// // Set node data
//// node->setPowerMode(powerMode);
//// node->setPowerSource(powerSource);
//// node->setAvailablePowerSources(availablePowerSources);
//// node->setPowerLevel(powerLevel);
// // Note: the power descriptor is the last request from the initialization
// if (node->state() != ZigbeeNode::StateInitialized) {
// node->setState(ZigbeeNode::StateInitialized);
// }
// // Note: the power descriptor request for the coordinator is the last step from the network init process
// if (m_startingState == StartingStateReadPowerDescriptor) {
// setStartingState(StartingStateNone);
// setState(StateRunning);
// readControllerVersion();
// foreach (ZigbeeNode *node, nodes()) {
// node->setConnected(true);
// }
// }
}
void ZigbeeNetworkManager::onCommandInitiateTouchLinkFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
}
void ZigbeeNetworkManager::onCommandTouchLinkFactoryResetFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
}
void ZigbeeNetworkManager::onCommandRequestLinkQualityFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
quint8 statusCode = static_cast<quint8>(reply->additionalMessage().data().at(1));
quint8 neighborTableEntries = static_cast<quint8>(reply->additionalMessage().data().at(2));
quint8 neighborTableListCount = static_cast<quint8>(reply->additionalMessage().data().at(3));
quint8 startIndex = static_cast<quint8>(reply->additionalMessage().data().at(4));
qCDebug(dcZigbeeNetwork()) << "LQI response:";
qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(statusCode);
qCDebug(dcZigbeeNetwork()) << " Neighbor table entries:" << neighborTableEntries;
qCDebug(dcZigbeeNetwork()) << " Neighbor table list count:" << neighborTableListCount;
qCDebug(dcZigbeeNetwork()) << " Start index:" << startIndex;
int offset = 5;
// Note: according to docs, if the table has no neigbors the list will be empty
if (neighborTableEntries == 0) {
qCDebug(dcZigbeeNetwork()) << " There are no neigbors";
return;
}
for (int i = startIndex; i < neighborTableListCount; i++) {
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(offset, 2));
quint64 panId = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(offset + 2, 8));
quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(offset + 10, 8));
quint8 depth = static_cast<quint8>(reply->additionalMessage().data().at(offset + 18));
quint8 linkQuality = static_cast<quint8>(reply->additionalMessage().data().at(offset + 19));
quint8 bitMap = static_cast<quint8>(reply->additionalMessage().data().at(offset + 20));
offset += 21;
qCDebug(dcZigbeeNetwork()) << " Neighbor:" << i;
qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNetwork()) << " PAN id:" << panId;
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress);
qCDebug(dcZigbeeNetwork()) << " Depth:" << depth;
qCDebug(dcZigbeeNetwork()) << " Link quality:" << linkQuality;
qCDebug(dcZigbeeNetwork()) << " BitMap:" << ZigbeeUtils::convertByteToHexString(bitMap);
foreach (ZigbeeNode *node, nodes()) {
if (node->extendedAddress() == ZigbeeAddress(ieeeAddress)) {
node->setShortAddress(shortAddress);
}
}
}
}
void ZigbeeNetworkManager::processLoggingMessage(const ZigbeeInterfaceMessage &message)
{
quint8 logLevel = static_cast<quint8>(message.data().at(0));
QString logMessage = QString::fromUtf8(message.data().right(message.data().count() - 1));
QString logLevelString;
switch (logLevel) {
case 0:
logLevelString = "Emergency:";
break;
case 1:
logLevelString = "Alert:";
break;
case 2:
logLevelString = "Critical:";
break;
case 3:
logLevelString = "Error:";
break;
case 4:
logLevelString = "Warning:";
break;
case 5:
logLevelString = "Notice:";
break;
case 6:
logLevelString = "Information:";
break;
case 7:
logLevelString = "Debug:";
break;
default:
logLevelString = "Unknown:";
break;
}
if (logLevel < 5) {
qCWarning(dcZigbeeController()).noquote() << "ControllerLog:" << logLevelString << logMessage;
} else {
qCDebug(dcZigbeeController()).noquote() << "ControllerLog:" << logLevelString << logMessage;
}
}
void ZigbeeNetworkManager::processFactoryNewRestart(const ZigbeeInterfaceMessage &message)
{
quint8 controllerStatus = static_cast<quint8>(message.data().at(0));
QString controllerStatusString;
switch (controllerStatus) {
case 0:
controllerStatusString = "startup";
break;
case 1:
controllerStatusString = "wait start";
break;
case 2:
controllerStatusString = "NRF start";
break;
case 3:
controllerStatusString = "discovery";
break;
case 4:
controllerStatusString = "network init";
break;
case 5:
controllerStatusString = "rescan";
break;
case 6:
controllerStatusString = "running";
break;
default:
qCWarning(dcZigbeeNetwork()) << "Unhandled controller status" << controllerStatus;
break;
}
qCDebug(dcZigbeeNetwork()) << "Restart finished. Current controller state:" << controllerStatusString;
if (m_startingState == StartingStateReset) setStartingState(StartingStateGetVersion);
}
void ZigbeeNetworkManager::processNodeClusterList(const ZigbeeInterfaceMessage &message)
{
quint8 sourceEndpoint = static_cast<quint8>(message.data().at(0));
quint16 profileId = static_cast<quint8>(message.data().at(1));
profileId <<= 8;
profileId |= static_cast<quint8>(message.data().at(2));
qCDebug(dcZigbeeController()) << "Node cluster list received:";
qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint;
qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
QByteArray clusterListData = message.data().right(message.data().count() - 3);
for (int i = 0; i < clusterListData.count(); i += 2) {
quint16 clusterId = static_cast<quint16>(clusterListData.at(i));
clusterId <<= 8;
clusterId |= clusterListData .at(i + 1);
qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
}
}
void ZigbeeNetworkManager::processNodeAttributeList(const ZigbeeInterfaceMessage &message)
{
quint8 sourceEndpoint = static_cast<quint8>(message.data().at(0));
quint16 profileId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2));
quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(3, 2));
qCDebug(dcZigbeeController()) << "Node attribute list received:";
qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint;
qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
QByteArray attributeListData = message.data().right(message.data().count() - 5);
if (attributeListData.count() % 2 != 0) {
qCWarning(dcZigbeeController()) << "Attribute list is incomplete. Truncate last byte";
attributeListData = attributeListData.left(attributeListData.count() - 1);
}
qCWarning(dcZigbeeController()) << "Attributes" << ZigbeeUtils::convertByteArrayToHexString(attributeListData);
for (int i = 0; i < attributeListData.count(); i += 2) {
quint16 attribute = ZigbeeUtils::convertByteArrayToUint16(attributeListData.mid(i, 2));
qCDebug(dcZigbeeController()) << " Attribute:" << ZigbeeUtils::convertUint16ToHexString(attribute);
}
}
void ZigbeeNetworkManager::processNodeCommandIdList(const ZigbeeInterfaceMessage &message)
{
quint8 sourceEndpoint = static_cast<quint8>(message.data().at(0));
quint16 profileId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2));
quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(3, 2));
qCDebug(dcZigbeeController()) << "Node command list received:";
qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint;
qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
QByteArray commandListData = message.data().right(message.data().count() - 5);
for (int i = 0; i < commandListData.count(); i++) {
quint8 attribute = static_cast<quint8>(commandListData.at(i));
qCDebug(dcZigbeeController()) << " Command:" << ZigbeeUtils::convertByteToHexString(attribute);
}
}
void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &message)
{
QByteArray data = message.data();
quint16 shortAddress = 0;
quint64 ieeeAddress = 0;
quint8 macCapabilitiesFlag = 0;
QDataStream stream(&data, QIODevice::ReadOnly);
stream >> shortAddress >> ieeeAddress >> macCapabilitiesFlag;
qCDebug(dcZigbeeNetwork()) << "Device announced:";
qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress);
qCDebug(dcZigbeeNetwork()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapabilitiesFlag);
// Check if we already have a node with this
// ZigbeeNode *node = createNode();
// node->setShortAddress(shortAddress);
// node->setExtendedAddress(ZigbeeAddress(ieeeAddress));
// node->setMacCapabilitiesFlag(macCapabilitiesFlag);
// qCDebug(dcZigbeeNetwork()) << " Node:" << node;
// // FIXME: check if node already added, and if we have to update it
// addUnitializedNode(node);
// node->setState(StateInitializing);
// ZigbeeInterfaceReply *reply = nullptr;
// reply = m_controller->commandAuthenticateDevice(node->extendedAddress(), securityConfiguration().globalTrustCenterLinkKey());
// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandAuthenticateDeviceFinished);
// reply = m_controller->commandNodeDescriptorRequest(node->shortAddress());
// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished);
// reply = m_controller->commandSimpleDescriptorRequest(node->shortAddress(), endPoint());
// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished);
// reply = m_controller->commandPowerDescriptorRequest(node->shortAddress());
// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished);
}
void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &message)
{
QByteArray data = message.data();
quint8 sequenceNumber = 0;
quint16 sourceAddress = 0;
quint8 endPoint = 0;
quint16 clusterId = 0;
quint16 attributeId = 0;
quint8 attributeStatus = 0;
quint8 attributDataType = 0;
quint16 dataSize = 0;
QDataStream stream(&data, QIODevice::ReadOnly);
stream >> sequenceNumber >> sourceAddress >> endPoint >> clusterId >> attributeId >> attributeStatus >> attributDataType >> dataSize;
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(attributDataType);
QByteArray attributeData = data.right(dataSize);
if (attributeData.length() != dataSize) {
qCCritical(dcZigbeeNetwork()) << "HACK" << attributeData.length() << "!=" << dataSize;
// Note: the NXP firmware for JN5169 has a bug here and does not send the attributeStatus.
// Repars data without attribute status
sequenceNumber = 0;
sourceAddress = 0;
endPoint = 0;
clusterId = 0;
attributeId = 0;
attributeStatus = 0;
attributDataType = 0;
dataSize = 0;
QDataStream alternativeStream(&data, QIODevice::ReadOnly);
alternativeStream >> sequenceNumber >> sourceAddress >> endPoint >> clusterId >> attributeId >> attributDataType >> dataSize;
dataType = static_cast<Zigbee::DataType>(attributDataType);
attributeData = data.right(dataSize);
}
qCDebug(dcZigbeeNetwork()) << "Attribute report:";
qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbeeNetwork()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceAddress);
qCDebug(dcZigbeeNetwork()) << " End point:" << ZigbeeUtils::convertByteToHexString(endPoint);
qCDebug(dcZigbeeNetwork()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
qCDebug(dcZigbeeNetwork()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId);
qCDebug(dcZigbeeNetwork()) << " Attribut data type:" << dataType;
qCDebug(dcZigbeeNetwork()) << " Attribut size:" << dataSize;
qCDebug(dcZigbeeNetwork()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(attributeData);
switch (dataType) {
case Zigbee::CharString:
qCDebug(dcZigbeeNetwork()) << " Data(converted)" << QString::fromUtf8(attributeData);
break;
case Zigbee::Bool:
qCDebug(dcZigbeeNetwork()) << " Data(converted)" << static_cast<bool>(attributeData.at(0));
break;
default:
break;
}
ZigbeeNode *node = getZigbeeNode(sourceAddress);
if (!node) {
qCWarning(dcZigbeeNode()) << "Received an attribute report from an unknown node. Ignoring data.";
return;
}
node->setClusterAttribute(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeClusterAttribute(attributeId, dataType, attributeData));
}
void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &message)
{
QByteArray data = message.data();
quint64 extendedAddress = 0;
bool rejoining = 0;
QDataStream stream(&data, QIODevice::ReadOnly);
stream >> extendedAddress;
stream >> rejoining;
ZigbeeAddress address(extendedAddress);
qCDebug(dcZigbeeNetwork()) << "Node leaving indication:" << address.toString() << "rejoining:" << rejoining;
ZigbeeNode *node = getZigbeeNode(address);
if (node) removeNode(node);
}
void ZigbeeNetworkManager::processRestartProvisioned(const ZigbeeInterfaceMessage &message)
{
if (message.data().isEmpty())
return;
quint8 status = static_cast<quint8>(message.data().at(0));
switch (status) {
case 0:
qCDebug(dcZigbeeNetwork()) << "Restart provisioned: start up";
break;
case 1:
qCDebug(dcZigbeeNetwork()) << "Restart provisioned: wait start";
break;
case 2:
qCDebug(dcZigbeeNetwork()) << "Restart provisioned: NFN start";
break;
case 3:
qCDebug(dcZigbeeNetwork()) << "Restart provisioned: discovery";
break;
case 4:
qCDebug(dcZigbeeNetwork()) << "Restart provisioned: network init";
break;
case 5:
qCDebug(dcZigbeeNetwork()) << "Restart provisioned: rescan";
break;
case 6:
qCDebug(dcZigbeeNetwork()) << "Restart provisioned: running";
break;
default:
qCDebug(dcZigbeeNetwork()) << "Restart provisioned: unknown";
break;
}
if (m_startingState == StartingStateReset) {
if (m_networkRunning) {
qCDebug(dcZigbeeNetwork()) << "Reset finished. Network already running. No need to set it up";
setStartingState(StartingStateGetPermitJoinStatus);
} else {
qCDebug(dcZigbeeNetwork()) << "Reset finished. Set up network";
setStartingState(StartingStateGetVersion);
}
}
}
void ZigbeeNetworkManager::processRouterDiscoveryConfirm(const ZigbeeInterfaceMessage &message)
{
if (message.data().isEmpty())
return;
quint8 status = static_cast<quint8>(message.data().at(0));
Zigbee::ZigbeeNwkLayerStatus networkStatus = static_cast<Zigbee::ZigbeeNwkLayerStatus>(message.data().at(0));
qCDebug(dcZigbeeNetwork()) << "Router discovery confirm received" << status << networkStatus;
}
void ZigbeeNetworkManager::startNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Start network...";
if (m_controller) {
qCDebug(dcZigbeeNetwork()) << "Clean up old controller...";
delete m_controller;
m_controller = nullptr;
}
qCDebug(dcZigbeeNetwork()) << "Create new controller...";
m_controller = new ZigbeeBridgeController(this);
connect(m_controller, &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived);
connect(m_controller, &ZigbeeBridgeController::availableChanged, this, &ZigbeeNetworkManager::onControllerAvailableChanged);
if (state() == StateUninitialized)
loadNetwork();
if (!m_controller->enable(serialPortName(), serialBaudrate())) {
setState(StateDisconnected);
setStartingState(StartingStateNone);
setError(ErrorHardwareUnavailable);
} else {
// Reset
setStartingState(StartingStateReset);
setState(StateStarting);
}
}
void ZigbeeNetworkManager::stopNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Stopping network...";
setState(StateStopping);
if (m_controller) {
delete m_controller;
m_controller = nullptr;
}
setStartingState(StartingStateNone);
setState(StateDisconnected);
setError(ErrorNoError);
}
void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &message)
{
switch (message.messageType()) {
case Zigbee::MessageTypeLogging:
processLoggingMessage(message);
break;
case Zigbee::MessageTypeFactoryNewRestart:
processFactoryNewRestart(message);
break;
case Zigbee::MessageTypeNodeClusterList:
processNodeClusterList(message);
break;
case Zigbee::MessageTypeNodeAttributeList:
processNodeAttributeList(message);
break;
case Zigbee::MessageTypeNodeCommandIdList:
processNodeCommandIdList(message);
break;
case Zigbee::MessageTypeDeviceAnnounce:
processDeviceAnnounce(message);
break;
case Zigbee::MessageTypeAttributeReport:
processAttributeReport(message);
break;
case Zigbee::MessageTypeLeaveIndication:
processLeaveIndication(message);
break;
case Zigbee::MessageTypeNetworkJoinedFormed:
processNetworkFormed(message);
break;
case Zigbee::MessageTypeRestartProvisioned:
processRestartProvisioned(message);
break;
case Zigbee::MessageTypeRouterDiscoveryConfirm:
processRouterDiscoveryConfirm(message);
break;
default:
qCWarning(dcZigbeeController()) << "Unhandled message received:" << message;
break;
}
}
void ZigbeeNetworkManager::onControllerAvailableChanged(bool available)
{
qCDebug(dcZigbeeNetwork()) << "Hardware controller is" << (available ? "now available" : "not available");
if (m_factoryResetting && !available) {
setStartingState(StartingStateReset);
return;
}
if (!available) {
foreach (ZigbeeNode *node, nodes()) {
node->setConnected(false);
}
setError(ErrorHardwareUnavailable);
setState(StateDisconnected);
setStartingState(StartingStateNone);
} else {
setError(ErrorNoError);
setState(StateStarting);
setStartingState(StartingStateReset);
}
}
void ZigbeeNetworkManager::factoryResetNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Factory reset network and forget all information. This cannot be undone.";
clearSettings();
setState(StateStarting);
setStartingState(StartingStateErase);
}