diff --git a/core.cpp b/core.cpp index 005a29b..f703865 100644 --- a/core.cpp +++ b/core.cpp @@ -1,8 +1,8 @@ #include "core.h" #include -Core::Core(QObject *parent) : +Core::Core(const int &channel, QObject *parent) : QObject(parent) { - m_manager = new ZigbeeNetworkManager("/dev/ttyS0", this); + m_manager = new ZigbeeNetworkManager(channel, "/dev/ttyS0", this); } diff --git a/core.h b/core.h index 39f09df..2045b7c 100644 --- a/core.h +++ b/core.h @@ -9,7 +9,7 @@ class Core : public QObject { Q_OBJECT public: - explicit Core(QObject *parent = nullptr); + explicit Core(const int &channel, QObject *parent = nullptr); private: ZigbeeNetworkManager *m_manager; diff --git a/firmware/ZigbeeNodeControlBridge_JN5168_FULL_FUNC_DEVICE_115200.bin b/firmware/ZigbeeNodeControlBridge_JN5168_FULL_FUNC_DEVICE_115200.bin new file mode 100644 index 0000000..1672914 Binary files /dev/null and b/firmware/ZigbeeNodeControlBridge_JN5168_FULL_FUNC_DEVICE_115200.bin differ diff --git a/flash b/flash new file mode 100755 index 0000000..c50643b --- /dev/null +++ b/flash @@ -0,0 +1,84 @@ +#!/bin/sh -e + +setProgramMode() { + # Control Pins to put JN516x in bootloader mode + # Pin ZIGBEE_PROGRAM - CSID6 - PE10 (4*32 + 10) = 138 + # Pin ZiGBEE_RESET - CSID7 - PE11 (4*32 + 11) = 139 + echo "Set up program mode for zigbee module" + if [ ! -d /sys/class/gpio/gpio138 ]; then echo 138 > /sys/class/gpio/export; fi + if [ ! -d /sys/class/gpio/gpio139 ]; then echo 139 > /sys/class/gpio/export; fi + + echo "out" > /sys/class/gpio/gpio138/direction + echo "out" > /sys/class/gpio/gpio139/direction + + echo 0 > /sys/class/gpio/gpio138/active_low + echo 1 > /sys/class/gpio/gpio139/active_low + + #resetLow + resetHigh + programHigh + programLow + resetLow +} + +programLow() { + if [ -z "$1" ]; then TIMEOUT=1; else TIMEOUT=$1; fi + echo "Program 0" + echo 0 > /sys/class/gpio/gpio138/value + sleep $TIMEOUT +} + +programHigh() { + if [ -z "$1" ]; then TIMEOUT=1; else TIMEOUT=$1; fi + echo "Program 1" + echo 1 > /sys/class/gpio/gpio138/value + sleep $TIMEOUT +} + +resetLow() { + if [ -z "$1" ]; then TIMEOUT=1; else TIMEOUT=$1; fi + echo "Reset 0" + echo 0 > /sys/class/gpio/gpio139/value + sleep $TIMEOUT +} + +resetHigh() { + if [ -z "$1" ]; then TIMEOUT=1; else TIMEOUT=$1; fi + echo "Reset 1" + echo 1 > /sys/class/gpio/gpio139/value + sleep $TIMEOUT +} + +startFlash() { + if [ $1 ]; then + echo "Start flashing $1 on /dev/ttyS0" + #/usr/bin/JennicModuleProgrammer -I 38400 -P 38400 -s /dev/ttyS0 -f $1 -v -V 3 + /usr/bin/iot_jp -I 38400 -P 38400 -s /dev/ttyS0 -f $1 -v -V 3 + #/usr/bin/iot_jp -I 115200 -P 115200 -s /dev/ttyS0 -f $1 -v -V 3 + result=$? + else + echo "Error: no firmware file passed" + fi +} + +setNormalMode() { + # Control Pins to put JN516x in normal mode + echo "Set up normal mode" +# programLow 0.5 +# resetHigh +# resetLow +} + +cleanup() { + echo "Clean up" + echo 138 > /sys/class/gpio/unexport + # echo 139 > /sys/class/gpio/unexport +} + +setProgramMode +startFlash $1 +setNormalMode +cleanup + +echo "Done" + diff --git a/interface/zigbeeinterface.cpp b/interface/zigbeeinterface.cpp index 6b9e2bf..203c7b7 100644 --- a/interface/zigbeeinterface.cpp +++ b/interface/zigbeeinterface.cpp @@ -17,6 +17,9 @@ ZigbeeInterface::~ZigbeeInterface() bool ZigbeeInterface::available() const { + if (!m_serialPort) + return false; + return m_serialPort->isOpen(); } diff --git a/main.cpp b/main.cpp index 8dd05b9..6e824d8 100644 --- a/main.cpp +++ b/main.cpp @@ -57,6 +57,8 @@ int main(int argc, char *argv[]) qInstallMessageHandler(consoleLogHandler); QCoreApplication application(argc, argv); + application.setOrganizationName("guh"); + application.setApplicationName("qt-zigbee"); // Command line parser QCommandLineParser parser; @@ -64,18 +66,25 @@ int main(int argc, char *argv[]) parser.addVersionOption(); parser.setApplicationDescription(QString("\nDaemon for the zigbee NXP uart bridge.\n\nCopyright %1 2016 Simon Stürz \nAll rights reserved.").arg(QChar(0xA9))); + // Debug level QCommandLineOption debugLevelOption(QStringList() << "d" << "debug-level", "Set debug level [1-4]."); debugLevelOption.setDefaultValue("1"); debugLevelOption.setValueName("level"); parser.addOption(debugLevelOption); + // Channel + QCommandLineOption channelOption(QStringList() << "c" << "channel", "Set channel for the zigbee network. Channel between [11-26] are allowed. If not specified, the quitest channel will be choosen automatically."); + channelOption.setDefaultValue(0); + channelOption.setValueName("channel"); + parser.addOption(channelOption); + parser.process(application); + // Check debug level bool debugLevelValueOk = false; int debugLevel = parser.value(debugLevelOption).toInt(&debugLevelValueOk); - if (debugLevel < 1 || debugLevel > 4 || !debugLevelValueOk) { - qWarning() << "Invalid debug level passed:" << parser.value(debugLevelOption); + qCritical() << "Invalid debug level passed:" << parser.value(debugLevelOption) << "Reset to default debug level 1."; debugLevel = 1; } @@ -86,7 +95,19 @@ int main(int argc, char *argv[]) QLoggingCategory::installFilter(loggingCategoryFilter); - Core core; + // Check channel + bool channelValueOk = false; + int channel = parser.value(channelOption).toInt(&channelValueOk); + if (channel != 0) { + if (channel < 11 || channel > 26 || !channelValueOk) { + qCritical() << "Invalid channel value passed:" << parser.value(channelOption) << "Selecting automatically quitest channel."; + channel = 0; + } + } + + + + Core core(channel); return application.exec(); } diff --git a/qt-zigbee.pro b/qt-zigbee.pro index ddc4ad4..5ae57ca 100644 --- a/qt-zigbee.pro +++ b/qt-zigbee.pro @@ -4,7 +4,7 @@ QT += serialport CONFIG += c++11 console CONFIG -= app_bundle -TARGET = qt-zigbee +TARGET = zigbee-cli target.path = /usr/bin INSTALLS += target diff --git a/zigbee.cpp b/zigbee.cpp index cc23ded..785ed1b 100644 --- a/zigbee.cpp +++ b/zigbee.cpp @@ -1,3 +1,2 @@ #include "zigbee.h" - diff --git a/zigbee.h b/zigbee.h index ee90aad..0c0a326 100644 --- a/zigbee.h +++ b/zigbee.h @@ -3,6 +3,7 @@ #include #include +#include #include class Zigbee @@ -192,11 +193,11 @@ public: // Appliance Statistics Cluster 0x0B03 // http://www.nxp.com/documents/user_manual/JN-UG-3076.pdf - MessageTypeStatisticsClusterLogMessage = 0x0301, // Was 0x0500, was 0x0301 - MessageTypeStatisticsClusterLogMessageResponse = 0x8301, + MessageTypeStatisticsClusterLogMessage = 0x0301, // Was 0x0500, was 0x0301 + MessageTypeStatisticsClusterLogMessageResponse = 0x8301, // IAS Cluster - MessageTypeSendIasZoneEnroolResponse = 0x0400, + MessageTypeSendIasZoneEnroolResponse = 0x0400, MessageTypeIasZoneStatusChangeNotify = 0x8401, // Extended utils @@ -297,9 +298,9 @@ public: LightLinkDeviceColourTemperatureLight = 0x0220, // Controller devices - LightLinkDeviceColourController = 0x8000, - LightLinkDeviceColourSceneController = 0x8010, - LightLinkDeviceNonColourController = 0x8020, + LightLinkDeviceColourController = 0x0800, + LightLinkDeviceColourSceneController = 0x0810, + LightLinkDeviceNonColourController = 0x0820, LightLinkDeviceNonColourSceneController = 0x8030, LightLinkDeviceControlBridge = 0x8040, LightLinkDeviceOnOffSensor = 0x8050 @@ -316,7 +317,7 @@ public: HomeAutomationDeviceDoorLockController = 0x000B, HomeAutomationDeviceSimpleSensor = 0x000C, HomeAutomationDeviceSmartPlug = 0x0051, - HomeAutomationDeviceControlBridge = 0x8040, + HomeAutomationDeviceControlBridge = 0x0840, // Lightning devices HomeAutomationDeviceOnOffLight = 0x0100, @@ -339,9 +340,65 @@ public: }; Q_ENUM(HomeAutomationDevice) - - - + enum DataType { + NoData = 0x00, + Data8 = 0x08, + Data16 = 0x09, + Data24 = 0x0a, + Data32 = 0x0b, + Data40 = 0x0c, + Data48 = 0x0d, + Data56 = 0x0e, + Data64 = 0x0f, + Bool = 0x10, + BitMap8 = 0x18, + BitMap16 = 0x19, + BitMap24 = 0x1a, + BitMap32 = 0x1b, + BitMap40 = 0x1c, + BitMap48 = 0x1d, + BitMap56 = 0x1e, + BitMap64 = 0x1f, + Uint8 = 0x20, + Uint16 = 0x21, + Uint24 = 0x22, + Uint32 = 0x23, + Uint40 = 0x24, + Uint48 = 0x25, + Uint56 = 0x26, + Uint64 = 0x27, + Int8 = 0x28, + Int16 = 0x29, + Int24 = 0x2a, + Int32 = 0x2b, + Int40 = 0x2c, + Int48 = 0x2d, + Int56 = 0x2e, + Int64 = 0x2f, + Enum8 = 0x30, + Enum16 = 0x31, + FloatSemi = 0x38, + FloatSingle = 0x39, + FloatDouble = 0x3a, + OctetString = 0x41, + CharString = 0x42, + LongOctetString = 0x43, + LongCharString = 0x44, + Array = 0x48, + Structure = 0x4c, + Set = 0x50, + Bag = 0x51, + TimeOfDay = 0xe0, + Date = 0xe1, + UtcTime = 0xe2, + Cluster = 0xe8, + Attribute = 0xe9, + BacnetId = 0xea, + IeeeAddress = 0xf0, + BitKey128 = 0xf1, + Unknown = 0xff + }; + Q_ENUM(DataType) ///* Manufacturer Codes */ ///* Codes less than 0x1000 were issued for RF4CE */ diff --git a/zigbeeaddress.cpp b/zigbeeaddress.cpp index e66d7b0..9b05917 100644 --- a/zigbeeaddress.cpp +++ b/zigbeeaddress.cpp @@ -34,11 +34,6 @@ ZigbeeAddress::ZigbeeAddress(const ZigbeeAddress &other) m_address = other.toUInt64(); } -ZigbeeAddress::~ZigbeeAddress() -{ - -} - quint64 ZigbeeAddress::toUInt64() const { return m_address; @@ -66,6 +61,12 @@ void ZigbeeAddress::clear() m_address = 0; } +ZigbeeAddress &ZigbeeAddress::operator=(const ZigbeeAddress &other) +{ + m_address = other.toUInt64(); + return *this; +} + bool ZigbeeAddress::operator<(const ZigbeeAddress &other) const { return m_address < other.toUInt64(); diff --git a/zigbeeaddress.h b/zigbeeaddress.h index 9af9bba..5589ba7 100644 --- a/zigbeeaddress.h +++ b/zigbeeaddress.h @@ -11,7 +11,6 @@ public: explicit ZigbeeAddress(quint64 address); explicit ZigbeeAddress(const QString &address); ZigbeeAddress(const ZigbeeAddress &other); - ~ZigbeeAddress(); quint64 toUInt64() const; QString toString() const; diff --git a/zigbeebridgecontroller.cpp b/zigbeebridgecontroller.cpp index 1fa290e..008cf09 100644 --- a/zigbeebridgecontroller.cpp +++ b/zigbeebridgecontroller.cpp @@ -9,7 +9,7 @@ ZigbeeBridgeController::ZigbeeBridgeController(const QString &serialPort, QObjec connect(m_interface, &ZigbeeInterface::messageReceived, this, &ZigbeeBridgeController::onMessageReceived); if (!m_interface->enable(serialPort)) { - qCWarning(dcZigbeeController()) << "Could not enable ZigbeeInterface on" << serialPort; + qCCritical(dcZigbeeController()) << "Could not enable ZigbeeInterface on" << serialPort; return; } } diff --git a/zigbeenetworkmanager.cpp b/zigbeenetworkmanager.cpp index d583890..3d000c2 100644 --- a/zigbeenetworkmanager.cpp +++ b/zigbeenetworkmanager.cpp @@ -4,28 +4,57 @@ #include #include +#include -ZigbeeNetworkManager::ZigbeeNetworkManager(const QString &serialPort, QObject *parent) : - ZigbeeNode(parent), - m_serialPort(serialPort) +ZigbeeNetworkManager::ZigbeeNetworkManager(const int &channel, const QString &serialPort, QObject *parent) : + ZigbeeNode(new ZigbeeBridgeController(serialPort, parent), parent) { - // TODO: load PAN id and serial port - reset(); + connect(controller(), &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived); -} + if (controller()->available()) { + qCDebug(dcZigbee()) << "Bridge controller started successfully on" << serialPort; + } else { + qCCritical(dcZigbee()) << "The zigbee controller is not available on" << serialPort; + //return; + } -QString ZigbeeNetworkManager::serialPort() const -{ - return m_serialPort; -} + QSettings settings; + settings.beginGroup("Network"); + m_extendedPanId = static_cast(settings.value("panId", 0).toUInt()); + if (m_extendedPanId == 0) { + m_extendedPanId = generateRandomPanId(); + settings.setValue("panId", m_extendedPanId); + } + settings.endGroup(); -void ZigbeeNetworkManager::setSerialPort(const QString &serialPort) -{ - if (m_serialPort == serialPort) - return; + qCDebug(dcZigbee()) << "PAN Id:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId); + + // Create channel mask + // Note: normal number passed, that specific channel will be used || Bitfield: all channels would be 0x07FFF800 + quint32 channelMask = 0; + if (channel == 0) { + qCDebug(dcZigbee()) << "Using quitest channel for the zigbee network."; + } else { + channelMask |= 1 << (channel); + qCDebug(dcZigbee()) << "Using channel" << channel << "for the zigbee network."; + } + + // Call init methods + erasePersistentData(); + //resetController(); + getVersion(); + setExtendedPanId(m_extendedPanId); + setChannelMask(channelMask); + setDeviceType(NodeTypeCoordinator); + startNetwork(); + + + //startScan(); + //getPermitJoiningStatus(); + enableWhitelist(); + permitJoining(); + //getPermitJoiningStatus(); - m_serialPort = serialPort; - reset(); } QString ZigbeeNetworkManager::controllerVersion() const @@ -33,38 +62,14 @@ QString ZigbeeNetworkManager::controllerVersion() const return m_controllerVersion; } +QList ZigbeeNetworkManager::nodeList() const +{ + return m_nodeList; +} + void ZigbeeNetworkManager::reset() { - if (m_controller) { - delete m_controller; - m_controller = nullptr; - } - - //m_extendedPanId = generateRandomPanId(); - m_extendedPanId = 1180461015847120384; - qCDebug(dcZigbee()) << "PAN ID" << m_extendedPanId; - - m_controller = new ZigbeeBridgeController(m_serialPort, this); - connect(m_controller, &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived); - - if (m_controller->available()) { - qCDebug(dcZigbee()) << "Bridge controller started successfully on" << m_serialPort; - } else { - qCWarning(dcZigbee()) << "The zigbee controller is not available"; - } - - // Call init methods - erasePersistentData(); - //reset(); - getVersion(); - setExtendedPanId(m_extendedPanId); - setChannelMask(0); - setDeviceType(NodeTypeCoordinator); - startNetwork(); - //startScan(); - //getPermitJoiningStatus(); - permitJoining(); - //getPermitJoiningStatus(); + qCCritical(dcZigbee()) << "Reset networkmanager: TODO: needs to be implementet"; } quint64 ZigbeeNetworkManager::generateRandomPanId() @@ -74,12 +79,44 @@ quint64 ZigbeeNetworkManager::generateRandomPanId() return (ULLONG_MAX - 0) * (qrand()/(double)RAND_MAX); } +void ZigbeeNetworkManager::loadNetwork() +{ + qCDebug(dcZigbee()) << "Loading network nodes"; + QSettings settings; + settings.beginGroup("Nodes"); + foreach (const QString nodeAddress, settings.childGroups()) { + settings.beginGroup(nodeAddress); + quint16 shortAddress = static_cast(settings.value("shortAddress", 0).toUInt()); + settings.endGroup(); + + ZigbeeNode *node = new ZigbeeNode(controller(), this); + node->setExtendedAddress(ZigbeeAddress(nodeAddress)); + node->setShortAddress(shortAddress); + m_nodeList.append(node); + node->init(); + } + +} + +void ZigbeeNetworkManager::saveNetwork() +{ + qCDebug(dcZigbee()) << "Save network"; + QSettings settings; + settings.beginGroup("Nodes"); + foreach (ZigbeeNode *node, m_nodeList) { + settings.beginGroup(node->extendedAddress().toString()); + settings.setValue("shortAddress", node->shortAddress()); + settings.endGroup(); + } +} + void ZigbeeNetworkManager::resetController() { ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeReset)); request.setDescription("Reset controller"); + request.setTimoutIntervall(3000); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onResetControllerFinished); } @@ -88,7 +125,7 @@ void ZigbeeNetworkManager::erasePersistentData() ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeErasePersistentData)); request.setDescription("Erase persistent data"); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onErasePersistentDataFinished); } @@ -101,7 +138,7 @@ void ZigbeeNetworkManager::sendDataManagerAvailableResponse() ZigbeeInterfaceRequest request(message); request.setDescription("Data manager available response"); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, reply, &ZigbeeInterfaceReply::deleteLater); } @@ -111,7 +148,7 @@ void ZigbeeNetworkManager::getVersion() request.setDescription("Get version"); request.setExpectedAdditionalMessageType(Zigbee::MessageTypeVersionList); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onGetVersionFinished); } @@ -124,7 +161,7 @@ void ZigbeeNetworkManager::setExtendedPanId(const quint64 &panId) ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetExtendetPanId, data)); request.setDescription("Set extended PAN ID " + QString::number(panId) + " " + ZigbeeUtils::convertUint64ToHexString(panId)); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetExtendedPanIdFinished); } @@ -137,7 +174,7 @@ void ZigbeeNetworkManager::setChannelMask(const quint32 &channelMask) ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetChannelMask, data)); request.setDescription("Set channel mask " + ZigbeeUtils::convertByteArrayToHexString(data)); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetChannelMaskFinished); } @@ -152,7 +189,7 @@ void ZigbeeNetworkManager::setDeviceType(const NodeType &deviceType) ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetDeviceType, data)); request.setDescription("Set device type"); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetDeviceTypeFinished); } @@ -163,7 +200,7 @@ void ZigbeeNetworkManager::startNetwork() request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkJoinedFormed); request.setTimoutIntervall(12000); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onStartNetworkFinished); } @@ -174,7 +211,7 @@ void ZigbeeNetworkManager::startScan() request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkJoinedFormed); request.setTimoutIntervall(12000); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onStartScanFinished); } @@ -188,7 +225,7 @@ void ZigbeeNetworkManager::permitJoining(quint16 targetAddress, const quint8 adv ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePermitJoiningRequest, data)); request.setDescription("Permit joining request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress) + " for " + QString::number(advertisingIntervall) + "[s]"); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onPermitJoiningFinished); } @@ -199,54 +236,17 @@ void ZigbeeNetworkManager::getPermitJoiningStatus() request.setExpectedAdditionalMessageType(Zigbee::MessageTypeGetPermitJoiningResponse); request.setTimoutIntervall(1000); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onGetPermitJoiningStatusFinished); } -void ZigbeeNetworkManager::requestNodeDescription(const quint16 &shortAddress) +void ZigbeeNetworkManager::enableWhitelist() { - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << shortAddress; + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNetworkWhitelistEnable)); + request.setDescription("Enable whitelist"); - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse); - request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); - request.setTimoutIntervall(10000); - - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestNodeDescriptionFinished); -} - -void ZigbeeNetworkManager::requestSimpleNodeDescription(const quint16 &shortAddress, const quint8 &endpoint) -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << shortAddress; - stream << endpoint; - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSimpleDescriptorRequest, data)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeSimpleDescriptorResponse); - request.setDescription("Simple node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); - request.setTimoutIntervall(10000); - - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestSimpleNodeDescriptionFinished); -} - -void ZigbeeNetworkManager::requestPowerDescriptor(const quint16 &shortAddress) -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << shortAddress; - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePowerDescriptorRequest, data)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypePowerDescriptorResponse); - request.setDescription("Node power descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); - request.setTimoutIntervall(10000); - - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestPowerDescriptorFinished); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onEnableWhitelistFinished); } void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile) @@ -255,15 +255,25 @@ void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, c QDataStream stream(&data, QIODevice::WriteOnly); stream << shortAddress; stream << static_cast(profile); - stream << static_cast(0); - stream << static_cast(0); - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePowerDescriptorRequest, data)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypePowerDescriptorResponse); + // TODO: check what this does + +// // Input clusters +// stream << static_cast(7); +// stream << static_cast(Zigbee::ClusterIdBasic); +// stream << static_cast(Zigbee::ClusterIdIdentify); +// stream << static_cast(Zigbee::ClusterIdGroups); +// stream << static_cast(Zigbee::ClusterIdScenes); +// stream << static_cast(Zigbee::ClusterIdOnOff); +// stream << static_cast(Zigbee::ClusterIdLevelControl); +// stream << static_cast(Zigbee::ClusterIdColorControl); + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeMatchDescriptorRequest, data)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeMatchDescriptorResponse); request.setDescription("Request match descriptors " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); - request.setTimoutIntervall(10000); + request.setTimoutIntervall(5000); - ZigbeeInterfaceReply *reply = m_controller->sendRequest(request); + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestMatchDescriptorFinished); } @@ -418,18 +428,16 @@ void ZigbeeNetworkManager::onStartNetworkFinished() qCDebug(dcZigbee()).noquote() << "Network" << networkStatusString; qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); - qCDebug(dcZigbee()) << " Extended address:" << ZigbeeUtils::convertUint64ToHexString(extendedAddress) << ZigbeeAddress(extendedAddress) << ZigbeeAddress(extendedAddress).toUInt64(); + qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(extendedAddress); qCDebug(dcZigbee()) << " Channel:" << channel; // Set the node information setShortAddress(shortAddress); - setExtendedAddress(extendedAddress); + setExtendedAddress(ZigbeeAddress(extendedAddress)); - // Request data - requestNodeDescription(shortAddress); - requestSimpleNodeDescription(shortAddress); - requestPowerDescriptor(shortAddress); + init(); + loadNetwork(); } void ZigbeeNetworkManager::onStartScanFinished() @@ -471,174 +479,33 @@ void ZigbeeNetworkManager::onPermitJoiningFinished() } qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; - -} - -void ZigbeeNetworkManager::onRequestNodeDescriptionFinished() -{ - ZigbeeInterfaceReply *reply = static_cast(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"; - - quint8 sequenceNumber = static_cast(reply->additionalMessage().data().at(0)); - quint8 status = static_cast(reply->additionalMessage().data().at(1)); - - quint16 shortAddress = reply->additionalMessage().data().at(2); - shortAddress <<= 8; - shortAddress |= reply->additionalMessage().data().at(3); - - quint16 manufacturerCode = reply->additionalMessage().data().at(4); - manufacturerCode <<= 8; - manufacturerCode |= reply->additionalMessage().data().at(5); - - quint16 maximalRxSize = reply->additionalMessage().data().at(6); - maximalRxSize <<= 8; - maximalRxSize |= reply->additionalMessage().data().at(7); - - quint16 maximalTxSize = reply->additionalMessage().data().at(8); - maximalTxSize <<= 8; - maximalTxSize |= reply->additionalMessage().data().at(9); - - quint16 serverMask = reply->additionalMessage().data().at(10); - serverMask <<= 8; - serverMask |= reply->additionalMessage().data().at(11); - - quint8 descriptorFlag = static_cast(reply->additionalMessage().data().at(12)); - quint8 macFlags = static_cast(reply->additionalMessage().data().at(13)); - quint8 maxBufferSize = static_cast(reply->additionalMessage().data().at(14)); - - quint16 bitField = reply->additionalMessage().data().at(15); - bitField <<= 8; - bitField |= reply->additionalMessage().data().at(16); - - // TODO: find node for short address and set data - - qCDebug(dcZigbee()) << "Node descriptor:"; - qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); - qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); - qCDebug(dcZigbee()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); - qCDebug(dcZigbee()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode); - qCDebug(dcZigbee()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(maximalRxSize); - qCDebug(dcZigbee()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(maximalTxSize); - qCDebug(dcZigbee()) << " Server makk:" << ZigbeeUtils::convertUint16ToHexString(serverMask); - qCDebug(dcZigbee()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorFlag); - qCDebug(dcZigbee()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macFlags); - qCDebug(dcZigbee()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(maxBufferSize); - qCDebug(dcZigbee()) << " Bit field:" << ZigbeeUtils::convertUint16ToHexString(bitField); - -} - -void ZigbeeNetworkManager::onRequestSimpleNodeDescriptionFinished() -{ - ZigbeeInterfaceReply *reply = static_cast(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(reply->additionalMessage().data().at(0)); - quint8 status = static_cast(reply->additionalMessage().data().at(1)); - - quint16 nwkAddress = reply->additionalMessage().data().at(2); - nwkAddress <<= 8; - nwkAddress |= reply->additionalMessage().data().at(3); - - quint8 length = static_cast(reply->additionalMessage().data().at(4)); - quint8 endPoint = static_cast(reply->additionalMessage().data().at(5)); - - quint16 profileId = reply->additionalMessage().data().at(6); - profileId <<= 8; - profileId |= reply->additionalMessage().data().at(7); - - quint16 deviceId = reply->additionalMessage().data().at(8); - deviceId <<= 8; - deviceId |= reply->additionalMessage().data().at(9); - - quint8 bitField = static_cast(reply->additionalMessage().data().at(10)); - - qCDebug(dcZigbee()) << "Node simple descriptor:"; - qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); - qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); - qCDebug(dcZigbee()) << " Nwk address:" << ZigbeeUtils::convertUint16ToHexString(nwkAddress); - qCDebug(dcZigbee()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); - qCDebug(dcZigbee()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endPoint); - qCDebug(dcZigbee()) << " Profile:" << ZigbeeUtils::profileIdToString((Zigbee::ZigbeeProfile)profileId); - - if (profileId == Zigbee::ZigbeeProfileLightLink) { - qCDebug(dcZigbee()) << " Device ID:" << static_cast(deviceId); - } else { - qCDebug(dcZigbee()) << " Device ID:" << static_cast(deviceId); - } - - qCDebug(dcZigbee()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField); - - quint8 inputClusterCount = static_cast(reply->additionalMessage().data().at(10)); - - qCDebug(dcZigbee()) << " Input clusters:"; - QByteArray inputClusterListData = reply->additionalMessage().data().mid(11, inputClusterCount * 2); - for (int i = 0; i < inputClusterListData.count(); i+=2) { - quint16 clusterId = inputClusterListData.at(i); - clusterId <<= 8; - clusterId |= inputClusterListData .at(i+1); - - qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); - } - - quint8 outputClusterCount = static_cast(reply->additionalMessage().data().at(12 + inputClusterCount * 2)); - - qCDebug(dcZigbee()) << " Output clusters:"; - QByteArray outputClusterListData = reply->additionalMessage().data().mid(12 + inputClusterCount * 2, outputClusterCount * 2); - for (int i = 0; i < outputClusterListData.count(); i+=2) { - quint16 clusterId = outputClusterListData.at(i); - clusterId <<= 8; - clusterId |= outputClusterListData .at(i+1); - - qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); - } - -} - -void ZigbeeNetworkManager::onRequestPowerDescriptorFinished() -{ - ZigbeeInterfaceReply *reply = static_cast(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(reply->additionalMessage().data().at(0)); - quint8 status = static_cast(reply->additionalMessage().data().at(1)); - - quint16 bitField = reply->additionalMessage().data().at(2); - bitField <<= 8; - bitField |= reply->additionalMessage().data().at(3); - - qCDebug(dcZigbee()) << "Node power descriptor:"; - qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); - qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); - qCDebug(dcZigbee()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField); - } void ZigbeeNetworkManager::onRequestMatchDescriptorFinished() { + ZigbeeInterfaceReply *reply = static_cast(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::onEnableWhitelistFinished() +{ + ZigbeeInterfaceReply *reply = static_cast(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::processLoggingMessage(const ZigbeeInterfaceMessage &message) @@ -713,9 +580,9 @@ void ZigbeeNetworkManager::processNodeClusterList(const ZigbeeInterfaceMessage & profileId <<= 8; profileId |= static_cast(message.data().at(2)); - qCDebug(dcZigbee()) << "Node cluster list received:"; - qCDebug(dcZigbee()) << " Souce endpoint:" << sourceEndpoint; - qCDebug(dcZigbee()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); + qCDebug(dcZigbeeController()) << "Node cluster list received:"; + qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint; + qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); QByteArray clusterListData = message.data().right(message.data().count() - 3); @@ -725,7 +592,7 @@ void ZigbeeNetworkManager::processNodeClusterList(const ZigbeeInterfaceMessage & clusterId <<= 8; clusterId |= clusterListData .at(i+1); - qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); } } @@ -742,10 +609,10 @@ void ZigbeeNetworkManager::processNodeAttributeList(const ZigbeeInterfaceMessage clusterId |= static_cast(message.data().at(4)); - qCDebug(dcZigbee()) << "Node attribute list received:"; - qCDebug(dcZigbee()) << " Souce endpoint:" << sourceEndpoint; - qCDebug(dcZigbee()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); - qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + 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)); QByteArray attributeListData = message.data().right(message.data().count() - 5); @@ -754,7 +621,7 @@ void ZigbeeNetworkManager::processNodeAttributeList(const ZigbeeInterfaceMessage attribute <<= 8; attribute |= attributeListData .at(i+1); - qCDebug(dcZigbee()) << " Attribute:" << ZigbeeUtils::convertUint16ToHexString(attribute); + qCDebug(dcZigbeeController()) << " Attribute:" << ZigbeeUtils::convertUint16ToHexString(attribute); } } @@ -770,16 +637,16 @@ void ZigbeeNetworkManager::processNodeCommandIdList(const ZigbeeInterfaceMessage clusterId <<= 8; clusterId |= static_cast(message.data().at(4)); - qCDebug(dcZigbee()) << "Node command list received:"; - qCDebug(dcZigbee()) << " Souce endpoint:" << sourceEndpoint; - qCDebug(dcZigbee()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); - qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + qCDebug(dcZigbeeController()) << "Node command list received:"; + qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint; + qCDebug(dcZigbeeController()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); + qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); QByteArray commandListData = message.data().right(message.data().count() - 5); for (int i = 0; i < commandListData.count(); i++) { quint8 attribute = commandListData.at(i); - qCDebug(dcZigbee()) << " Command:" << ZigbeeUtils::convertByteToHexString(attribute); + qCDebug(dcZigbeeController()) << " Command:" << ZigbeeUtils::convertByteToHexString(attribute); } } @@ -809,14 +676,86 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m qCDebug(dcZigbee()) << "Device announced:"; qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); - qCDebug(dcZigbee()) << " Extended address:" << ZigbeeUtils::convertUint64ToHexString(ieeeAddress) << ZigbeeAddress(ieeeAddress); + qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress); qCDebug(dcZigbee()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapability); - // TODO: parse mac capabilities + ZigbeeNode *node = new ZigbeeNode(controller(), this); + node->setShortAddress(shortAddress); + node->setExtendedAddress(ZigbeeAddress(ieeeAddress)); - requestNodeDescription(shortAddress); - requestSimpleNodeDescription(shortAddress); - requestPowerDescriptor(shortAddress); + m_nodeList.append(node); + + node->init(); + + saveNetwork(); +} + +void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &message) +{ + quint8 sequenceNumber = static_cast(message.data().at(0)); + + quint16 sourceAddress = message.data().at(1); + sourceAddress <<= 8; + sourceAddress |= message.data().at(2); + + quint8 endPoint = static_cast(message.data().at(3)); + + quint16 clusterId = message.data().at(4); + clusterId <<= 8; + clusterId |= message.data().at(5); + + quint16 attributeId = message.data().at(6); + attributeId <<= 8; + attributeId |= message.data().at(7); + + quint8 attributStatus = static_cast(message.data().at(8)); + quint8 attributDataType = static_cast(message.data().at(9)); + + quint16 attributeSize = message.data().at(10); + attributeSize <<= 8; + attributeSize |= message.data().at(11); + + QByteArray data = message.data().mid(12); + Zigbee::DataType dataType = static_cast(attributDataType); + + qCDebug(dcZigbee()) << "Attribute report:"; + qCDebug(dcZigbee()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + qCDebug(dcZigbee()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceAddress); + qCDebug(dcZigbee()) << " End point:" << ZigbeeUtils::convertByteToHexString(endPoint); + qCDebug(dcZigbee()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + qCDebug(dcZigbee()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId); + qCDebug(dcZigbee()) << " Attribut status:" << ZigbeeUtils::convertByteToHexString(attributStatus); + qCDebug(dcZigbee()) << " Attribut data type:" << dataType; + qCDebug(dcZigbee()) << " Attribut size:" << attributeSize; + qCDebug(dcZigbee()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(data); + + switch (dataType) { + case Zigbee::CharString: + qCDebug(dcZigbee()) << " Data(converted)" << QString::fromUtf8(data); + break; + case Zigbee::Bool: + qCDebug(dcZigbee()) << " Data(converted)" << QVariant(data.toInt()).toBool(); + break; + default: + break; + } + + // TODO: find node and set attribute value + +} + +void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &message) +{ + + quint16 shortAddress = message.data().at(0); + shortAddress <<= 8; + shortAddress |= message.data().at(1); + + quint8 rejoining = message.data().at(2); + + qCDebug(dcZigbee()) << "Node leaving:" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << rejoining; + + // remove node } void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &message) @@ -840,6 +779,12 @@ void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &messa case Zigbee::MessageTypeDeviceAnnounce: processDeviceAnnounce(message); break; + case Zigbee::MessageTypeAttributeReport: + processAttributeReport(message); + break; + case Zigbee::MessageTypeLeaveIndication: + processLeaveIndication(message); + break; default: qCDebug(dcZigbeeController()) << "Message received:" << message; break; diff --git a/zigbeenetworkmanager.h b/zigbeenetworkmanager.h index 46addaa..3388c04 100644 --- a/zigbeenetworkmanager.h +++ b/zigbeenetworkmanager.h @@ -11,21 +11,21 @@ class ZigbeeNetworkManager : public ZigbeeNode { Q_OBJECT public: - explicit ZigbeeNetworkManager(const QString &serialPort = "/dev/ttyS0", QObject *parent = nullptr); - - QString serialPort() const; - void setSerialPort(const QString &serialPort); + explicit ZigbeeNetworkManager(const int &channel = 0, const QString &serialPort = "/dev/ttyS0", QObject *parent = nullptr); QString controllerVersion() const; + QList nodeList() const; + void reset(); private: ZigbeeBridgeController *m_controller = nullptr; - QString m_serialPort; QString m_controllerVersion; quint64 m_extendedPanId; + QList m_nodeList; + quint64 generateRandomPanId(); // Controller methods @@ -39,11 +39,9 @@ private: void startNetwork(); void startScan(); void permitJoining(quint16 targetAddress = 0xfffc, const quint8 advertisingIntervall = 254); - void getPermitJoiningStatus(); - void requestNodeDescription(const quint16 &shortAddress); - void requestSimpleNodeDescription(const quint16 &shortAddress, const quint8 &endpoint = 1); - void requestPowerDescriptor(const quint16 &shortAddress); + void getPermitJoiningStatus(); + void enableWhitelist(); void requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile); @@ -52,6 +50,9 @@ signals: private slots: void onMessageReceived(const ZigbeeInterfaceMessage &message); + void loadNetwork(); + void saveNetwork(); + // Controller methods finished slots void onResetControllerFinished(); void onErasePersistentDataFinished(); @@ -63,13 +64,11 @@ private slots: void onStartScanFinished(); void onGetPermitJoiningStatusFinished(); void onPermitJoiningFinished(); - - void onRequestNodeDescriptionFinished(); - void onRequestSimpleNodeDescriptionFinished(); - void onRequestPowerDescriptorFinished(); + void onEnableWhitelistFinished(); void onRequestMatchDescriptorFinished(); + // Process controller notifications/messages void processLoggingMessage(const ZigbeeInterfaceMessage &message); void processFactoryNewRestart(const ZigbeeInterfaceMessage &message); @@ -77,6 +76,8 @@ private slots: void processNodeAttributeList(const ZigbeeInterfaceMessage &message); void processNodeCommandIdList(const ZigbeeInterfaceMessage &message); void processDeviceAnnounce(const ZigbeeInterfaceMessage &message); + void processAttributeReport(const ZigbeeInterfaceMessage &message); + void processLeaveIndication(const ZigbeeInterfaceMessage &message); }; #endif // ZIGBEEMANAGER_H diff --git a/zigbeenode.cpp b/zigbeenode.cpp index fa75b5b..5a5dd95 100644 --- a/zigbeenode.cpp +++ b/zigbeenode.cpp @@ -1,16 +1,15 @@ #include "zigbeenode.h" +#include "zigbeeutils.h" +#include "loggingcategory.h" -ZigbeeNode::ZigbeeNode(QObject *parent) : QObject(parent) -{ - -} +#include quint16 ZigbeeNode::shortAddress() const { return m_shortAddress; } -quint64 ZigbeeNode::extendedAddress() const +ZigbeeAddress ZigbeeNode::extendedAddress() const { return m_extendedAddress; } @@ -20,12 +19,237 @@ ZigbeeNode::NodeType ZigbeeNode::nodeType() const return m_nodeType; } +void ZigbeeNode::init() +{ + requestNodeDescription(); + requestSimpleNodeDescription(); + requestPowerDescriptor(); +} + +void ZigbeeNode::requestNodeDescription() +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << m_shortAddress; + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse); + request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress)); + request.setTimoutIntervall(10000); + + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestNodeDescriptionFinished); +} + +void ZigbeeNode::requestSimpleNodeDescription() +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << m_shortAddress; + stream << quint8(1); + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSimpleDescriptorRequest, data)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeSimpleDescriptorResponse); + request.setDescription("Simple node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress)); + request.setTimoutIntervall(10000); + + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestSimpleNodeDescriptionFinished); +} + +void ZigbeeNode::requestPowerDescriptor() +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << m_shortAddress; + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePowerDescriptorRequest, data)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypePowerDescriptorResponse); + request.setDescription("Node power descriptor request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress)); + request.setTimoutIntervall(10000); + + ZigbeeInterfaceReply *reply = controller()->sendRequest(request); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestPowerDescriptorFinished); +} + +ZigbeeNode::ZigbeeNode(ZigbeeBridgeController *controller, QObject *parent) : + QObject(parent), + m_controller(controller) +{ + +} + +ZigbeeBridgeController *ZigbeeNode::controller() +{ + return m_controller; +} + void ZigbeeNode::setShortAddress(const quint16 &shortAddress) { m_shortAddress = shortAddress; } -void ZigbeeNode::setExtendedAddress(const quint64 &extendedAddress) +void ZigbeeNode::setExtendedAddress(const ZigbeeAddress &extendedAddress) { m_extendedAddress = extendedAddress; } + +void ZigbeeNode::onRequestNodeDescriptionFinished() +{ + ZigbeeInterfaceReply *reply = static_cast(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"; + + quint8 sequenceNumber = static_cast(reply->additionalMessage().data().at(0)); + quint8 status = static_cast(reply->additionalMessage().data().at(1)); + + quint16 shortAddress = reply->additionalMessage().data().at(2); + shortAddress <<= 8; + shortAddress |= reply->additionalMessage().data().at(3); + + quint16 manufacturerCode = reply->additionalMessage().data().at(4); + manufacturerCode <<= 8; + manufacturerCode |= reply->additionalMessage().data().at(5); + + quint16 maximalRxSize = reply->additionalMessage().data().at(6); + maximalRxSize <<= 8; + maximalRxSize |= reply->additionalMessage().data().at(7); + + quint16 maximalTxSize = reply->additionalMessage().data().at(8); + maximalTxSize <<= 8; + maximalTxSize |= reply->additionalMessage().data().at(9); + + quint16 serverMask = reply->additionalMessage().data().at(10); + serverMask <<= 8; + serverMask |= reply->additionalMessage().data().at(11); + + quint8 descriptorFlag = static_cast(reply->additionalMessage().data().at(12)); + quint8 macFlags = static_cast(reply->additionalMessage().data().at(13)); + quint8 maxBufferSize = static_cast(reply->additionalMessage().data().at(14)); + + quint16 bitField = reply->additionalMessage().data().at(15); + bitField <<= 8; + bitField |= reply->additionalMessage().data().at(16); + + // TODO: find node for short address and set data + + qCDebug(dcZigbee()) << "Node descriptor:"; + qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); + qCDebug(dcZigbee()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); + qCDebug(dcZigbee()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode); + qCDebug(dcZigbee()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(maximalRxSize); + qCDebug(dcZigbee()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(maximalTxSize); + qCDebug(dcZigbee()) << " Server makk:" << ZigbeeUtils::convertUint16ToHexString(serverMask); + qCDebug(dcZigbee()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorFlag); + qCDebug(dcZigbee()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macFlags); + qCDebug(dcZigbee()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(maxBufferSize); + qCDebug(dcZigbee()) << " Bit field:" << ZigbeeUtils::convertUint16ToHexString(bitField); +} + +void ZigbeeNode::onRequestSimpleNodeDescriptionFinished() +{ + ZigbeeInterfaceReply *reply = static_cast(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(reply->additionalMessage().data().at(0)); + quint8 status = static_cast(reply->additionalMessage().data().at(1)); + + quint16 nwkAddress = reply->additionalMessage().data().at(2); + nwkAddress <<= 8; + nwkAddress |= reply->additionalMessage().data().at(3); + + quint8 length = static_cast(reply->additionalMessage().data().at(4)); + quint8 endPoint = static_cast(reply->additionalMessage().data().at(5)); + + quint16 profileId = reply->additionalMessage().data().at(6); + profileId <<= 8; + profileId |= reply->additionalMessage().data().at(7); + + quint16 deviceId = reply->additionalMessage().data().at(8); + deviceId <<= 8; + deviceId |= reply->additionalMessage().data().at(9); + + quint8 bitField = static_cast(reply->additionalMessage().data().at(10)); + + qCDebug(dcZigbee()) << "Node simple descriptor:"; + qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); + qCDebug(dcZigbee()) << " Nwk address:" << ZigbeeUtils::convertUint16ToHexString(nwkAddress); + qCDebug(dcZigbee()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); + qCDebug(dcZigbee()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endPoint); + qCDebug(dcZigbee()) << " Profile:" << ZigbeeUtils::profileIdToString((Zigbee::ZigbeeProfile)profileId); + + if (profileId == Zigbee::ZigbeeProfileLightLink) { + qCDebug(dcZigbee()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); + } else { + qCDebug(dcZigbee()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); + } + + qCDebug(dcZigbee()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField); + + quint8 inputClusterCount = static_cast(reply->additionalMessage().data().at(10)); + + qCDebug(dcZigbee()) << " Input clusters:"; + QByteArray inputClusterListData = reply->additionalMessage().data().mid(11, inputClusterCount * 2); + for (int i = 0; i < inputClusterListData.count(); i+=2) { + quint16 clusterId = inputClusterListData.at(i); + clusterId <<= 8; + clusterId |= inputClusterListData .at(i+1); + + qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + } + + quint8 outputClusterCount = static_cast(reply->additionalMessage().data().at(12 + inputClusterCount * 2)); + + qCDebug(dcZigbee()) << " Output clusters:"; + QByteArray outputClusterListData = reply->additionalMessage().data().mid(12 + inputClusterCount * 2, outputClusterCount * 2); + for (int i = 0; i < outputClusterListData.count(); i+=2) { + quint16 clusterId = outputClusterListData.at(i); + clusterId <<= 8; + clusterId |= outputClusterListData .at(i+1); + + qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + } + +} + +void ZigbeeNode::onRequestPowerDescriptorFinished() +{ + ZigbeeInterfaceReply *reply = static_cast(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(reply->additionalMessage().data().at(0)); + quint8 status = static_cast(reply->additionalMessage().data().at(1)); + + quint16 bitField = reply->additionalMessage().data().at(2); + bitField <<= 8; + bitField |= reply->additionalMessage().data().at(3); + + qCDebug(dcZigbee()) << "Node power descriptor:"; + qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); + qCDebug(dcZigbee()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField); +} diff --git a/zigbeenode.h b/zigbeenode.h index bd6b904..a09cde6 100644 --- a/zigbeenode.h +++ b/zigbeenode.h @@ -4,10 +4,17 @@ #include #include "zigbee.h" +#include "zigbeeaddress.h" +#include "zigbeebridgecontroller.h" + +class ZigbeeNetworkManager; class ZigbeeNode : public QObject { Q_OBJECT + + friend class ZigbeeNetworkManager; + public: enum NodeType { NodeTypeCoordinator = 0, @@ -23,10 +30,8 @@ public: }; Q_ENUM(FrequencyBand) - explicit ZigbeeNode(QObject *parent = nullptr); - quint16 shortAddress() const; - quint64 extendedAddress() const; + ZigbeeAddress extendedAddress() const; // Information from node descriptor NodeType nodeType() const; @@ -34,18 +39,36 @@ public: bool canBeCoordinator() const; + void init(); + private: + ZigbeeBridgeController *m_controller; + quint16 m_shortAddress = 0; - quint64 m_extendedAddress = 0; + ZigbeeAddress m_extendedAddress; NodeType m_nodeType; -protected: - void setShortAddress(const quint16 &shortAddress); - void setExtendedAddress(const quint64 &extendedAddress); + void requestNodeDescription(); + void requestSimpleNodeDescription(); + void requestPowerDescriptor(); +protected: + ZigbeeNode(ZigbeeBridgeController *controller, QObject *parent = nullptr); + + ZigbeeBridgeController *controller(); + + void setShortAddress(const quint16 &shortAddress); + void setExtendedAddress(const ZigbeeAddress &extendedAddress); + signals: +private slots: + void onRequestNodeDescriptionFinished(); + void onRequestSimpleNodeDescriptionFinished(); + void onRequestPowerDescriptorFinished(); + + public slots: };