From 080e89cf94e6e6cce8b429556f8a83513f391465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 28 Feb 2020 17:28:49 +0100 Subject: [PATCH] Restore basic node adding and start node initialization --- .../nxp/interface/zigbeeinterface.cpp | 2 +- .../nxp/zigbeebridgecontrollernxp.cpp | 2 +- .../nxp/zigbeebridgecontrollernxp.h | 2 +- libnymea-zigbee/nxp/zigbeenetworknxp.cpp | 194 +++++++++++------- libnymea-zigbee/nxp/zigbeenetworknxp.h | 5 +- libnymea-zigbee/nxp/zigbeenodenxp.cpp | 101 ++++++++- libnymea-zigbee/nxp/zigbeenodenxp.h | 27 ++- libnymea-zigbee/zigbeenetwork.cpp | 184 ++++++++--------- libnymea-zigbee/zigbeenetwork.h | 11 +- libnymea-zigbee/zigbeenetworkmanager.cpp | 37 +--- libnymea-zigbee/zigbeenetworkmanager.h | 22 +- libnymea-zigbee/zigbeenode.cpp | 5 + libnymea-zigbee/zigbeenode.h | 8 +- 13 files changed, 359 insertions(+), 241 deletions(-) diff --git a/libnymea-zigbee/nxp/interface/zigbeeinterface.cpp b/libnymea-zigbee/nxp/interface/zigbeeinterface.cpp index 27176de..455ac5c 100644 --- a/libnymea-zigbee/nxp/interface/zigbeeinterface.cpp +++ b/libnymea-zigbee/nxp/interface/zigbeeinterface.cpp @@ -222,7 +222,7 @@ void ZigbeeInterface::onReadyRead() void ZigbeeInterface::onError(const QSerialPort::SerialPortError &error) { if (error != QSerialPort::NoError && m_serialPort->isOpen()) { - qCCritical(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString(); + qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString(); m_reconnectTimer->start(); m_serialPort->close(); setAvailable(false); diff --git a/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.cpp b/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.cpp index 0eccc7e..882b965 100644 --- a/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.cpp +++ b/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.cpp @@ -190,7 +190,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandGetPermitJoinStatus() return sendRequest(request); } -ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandRequestActiveEndpoints(quint16 shortAddress) +ZigbeeInterfaceReply *ZigbeeBridgeControllerNxp::commandActiveEndpointsRequest(quint16 shortAddress) { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); diff --git a/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.h b/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.h index debf665..3cafdce 100644 --- a/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.h +++ b/libnymea-zigbee/nxp/zigbeebridgecontrollernxp.h @@ -59,7 +59,7 @@ public: ZigbeeInterfaceReply *commandStartScan(); ZigbeeInterfaceReply *commandPermitJoin(quint16 targetAddress = 0xfffc, const quint8 advertisingIntervall = 180, bool tcSignificance = false); ZigbeeInterfaceReply *commandGetPermitJoinStatus(); - ZigbeeInterfaceReply *commandRequestActiveEndpoints(quint16 shortAddress); + ZigbeeInterfaceReply *commandActiveEndpointsRequest(quint16 shortAddress); ZigbeeInterfaceReply *commandRequestLinkQuality(quint16 shortAddress); ZigbeeInterfaceReply *commandEnableWhiteList(); ZigbeeInterfaceReply *commandInitiateTouchLink(); diff --git a/libnymea-zigbee/nxp/zigbeenetworknxp.cpp b/libnymea-zigbee/nxp/zigbeenetworknxp.cpp index fcdc77b..0ab2c1c 100644 --- a/libnymea-zigbee/nxp/zigbeenetworknxp.cpp +++ b/libnymea-zigbee/nxp/zigbeenetworknxp.cpp @@ -2,6 +2,8 @@ #include "../loggingcategory.h" #include "../zigbeeutils.h" +#include "zigbeenodenxp.h" + #include ZigbeeNetworkNxp::ZigbeeNetworkNxp(QObject *parent) : @@ -155,7 +157,18 @@ void ZigbeeNetworkNxp::setStartingState(ZigbeeNetworkNxp::StartingState state) case StartingStateStartNetwork: { qCDebug(dcZigbeeNetwork()) << "Starting state changed: Starting network"; ZigbeeInterfaceReply *reply = m_controller->commandStartNetwork(); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkNxp::onCommandStartNetworkFinished); + connect(reply, &ZigbeeInterfaceReply::finished, this, [this, reply](){ + 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()); + }); break; } case StartingStateReadeNodeDescriptor: { @@ -221,6 +234,36 @@ void ZigbeeNetworkNxp::readPermitJoinStatus() }); } +ZigbeeNode *ZigbeeNetworkNxp::createNode(QObject *parent) +{ + return new ZigbeeNodeNxp(m_controller, parent); +} + +void ZigbeeNetworkNxp::setPermitJoiningInternal(bool permitJoining) +{ + // Note: 0xfffc = all routers + qCDebug(dcZigbeeNetwork()) << "Send request to" << (permitJoining ? "enable" : "disable") << "permit joining network."; + ZigbeeInterfaceReply *reply = m_controller->commandPermitJoin(0xfffc, (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"; + qCDebug(dcZigbeeController()) << reply->additionalMessage(); + + if (m_permitJoining == permitJoining) + return; + + qCDebug(dcZigbeeNetwork()) << "Permit joining changed to" << permitJoining; + m_permitJoining = permitJoining; + emit permitJoiningChanged(m_permitJoining); + }); +} + void ZigbeeNetworkNxp::onCommandInitiateTouchLinkFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); @@ -398,6 +441,8 @@ void ZigbeeNetworkNxp::processNodeClusterList(const ZigbeeInterfaceMessage &mess profileId <<= 8; profileId |= static_cast(message.data().at(2)); + // FIXME: + return; qCDebug(dcZigbeeController()) << "Node cluster list received:"; qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint; qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); @@ -418,10 +463,14 @@ void ZigbeeNetworkNxp::processNodeAttributeList(const ZigbeeInterfaceMessage &me { quint8 sourceEndpoint = static_cast(message.data().at(0)); + quint16 profileId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2)); quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(3, 2)); + // FIXME: + return; qCDebug(dcZigbeeController()) << "Node attribute list received:"; + qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint; qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); @@ -445,6 +494,8 @@ void ZigbeeNetworkNxp::processNodeCommandIdList(const ZigbeeInterfaceMessage &me quint16 profileId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2)); quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(3, 2)); + // FIXME: + return; qCDebug(dcZigbeeController()) << "Node command list received:"; qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint; qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); @@ -469,39 +520,37 @@ void ZigbeeNetworkNxp::processDeviceAnnounce(const ZigbeeInterfaceMessage &messa QDataStream stream(&data, QIODevice::ReadOnly); stream >> shortAddress >> ieeeAddress >> macCapabilitiesFlag; + ZigbeeAddress nodeIeeeAddress(ieeeAddress); + qCDebug(dcZigbeeNetwork()) << "Device announced:"; qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); - qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress); + qCDebug(dcZigbeeNetwork()) << " Extended address:" << nodeIeeeAddress; qCDebug(dcZigbeeNetwork()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapabilitiesFlag); // Check if we already have a node with this + if (hasNode(nodeIeeeAddress)) { + qCDebug(dcZigbeeNetwork()) << "Node already registered in the network."; + ZigbeeNode *node = getZigbeeNode(nodeIeeeAddress); + if (node->shortAddress() != shortAddress) { + qCWarning(dcZigbeeNetwork()) << "The node changed the NWK address from" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress()) << "to" << ZigbeeUtils::convertUint16ToHexString(shortAddress); + // FIMXE: check if we should reinitialize the node + } + return; + } - // 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); + ZigbeeNodeNxp *node = new ZigbeeNodeNxp(m_controller, this); + node->setShortAddress(shortAddress); + node->setExtendedAddress(ZigbeeAddress(ieeeAddress)); + node->setMacCapabilitiesFlag(macCapabilitiesFlag); + qCDebug(dcZigbeeNetwork()) << "Node:" << node; + node->startInitialization(); + addUnitializedNode(node); // ZigbeeInterfaceReply *reply = nullptr; // reply = m_controller->commandAuthenticateDevice(node->extendedAddress(), securityConfiguration().globalTrustCenterLinkKey()); // connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkNxp::onCommandAuthenticateDeviceFinished); - // reply = m_controller->commandNodeDescriptorRequest(node->shortAddress()); - // connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkNxp::onCommandNodeDescriptorRequestFinished); - - // reply = m_controller->commandSimpleDescriptorRequest(node->shortAddress(), endPoint()); - // connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkNxp::onCommandSimpleDescriptorRequestFinished); - - // reply = m_controller->commandPowerDescriptorRequest(node->shortAddress()); - // connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkNxp::onCommandPowerDescriptorRequestFinished); } void ZigbeeNetworkNxp::processAttributeReport(const ZigbeeInterfaceMessage &message) @@ -691,25 +740,28 @@ void ZigbeeNetworkNxp::onControllerAvailableChanged(bool available) { qCDebug(dcZigbeeNetwork()) << "Hardware controller is" << (available ? "now available" : "not available"); - if (m_factoryResetting && !available) { - setStartingState(StartingStateReset); - return; - } - if (!available) { - // FIXME - // foreach (ZigbeeNode *node, nodes()) { - // node->setConnected(false); - // } + foreach (ZigbeeNode *node, nodes()) { + qobject_cast(node)->setConnected(false); + } setError(ErrorHardwareUnavailable); - setPermitJoining(false); - setState(StateOffline); + m_permitJoining = false; + emit permitJoiningChanged(m_permitJoining); setStartingState(StartingStateNone); + setState(StateOffline); } else { m_error = ErrorNoError; + m_permitJoining = false; + emit permitJoiningChanged(m_permitJoining); + // Note: if we are factory resetting, erase also the data on the controller before resetting + if (m_factoryResetting) { + setStartingState(StartingStateErase); + } else { + setStartingState(StartingStateReset); + } + setState(StateStarting); - setStartingState(StartingStateReset); } } @@ -765,23 +817,6 @@ void ZigbeeNetworkNxp::onCommandSoftResetControllerFinished() qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; } -void ZigbeeNetworkNxp::onCommandStartNetworkFinished() -{ - ZigbeeInterfaceReply *reply = static_cast(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()); - // FIXME: start creating coordinator node - //if (m_startingState == StartingStateStartNetwork) setStartingState(StartingStateGetPermitJoinStatus); -} - void ZigbeeNetworkNxp::onCommandStartScanFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); @@ -837,7 +872,8 @@ void ZigbeeNetworkNxp::processNetworkFormed(const ZigbeeInterfaceMessage &messag if (networkStatus != Zigbee::ZigbeeNwkLayerStatusJointNetwork && networkStatus != Zigbee::ZigbeeNwkLayerStatusFormedNetwork) { qCWarning(dcZigbeeNetwork()) << "Forming network failed" << networkStatusString; - setPermitJoining(false); + m_permitJoining = false; + emit permitJoiningChanged(m_permitJoining); setStartingState(StartingStateNone); setState(StateOffline); setError(ErrorZigbeeError); @@ -856,20 +892,28 @@ void ZigbeeNetworkNxp::processNetworkFormed(const ZigbeeInterfaceMessage &messag qCDebug(dcZigbeeNetwork()) << " Permit joining:" << permitJoining(); saveNetwork(); - m_networkRunning = true; - setState(StateRunning); - // FIXME: create coordinator node + if (nodes().isEmpty()) { + // Create coordinator node + ZigbeeNodeNxp *node = new ZigbeeNodeNxp(m_controller, m_controller); + node->setShortAddress(shortAddress); + node->setExtendedAddress(ZigbeeAddress(extendedAddress)); + node->startInitialization(); - // // Set the node information - // setShortAddress(shortAddress); - // setExtendedAddress(ZigbeeAddress(extendedAddress)); - // setChannel(channel); - - // if (!hasNode(this->shortAddress())) - // addUnitializedNode(this); + connect(node, &ZigbeeNode::stateChanged, this, [this, node](){ + if (node->state() == ZigbeeNode::StateInitialized) { + m_coordinatorNode = qobject_cast(node); + addNode(m_coordinatorNode); + qCDebug(dcZigbeeNetwork()) << "Coordinator node initialized. The network is now set up."; + setState(StateRunning); + } + }); + } else { + // Primary initialization was already done. + setState(StateRunning); + } } void ZigbeeNetworkNxp::startNetwork() @@ -890,12 +934,10 @@ void ZigbeeNetworkNxp::startNetwork() if (state() == StateUninitialized) loadNetwork(); - if (extendedPanId() == 0 && channel() == 0) { - m_factoryResetting = true; - } + // Do a factory reset if there are no network configuration and create a new one from scratch + m_factoryResetting = !networkConfigurationAvailable(); setState(StateOffline); - // Check if we have to create a pan ID and select the channel if (extendedPanId() == 0) { setExtendedPanId(ZigbeeUtils::generateRandomPanId()); @@ -904,25 +946,18 @@ void ZigbeeNetworkNxp::startNetwork() // TODO: get desired channel, by default use all - if (!m_controller->enable(serialPortName(), serialBaudrate())) { - setPermitJoining(false); + m_permitJoining = false; + emit permitJoiningChanged(m_permitJoining); setState(StateOffline); setStartingState(StartingStateNone); setError(ErrorHardwareUnavailable); return; } - setPermitJoining(false); - - // Note: if we are factory resetting, erase also the data on the controller - if (m_factoryResetting) { - setStartingState(StartingStateReset); - } else { - setStartingState(StartingStateErase); - } - - setState(StateStarting); + m_permitJoining = false; + emit permitJoiningChanged(m_permitJoining); + // Note: wait for the controller available signal and start the initialization there } void ZigbeeNetworkNxp::stopNetwork() @@ -935,7 +970,8 @@ void ZigbeeNetworkNxp::stopNetwork() } setStartingState(StartingStateNone); - setPermitJoining(false); + m_permitJoining = false; + emit permitJoiningChanged(m_permitJoining); setState(StateOffline); setError(ErrorNoError); } diff --git a/libnymea-zigbee/nxp/zigbeenetworknxp.h b/libnymea-zigbee/nxp/zigbeenetworknxp.h index 64bdc84..b7b5d8e 100644 --- a/libnymea-zigbee/nxp/zigbeenetworknxp.h +++ b/libnymea-zigbee/nxp/zigbeenetworknxp.h @@ -35,6 +35,10 @@ private: void readControllerVersion(); void readPermitJoinStatus(); +protected: + ZigbeeNode *createNode(QObject *parent) override; + void setPermitJoiningInternal(bool permitJoining) override; + private slots: void onMessageReceived(const ZigbeeInterfaceMessage &message); void onControllerAvailableChanged(bool available); @@ -42,7 +46,6 @@ private slots: // Controller command finished slots void onCommandResetControllerFinished(); void onCommandSoftResetControllerFinished(); - void onCommandStartNetworkFinished(); void onCommandStartScanFinished(); //void onCommandEnableWhitelistFinished(); diff --git a/libnymea-zigbee/nxp/zigbeenodenxp.cpp b/libnymea-zigbee/nxp/zigbeenodenxp.cpp index c58fc02..82485e3 100644 --- a/libnymea-zigbee/nxp/zigbeenodenxp.cpp +++ b/libnymea-zigbee/nxp/zigbeenodenxp.cpp @@ -1,6 +1,105 @@ #include "zigbeenodenxp.h" +#include "loggingcategory.h" +#include "zigbeeutils.h" -ZigbeeNodeNxp::ZigbeeNodeNxp(QObject *parent) : QObject(parent) +#include + +ZigbeeNodeNxp::ZigbeeNodeNxp(ZigbeeBridgeControllerNxp *controller, QObject *parent): + ZigbeeNode(parent), + m_controller(controller) { } + +void ZigbeeNodeNxp::setInitState(ZigbeeNodeNxp::InitState initState) +{ + m_initState = initState; + + switch (m_initState) { + case InitStateNone: + break; + case InitStateNodeDescriptor: { + qCDebug(dcZigbeeNode()) << "Request node descriptor for" << this; + ZigbeeInterfaceReply *reply = m_controller->commandNodeDescriptorRequest(shortAddress()); + 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(); + } + + setNodeDescriptorRawData(reply->additionalMessage().data()); + setInitState(InitStatePowerDescriptor); + }); + break; + } + case InitStatePowerDescriptor: { + qCDebug(dcZigbeeNode()) << "Request power descriptor for" << this; + ZigbeeInterfaceReply *reply = m_controller->commandPowerDescriptorRequest(shortAddress()); + 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(); + } + + QByteArray data = reply->additionalMessage().data(); + quint8 sequenceNumber = 0; + quint8 status = 0; + quint16 powerDescriptorFlag = 0; + + QDataStream stream(&data, QIODevice::ReadOnly); + stream >> sequenceNumber >> status >> powerDescriptorFlag; + setPowerDescriptorFlag(powerDescriptorFlag); + setInitState(InitStateActiveEndpoints); + }); + break; + } + case InitStateActiveEndpoints: { + qCDebug(dcZigbeeNode()) << "Request active endpoints for" << this; + ZigbeeInterfaceReply *reply = m_controller->commandActiveEndpointsRequest(shortAddress()); + 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(); + } else { + + QByteArray data = reply->additionalMessage().data(); + quint8 sequenceNumber = 0; + quint8 status = 0; + quint16 shortAddress = 0; + quint8 endpointCount = 0; + QList endpointIds; + + QDataStream stream(&data, QIODevice::ReadOnly); + stream >> sequenceNumber >> status >> shortAddress >> endpointCount; + + qCDebug(dcZigbeeNode()) << "Active endpoint list received:"; + qCDebug(dcZigbeeNode()) << "Sequence number" << sequenceNumber; + qCDebug(dcZigbeeNode()) << "Status:" << status; + qCDebug(dcZigbeeNode()) << "Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); + qCDebug(dcZigbeeNode()) << "Endpoint count:" << endpointCount; + for (int i = 0; i < endpointCount; i++) { + quint8 endpointId = 0; + stream >> endpointId; + endpointIds.append(endpointId); + qCDebug(dcZigbeeNode()) << " - " << ZigbeeUtils::convertByteToHexString(endpointId); + } + } + setState(StateInitialized); + }); + break; + } + case InitStateSimpleDescriptors: + + break; + } +} + +void ZigbeeNodeNxp::startInitialization() +{ + qCDebug(dcZigbeeNode()) << "Start initialization" << this; + setState(StateInitializing); + setInitState(InitStateNodeDescriptor); +} diff --git a/libnymea-zigbee/nxp/zigbeenodenxp.h b/libnymea-zigbee/nxp/zigbeenodenxp.h index 9d742ce..b02ee69 100644 --- a/libnymea-zigbee/nxp/zigbeenodenxp.h +++ b/libnymea-zigbee/nxp/zigbeenodenxp.h @@ -4,11 +4,34 @@ #include #include "../zigbeenode.h" -class ZigbeeNodeNxp : public QObject +#include "zigbeebridgecontrollernxp.h" + +class ZigbeeNodeNxp : public ZigbeeNode { Q_OBJECT + + friend class ZigbeeNetworkNxp; + public: - explicit ZigbeeNodeNxp(QObject *parent = nullptr); + enum InitState { + InitStateNone, + InitStateNodeDescriptor, + InitStatePowerDescriptor, + InitStateActiveEndpoints, + InitStateSimpleDescriptors + }; + Q_ENUM(InitState) + + explicit ZigbeeNodeNxp(ZigbeeBridgeControllerNxp *controller, QObject *parent = nullptr); + +private: + ZigbeeBridgeControllerNxp *m_controller = nullptr; + InitState m_initState = InitStateNone; + + void setInitState(InitState initState); + +protected: + void startInitialization() override; signals: diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index 93197d0..2a23fe6 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -136,12 +136,7 @@ bool ZigbeeNetwork::permitJoining() const void ZigbeeNetwork::setPermitJoining(bool permitJoining) { - if (m_permitJoining == permitJoining) - return; - - qCDebug(dcZigbeeNetwork()) << "Permit joining changed to" << permitJoining; - m_permitJoining = permitJoining; - emit permitJoiningChanged(m_permitJoining); + setPermitJoiningInternal(permitJoining); } QList ZigbeeNetwork::nodes() const @@ -151,7 +146,7 @@ QList ZigbeeNetwork::nodes() const ZigbeeNode *ZigbeeNetwork::coordinatorNode() const { - return getZigbeeNode(0); + return m_coordinatorNode; } ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) const @@ -205,7 +200,8 @@ void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node) return; } - node->setConnected(state() == StateRunning); + // FIXME: check when and how the note will be reachable + //node->setConnected(state() == StateRunning); m_nodes.append(node); emit nodeAdded(node); @@ -253,78 +249,76 @@ void ZigbeeNetwork::loadNetwork() foreach (const QString ieeeAddressString, settings.childGroups()) { settings.beginGroup(ieeeAddressString); - ZigbeeNode *node = new ZigbeeNode(this); + ZigbeeNode *node = createNode(this); node->setExtendedAddress(ZigbeeAddress(ieeeAddressString)); node->setShortAddress(static_cast(settings.value("nwkAddress", 0).toUInt())); node->setMacCapabilitiesFlag(static_cast(settings.value("macCapabilitiesFlag", 0).toUInt())); node->setNodeDescriptorRawData(settings.value("nodeDescriptorRawData", QByteArray()).toByteArray()); node->setPowerDescriptorFlag(static_cast(settings.value("powerDescriptorFlag", 0).toUInt())); - // TODO: load endpoints -// settings.beginGroup("inputCluster"); -// foreach (const QString &clusterIdString, settings.childGroups()) { -// settings.beginGroup(clusterIdString); -// Zigbee::ClusterId clusterId = static_cast(clusterIdString.toInt()); + // settings.beginGroup("inputCluster"); + // foreach (const QString &clusterIdString, settings.childGroups()) { + // settings.beginGroup(clusterIdString); + // Zigbee::ClusterId clusterId = static_cast(clusterIdString.toInt()); -// foreach (const QString &attributeIdString, settings.childGroups()) { -// settings.beginGroup(attributeIdString); -// quint16 id = static_cast(attributeIdString.toInt()); -// Zigbee::DataType dataType = static_cast(settings.value("dataType", 0).toInt()); -// QByteArray data = settings.value("data").toByteArray(); -// node->setClusterAttribute(clusterId, ZigbeeClusterAttribute(id, dataType, data)); -// settings.endGroup(); // attributeId -// } -// settings.endGroup(); // clusterId -// } -// settings.endGroup(); // inputCluster + // foreach (const QString &attributeIdString, settings.childGroups()) { + // settings.beginGroup(attributeIdString); + // quint16 id = static_cast(attributeIdString.toInt()); + // Zigbee::DataType dataType = static_cast(settings.value("dataType", 0).toInt()); + // QByteArray data = settings.value("data").toByteArray(); + // node->setClusterAttribute(clusterId, ZigbeeClusterAttribute(id, dataType, data)); + // settings.endGroup(); // attributeId + // } + // settings.endGroup(); // clusterId + // } + // settings.endGroup(); // inputCluster -// // Output cluster -// settings.beginGroup("outputCluster"); -// foreach (const QString &clusterIdString, settings.childGroups()) { -// settings.beginGroup(clusterIdString); -// Zigbee::ClusterId clusterId = static_cast(clusterIdString.toInt()); + // // Output cluster + // settings.beginGroup("outputCluster"); + // foreach (const QString &clusterIdString, settings.childGroups()) { + // settings.beginGroup(clusterIdString); + // Zigbee::ClusterId clusterId = static_cast(clusterIdString.toInt()); -// foreach (const QString &attributeIdString, settings.childGroups()) { -// settings.beginGroup(attributeIdString); -// quint16 id = static_cast(attributeIdString.toInt()); -// Zigbee::DataType dataType = static_cast(settings.value("dataType", 0).toInt()); -// QByteArray data = settings.value("data").toByteArray(); -// node->setClusterAttribute(clusterId, ZigbeeClusterAttribute(id, dataType, data)); -// settings.endGroup(); // attributeId -// } -// settings.endGroup(); // clusterId -// } -// settings.endGroup(); // outputCluster - //FIXME - //node->setState(StateInitialized); + // foreach (const QString &attributeIdString, settings.childGroups()) { + // settings.beginGroup(attributeIdString); + // quint16 id = static_cast(attributeIdString.toInt()); + // Zigbee::DataType dataType = static_cast(settings.value("dataType", 0).toInt()); + // QByteArray data = settings.value("data").toByteArray(); + // node->setClusterAttribute(clusterId, ZigbeeClusterAttribute(id, dataType, data)); + // settings.endGroup(); // attributeId + // } + // settings.endGroup(); // clusterId + // } + // settings.endGroup(); // outputCluster + + node->setState(ZigbeeNode::StateInitialized); addNodeInternally(node); - settings.endGroup(); // ieeeAddress } settings.endGroup(); // Nodes - qCDebug(dcZigbeeNetwork()) << "Extended PAN ID:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId); - qCDebug(dcZigbeeNetwork()) << "Channel" << m_channel; - qCDebug(dcZigbeeNetwork()) << QStringLiteral("Nodes: (%1)").arg(m_nodes.count()); - foreach (ZigbeeNode *node, nodes()) { - qCDebug(dcZigbeeNetwork()) << " - " << node; -// qCDebug(dcZigbeeNetwork()) << "Output cluster:"; -// foreach (ZigbeeCluster *cluster, node->outputClusters()) { -// qCDebug(dcZigbeeNetwork()) << " " << cluster; -// foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) { -// qCDebug(dcZigbeeNetwork()) << " " << attribute; -// } -// } + //qCDebug(dcZigbeeNetwork()) << "Extended PAN ID:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId); + //qCDebug(dcZigbeeNetwork()) << "Channel" << m_channel; + //qCDebug(dcZigbeeNetwork()) << QStringLiteral("Nodes: (%1)").arg(m_nodes.count()); + // foreach (ZigbeeNode *node, nodes()) { + // qCDebug(dcZigbeeNetwork()) << " - " << node; + // qCDebug(dcZigbeeNetwork()) << "Output cluster:"; + // foreach (ZigbeeCluster *cluster, node->outputClusters()) { + // qCDebug(dcZigbeeNetwork()) << " " << cluster; + // foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + // qCDebug(dcZigbeeNetwork()) << " " << attribute; + // } + // } -// qCDebug(dcZigbeeNetwork()) << "Input cluster:"; -// foreach (ZigbeeCluster *cluster, node->inputClusters()) { -// qCDebug(dcZigbeeNetwork()) << " " << cluster; -// foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) { -// qCDebug(dcZigbeeNetwork()) << " " << attribute; -// } -// } - } + // qCDebug(dcZigbeeNetwork()) << "Input cluster:"; + // foreach (ZigbeeCluster *cluster, node->inputClusters()) { + // qCDebug(dcZigbeeNetwork()) << " " << cluster; + // foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + // qCDebug(dcZigbeeNetwork()) << " " << attribute; + // } + // } + // } } void ZigbeeNetwork::clearSettings() @@ -368,34 +362,34 @@ void ZigbeeNetwork::saveNode(ZigbeeNode *node) // TODO: save the rest of the node -// // Input clusters -// settings.beginGroup("inputCluster"); -// foreach (ZigbeeCluster *cluster, node->inputClusters()) { -// settings.beginGroup(QString::number(static_cast(cluster->clusterId()))); -// foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) { -// settings.beginGroup(QString::number(static_cast(attribute.id()))); -// settings.setValue("dataType", static_cast(attribute.dataType())); -// settings.setValue("data", attribute.data()); -// settings.endGroup(); // attributeId -// } -// settings.endGroup(); // clusterId -// } -// settings.endGroup(); // inputCluster + // // Input clusters + // settings.beginGroup("inputCluster"); + // foreach (ZigbeeCluster *cluster, node->inputClusters()) { + // settings.beginGroup(QString::number(static_cast(cluster->clusterId()))); + // foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + // settings.beginGroup(QString::number(static_cast(attribute.id()))); + // settings.setValue("dataType", static_cast(attribute.dataType())); + // settings.setValue("data", attribute.data()); + // settings.endGroup(); // attributeId + // } + // settings.endGroup(); // clusterId + // } + // settings.endGroup(); // inputCluster -// // Output clusters -// settings.beginGroup("outputCluster"); -// foreach (ZigbeeCluster *cluster, node->outputClusters()) { -// settings.beginGroup(QString::number(static_cast(cluster->clusterId()))); -// foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) { -// settings.beginGroup(QString::number(static_cast(attribute.id()))); -// settings.setValue("dataType", static_cast(attribute.dataType())); -// settings.setValue("data", attribute.data()); -// settings.endGroup(); // attributeId -// } -// settings.endGroup(); // clusterId -// } -// settings.endGroup(); // inputCluster + // // Output clusters + // settings.beginGroup("outputCluster"); + // foreach (ZigbeeCluster *cluster, node->outputClusters()) { + // settings.beginGroup(QString::number(static_cast(cluster->clusterId()))); + // foreach (const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + // settings.beginGroup(QString::number(static_cast(attribute.id()))); + // settings.setValue("dataType", static_cast(attribute.dataType())); + // settings.setValue("data", attribute.data()); + // settings.endGroup(); // attributeId + // } + // settings.endGroup(); // clusterId + // } + // settings.endGroup(); // inputCluster settings.endGroup(); // Node ieee address @@ -416,11 +410,6 @@ void ZigbeeNetwork::removeNodeFromSettings(ZigbeeNode *node) settings.endGroup(); // Nodes } -ZigbeeNode *ZigbeeNetwork::createNode(QObject *parent) -{ - return new ZigbeeNode(parent); -} - void ZigbeeNetwork::addNode(ZigbeeNode *node) { qCDebug(dcZigbeeNetwork()) << "Add node" << node; @@ -467,6 +456,11 @@ void ZigbeeNetwork::setError(ZigbeeNetwork::Error error) emit errorOccured(m_error); } +bool ZigbeeNetwork::networkConfigurationAvailable() const +{ + return m_extendedPanId != 0 && m_channel != 0; +} + void ZigbeeNetwork::onNodeStateChanged(ZigbeeNode::State state) { ZigbeeNode *node = qobject_cast(sender()); diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h index df92420..4772687 100644 --- a/libnymea-zigbee/zigbeenetwork.h +++ b/libnymea-zigbee/zigbeenetwork.h @@ -94,7 +94,6 @@ public: bool hasNode(quint16 shortAddress) const; bool hasNode(const ZigbeeAddress &address) const; - private: State m_state = StateUninitialized; @@ -107,7 +106,6 @@ private: quint32 m_channel = 0; ZigbeeSecurityConfiguration m_securityConfiguration; ZigbeeNode::NodeType m_nodeType = ZigbeeNode::NodeTypeCoordinator; - bool m_permitJoining = false; QString m_settingsFileName = "/etc/nymea/nymea-zigbee.conf"; QList m_nodes; @@ -118,6 +116,11 @@ private: protected: Error m_error = ErrorNoError; + ZigbeeNode *m_coordinatorNode = nullptr; + bool m_permitJoining = false; + + virtual ZigbeeNode *createNode(QObject *parent) = 0; + virtual void setPermitJoiningInternal(bool permitJoining) = 0; void saveNetwork(); void loadNetwork(); @@ -126,8 +129,6 @@ protected: void saveNode(ZigbeeNode *node); void removeNodeFromSettings(ZigbeeNode *node); - ZigbeeNode *createNode(QObject *parent); - void addNode(ZigbeeNode *node); void addUnitializedNode(ZigbeeNode *node); void removeNode(ZigbeeNode *node); @@ -135,6 +136,8 @@ protected: void setState(State state); void setError(Error error); + bool networkConfigurationAvailable() const; + signals: void settingsFileNameChanged(const QString &settingsFileName); void serialPortNameChanged(const QString &serialPortName); diff --git a/libnymea-zigbee/zigbeenetworkmanager.cpp b/libnymea-zigbee/zigbeenetworkmanager.cpp index b7ab633..9fbdc78 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.cpp +++ b/libnymea-zigbee/zigbeenetworkmanager.cpp @@ -27,47 +27,18 @@ #include "zigbeenetworkmanager.h" #include "loggingcategory.h" -#include "zigbeeutils.h" #include "nxp/zigbeenetworknxp.h" #include -#include -#include -ZigbeeNetworkManager::ZigbeeNetworkManager(const QString &serialPortName, qint32 baudrate, BackendType backendType, QObject *parent) : - QObject(parent), - m_serialPortName(serialPortName), - m_baudrate(baudrate), - m_backendType(backendType) +ZigbeeNetwork *ZigbeeNetworkManager::createZigbeeNetwork(ZigbeeNetworkManager::BackendType backend, QObject *parent) { srand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); - - switch (backendType) { + switch (backend) { case BackendTypeNxp: - m_network = new ZigbeeNetworkNxp(this); - m_network->setSerialPortName(m_serialPortName); - m_network->setSerialBaudrate(baudrate); - break; + return qobject_cast(new ZigbeeNetworkNxp(parent)); } -} -QString ZigbeeNetworkManager::serialPortName() const -{ - return m_serialPortName; -} - -qint32 ZigbeeNetworkManager::baudrate() const -{ - return m_baudrate; -} - -ZigbeeNetworkManager::BackendType ZigbeeNetworkManager::backendType() const -{ - return m_backendType; -} - -ZigbeeNetwork *ZigbeeNetworkManager::network() const -{ - return m_network; + return nullptr; } diff --git a/libnymea-zigbee/zigbeenetworkmanager.h b/libnymea-zigbee/zigbeenetworkmanager.h index 820ea49..965175b 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.h +++ b/libnymea-zigbee/zigbeenetworkmanager.h @@ -35,32 +35,14 @@ #include "zigbeenetwork.h" -class ZigbeeNetworkManager : public QObject +class ZigbeeNetworkManager { - Q_OBJECT - public: enum BackendType { BackendTypeNxp }; - Q_ENUM(BackendType) - - explicit ZigbeeNetworkManager(const QString &serialPortName, qint32 baudrate, BackendType backendType, QObject *parent = nullptr); - - QString serialPortName() const; - qint32 baudrate() const; - BackendType backendType() const; - - ZigbeeNetwork *network() const; - -private: - QString m_serialPortName; - qint32 m_baudrate; - BackendType m_backendType = BackendTypeNxp; - ZigbeeNetwork *m_network = nullptr; - -private slots: + static ZigbeeNetwork *createZigbeeNetwork(BackendType backend, QObject *parent = nullptr); }; #endif // ZIGBEEMANAGER_H diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index 9c96faa..7a08c94 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -493,6 +493,11 @@ void ZigbeeNode::setPowerDescriptorFlag(quint16 powerDescriptorFlag) } +void ZigbeeNode::startInitialization() +{ + qCWarning(dcZigbeeNode()) << "Start initialization is not implemented for this backend."; +} + void ZigbeeNode::setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute) { qCDebug(dcZigbeeNode()) << this << "cluster attribute changed" << clusterId << attribute; diff --git a/libnymea-zigbee/zigbeenode.h b/libnymea-zigbee/zigbeenode.h index 6921d1d..16489f8 100644 --- a/libnymea-zigbee/zigbeenode.h +++ b/libnymea-zigbee/zigbeenode.h @@ -39,7 +39,6 @@ class ZigbeeNode : public QObject Q_OBJECT friend class ZigbeeNetwork; - friend class ZigbeeNetworkManager; public: enum State { @@ -146,7 +145,6 @@ public: PowerLevel powerLevel() const; private: - ZigbeeNode(QObject *parent = nullptr); bool m_connected = false; State m_state = StateUninitialized; @@ -199,7 +197,8 @@ private: bool m_extendedActiveEndpointListAvailable = false; bool m_extendedSimpleDescriptorListAvailable = false; -private: +protected: + ZigbeeNode(QObject *parent = nullptr); void setState(State state); void setConnected(bool connected); @@ -225,6 +224,9 @@ private: quint16 powerDescriptorFlag() const; void setPowerDescriptorFlag(quint16 powerDescriptorFlag); + // + virtual void startInitialization(); + // Cluster commands void setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute = ZigbeeClusterAttribute());