diff --git a/docs/JN-UG-3113.pdf b/docs/JN-UG-3113.pdf new file mode 100644 index 0000000..5237738 Binary files /dev/null and b/docs/JN-UG-3113.pdf differ diff --git a/docs/deCONZ-Serial-Protocol-en.pdf b/docs/deCONZ-Serial-Protocol-en.pdf new file mode 100644 index 0000000..d8e6bdc Binary files /dev/null and b/docs/deCONZ-Serial-Protocol-en.pdf differ diff --git a/docs/docs-05-3474-20-0csg-zigbee-specification.pdf b/docs/docs-05-3474-20-0csg-zigbee-specification.pdf new file mode 100644 index 0000000..5c7cf97 Binary files /dev/null and b/docs/docs-05-3474-20-0csg-zigbee-specification.pdf differ diff --git a/libnymea-zigbee/interface/zigbeeinterface.cpp b/libnymea-zigbee/interface/zigbeeinterface.cpp index 40a46ae..a69cdb5 100644 --- a/libnymea-zigbee/interface/zigbeeinterface.cpp +++ b/libnymea-zigbee/interface/zigbeeinterface.cpp @@ -3,11 +3,13 @@ #include "zigbeeutils.h" ZigbeeInterface::ZigbeeInterface(QObject *parent) : - QObject(parent), - m_serialPort(nullptr), - m_readingState(WaitForStart) + QObject(parent) { + m_reconnectTimer = new QTimer(this); + m_reconnectTimer->setSingleShot(true); + m_reconnectTimer->setInterval(5000); + connect(m_reconnectTimer, &QTimer::timeout, this, &ZigbeeInterface::onReconnectTimeout); } ZigbeeInterface::~ZigbeeInterface() @@ -56,13 +58,24 @@ void ZigbeeInterface::streamByte(quint8 byte, bool specialCharacter) byte ^= 0x10; } + qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << ZigbeeUtils::convertByteToHexString(byte); - if (m_serialPort->write(QByteArray(1, (char)byte)) < 0) { + if (m_serialPort->write(QByteArray(1, static_cast(byte))) < 0) { qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteToHexString(byte); } + m_serialPort->flush(); } +void ZigbeeInterface::setAvailable(bool available) +{ + if (m_available == available) + return; + + m_available = available; + emit availableChanged(m_available); +} + void ZigbeeInterface::setReadingState(const ZigbeeInterface::ReadingState &state) { if (m_readingState == state) @@ -72,6 +85,19 @@ void ZigbeeInterface::setReadingState(const ZigbeeInterface::ReadingState &state qCDebug(dcZigbeeInterfaceTraffic()) << m_readingState; } +void ZigbeeInterface::onReconnectTimeout() +{ + if (m_serialPort && !m_serialPort->isOpen()) { + if (!m_serialPort->open(QSerialPort::ReadWrite)) { + setAvailable(false); + m_reconnectTimer->start(); + } else { + qCDebug(dcZigbeeInterface()) << "The controller showed up again."; + setAvailable(true); + } + } +} + void ZigbeeInterface::onReadyRead() { QByteArray data = m_serialPort->readAll(); @@ -159,8 +185,11 @@ void ZigbeeInterface::onReadyRead() void ZigbeeInterface::onError(const QSerialPort::SerialPortError &error) { - if (error != QSerialPort::NoError) { - qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString(); + if (error != QSerialPort::NoError && m_serialPort->isOpen()) { + qCCritical(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString(); + m_reconnectTimer->start(); + m_serialPort->close(); + setAvailable(false); } } @@ -171,6 +200,8 @@ bool ZigbeeInterface::enable(const QString &serialPort, qint32 baudrate) m_serialPort = nullptr; } + setAvailable(false); + m_serialPort = new QSerialPort(serialPort, this); m_serialPort->setBaudRate(baudrate); m_serialPort->setDataBits(QSerialPort::Data8); @@ -182,12 +213,12 @@ bool ZigbeeInterface::enable(const QString &serialPort, qint32 baudrate) if (!m_serialPort->open(QSerialPort::ReadWrite)) { qCWarning(dcZigbeeInterface()) << "Could not open serial port" << serialPort << baudrate; - delete m_serialPort; - m_serialPort = nullptr; + m_reconnectTimer->start(); return false; } qCDebug(dcZigbeeInterface()) << "Interface enabled successfully on" << serialPort; + setAvailable(true); return true; } @@ -208,7 +239,6 @@ void ZigbeeInterface::sendMessage(const ZigbeeInterfaceMessage &message) { quint16 messageTypeValue = static_cast(message.messageType()); quint16 lengthValue = static_cast(message.data().count()); - quint8 crcValue = calculateCrc(messageTypeValue, lengthValue, message.data()); qCDebug(dcZigbeeInterface()) << "-->" << message << "|" << "crc:" << ZigbeeUtils::convertByteToHexString(crcValue) << ", length:" << ZigbeeUtils::convertUint16ToHexString(lengthValue); @@ -221,7 +251,7 @@ void ZigbeeInterface::sendMessage(const ZigbeeInterfaceMessage &message) streamByte(crcValue); for (int i = 0; i < message.data().count(); i++) { - streamByte(message.data().at(i)); + streamByte(static_cast(message.data().at(i))); } streamByte(0x03, true); } diff --git a/libnymea-zigbee/interface/zigbeeinterface.h b/libnymea-zigbee/interface/zigbeeinterface.h index 292ba8d..b45e4f7 100644 --- a/libnymea-zigbee/interface/zigbeeinterface.h +++ b/libnymea-zigbee/interface/zigbeeinterface.h @@ -2,6 +2,7 @@ #define ZIGBEEINTERFACE_H #include +#include #include #include "zigbee.h" @@ -29,11 +30,13 @@ public: QString serialPort() const; private: - QSerialPort *m_serialPort; + QTimer *m_reconnectTimer = nullptr; + QSerialPort *m_serialPort = nullptr; QByteArray m_messageBuffer; + bool m_available = false; // Message parsing - ReadingState m_readingState; + ReadingState m_readingState = WaitForStart; quint8 m_crcValue; quint8 m_currentValue; quint16 m_messageTypeValue; @@ -44,14 +47,15 @@ private: quint8 calculateCrc(const quint16 &messageTypeValue, const quint16 &lenghtValue, const QByteArray &data); void streamByte(quint8 byte, bool specialCharacter = false); - + void setAvailable(bool available); void setReadingState(const ReadingState & state); signals: - void availableChanged(const bool &available); + void availableChanged(bool available); void messageReceived(const ZigbeeInterfaceMessage &message); private slots: + void onReconnectTimeout(); void onReadyRead(); void onError(const QSerialPort::SerialPortError &error); diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index 72ff1ac..e0c46e0 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -10,10 +10,13 @@ SOURCES += \ interface/zigbeeinterfacemessage.cpp \ interface/zigbeeinterfacerequest.cpp \ interface/zigbeeinterfacereply.cpp \ + nxp/nxpzigbeenetworkmanager.cpp \ + zigbeenetwork.cpp \ zigbeenetworkmanager.cpp \ zigbee.cpp \ loggingcategory.cpp \ zigbeebridgecontroller.cpp \ + zigbeesecurityconfiguration.cpp \ zigbeeutils.cpp \ zigbeenode.cpp \ zigbeeaddress.cpp \ @@ -23,10 +26,13 @@ HEADERS += \ interface/zigbeeinterfacemessage.h \ interface/zigbeeinterfacerequest.h \ interface/zigbeeinterfacereply.h \ + nxp/nxpzigbeenetworkmanager.h \ + zigbeenetwork.h \ zigbeenetworkmanager.h \ zigbee.h \ loggingcategory.h \ zigbeebridgecontroller.h \ + zigbeesecurityconfiguration.h \ zigbeeutils.h \ zigbeenode.h \ zigbeeaddress.h \ diff --git a/libnymea-zigbee/loggingcategory.cpp b/libnymea-zigbee/loggingcategory.cpp index a1d62de..45d3f74 100644 --- a/libnymea-zigbee/loggingcategory.cpp +++ b/libnymea-zigbee/loggingcategory.cpp @@ -1,6 +1,6 @@ #include "loggingcategory.h" -Q_LOGGING_CATEGORY(dcZigbee, "Zigbee") +Q_LOGGING_CATEGORY(dcZigbeeNetwork, "ZigbeeNetwork") Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface") Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController") Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic") diff --git a/libnymea-zigbee/loggingcategory.h b/libnymea-zigbee/loggingcategory.h index aa585b8..65a4cc6 100644 --- a/libnymea-zigbee/loggingcategory.h +++ b/libnymea-zigbee/loggingcategory.h @@ -4,7 +4,7 @@ #include #include -Q_DECLARE_LOGGING_CATEGORY(dcZigbee) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetwork) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic) diff --git a/libnymea-zigbee/nxp/nxpzigbeenetworkmanager.cpp b/libnymea-zigbee/nxp/nxpzigbeenetworkmanager.cpp new file mode 100644 index 0000000..a33126e --- /dev/null +++ b/libnymea-zigbee/nxp/nxpzigbeenetworkmanager.cpp @@ -0,0 +1,6 @@ +#include "nxpzigbeenetworkmanager.h" + +NxpZigbeeNetworkManager::NxpZigbeeNetworkManager(QObject *parent) : QObject(parent) +{ + +} diff --git a/libnymea-zigbee/nxp/nxpzigbeenetworkmanager.h b/libnymea-zigbee/nxp/nxpzigbeenetworkmanager.h new file mode 100644 index 0000000..97e0f90 --- /dev/null +++ b/libnymea-zigbee/nxp/nxpzigbeenetworkmanager.h @@ -0,0 +1,17 @@ +#ifndef NXPZIGBEENETWORKMANAGER_H +#define NXPZIGBEENETWORKMANAGER_H + +#include + +class NxpZigbeeNetworkManager : public QObject +{ + Q_OBJECT +public: + explicit NxpZigbeeNetworkManager(QObject *parent = nullptr); + +signals: + +public slots: +}; + +#endif // NXPZIGBEENETWORKMANAGER_H diff --git a/libnymea-zigbee/zigbeebridgecontroller.cpp b/libnymea-zigbee/zigbeebridgecontroller.cpp index f736c42..82c0c03 100644 --- a/libnymea-zigbee/zigbeebridgecontroller.cpp +++ b/libnymea-zigbee/zigbeebridgecontroller.cpp @@ -1,17 +1,15 @@ #include "zigbeebridgecontroller.h" #include "loggingcategory.h" +#include "zigbeeutils.h" -ZigbeeBridgeController::ZigbeeBridgeController(const QString &serialPort, qint32 baudrate, QObject *parent) : +#include + +ZigbeeBridgeController::ZigbeeBridgeController(QObject *parent) : QObject(parent) { m_interface = new ZigbeeInterface(this); - + connect(m_interface, &ZigbeeInterface::availableChanged, this, &ZigbeeBridgeController::availableChanged); connect(m_interface, &ZigbeeInterface::messageReceived, this, &ZigbeeBridgeController::onMessageReceived); - - if (!m_interface->enable(serialPort, baudrate)) { - qCCritical(dcZigbeeController()) << "Could not enable ZigbeeInterface on" << serialPort; - return; - } } bool ZigbeeBridgeController::available() const @@ -19,6 +17,290 @@ bool ZigbeeBridgeController::available() const return m_interface->available(); } +ZigbeeInterfaceReply *ZigbeeBridgeController::commandResetController() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeReset, QByteArray())); + request.setDescription("Reset controller"); + request.setTimoutIntervall(5000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandErasePersistantData() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeErasePersistentData, QByteArray())); + request.setDescription("Erase persistent data"); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandGetVersion() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeGetVersion, QByteArray())); + request.setDescription("Get version"); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeVersionList); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandSetExtendedPanId(quint64 extendedPanId) +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << extendedPanId; + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetExtendetPanId, data)); + request.setDescription("Set extended PAN id " + QString::number(extendedPanId) + " " + ZigbeeUtils::convertUint64ToHexString(extendedPanId)); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandSetChannelMask(quint32 channelMask) +{ + // Note: 10 < value < 27 -> using sinle channel value + // 0x07fff800 select from all channels 11 - 26 + // 0x2108800 primary zigbee light link channels 11, 15, 20, 25 + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << channelMask; + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetChannelMask, data)); + request.setDescription("Set channel mask " + ZigbeeUtils::convertByteArrayToHexString(data)); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandSetNodeType(ZigbeeNode::NodeType nodeType) +{ + quint8 deviceTypeValue = 0; + if (nodeType == ZigbeeNode::NodeTypeEndDevice) { + qCWarning(dcZigbeeController()) << "Set the controller as EndDevice is not allowed. Default to coordinator node type."; + deviceTypeValue = static_cast(ZigbeeNode::NodeTypeCoordinator); + } else { + deviceTypeValue = static_cast(nodeType); + } + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << deviceTypeValue; + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetDeviceType, data)); + + switch (nodeType) { + case ZigbeeNode::NodeTypeCoordinator: + request.setDescription("Set device type coordinator"); + break; + case ZigbeeNode::NodeTypeRouter: + request.setDescription("Set device type router"); + break; + default: + break; + } + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandStartNetwork() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeStartNetwork, QByteArray())); + request.setDescription("Start network"); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkJoinedFormed); + request.setTimoutIntervall(12000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandStartScan() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeStartScan, QByteArray())); + request.setDescription("Start scan"); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkJoinedFormed); + request.setTimoutIntervall(12000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandPermitJoin(quint16 targetAddress, const quint8 advertisingIntervall, bool tcSignificance) +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << targetAddress; + stream << advertisingIntervall; + stream << static_cast(tcSignificance); + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePermitJoiningRequest, data)); + request.setDescription("Permit joining request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress) + " for " + QString::number(advertisingIntervall) + "[s]"); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandGetPermitJoinStatus() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeGetPermitJoining, QByteArray())); + request.setDescription("Get permit joining status"); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeGetPermitJoiningResponse); + request.setTimoutIntervall(1000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandRequestLinkQuality(quint16 shortAddress) +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << shortAddress; + stream << static_cast(0); + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeManagementLqiRequest, data)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeManagementLqiResponse); + request.setDescription("Request link quality request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); + request.setTimoutIntervall(5000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandEnableWhiteList() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNetworkWhitelistEnable, QByteArray())); + request.setDescription("Enable whitelist"); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandInitiateTouchLink() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeInitiateTouchlink, QByteArray())); + request.setDescription("Initiate touch link"); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandTouchLinkFactoryReset() +{ + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeTouchlinkFactoryReset, QByteArray())); + request.setDescription("Touch link factory reset"); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandNetworkAddressRequest(quint16 targetAddress, quint64 extendedAddress) +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << targetAddress; + stream << extendedAddress; + stream << static_cast(1); + stream << static_cast(0); + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNetworkAdressRequest, data)); + request.setDescription("Network address request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkAdressResponse); + request.setTimoutIntervall(1000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandSetSecurityStateAndKey(quint8 keyState, quint8 keySequence, quint8 keyType, const QString &key) +{ + // Note: calls ZPS_vAplSecSetInitialSecurityState + + // Key state: + // ZPS_ZDO_PRECONFIGURED_LINK_KEY = 3 + // This key will be used to encrypt the network key. This is the master or manufacturer key + + // ZPS_ZDO_ZLL_LINK_KEY = 4 + // This key will be generated by the trust center. + + // Key Type: + // ZPS_APS_UNIQUE_LINK_KEY = + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << keyState; + stream << keySequence; + stream << keyType; + stream << QByteArray::fromHex(key.toUtf8()); + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetSecurity, data)); + request.setDescription("Set security configuration"); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandAuthenticateDevice(const ZigbeeAddress &ieeeAddress, const QString &key) +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << ieeeAddress.toUInt64(); + stream << QByteArray::fromHex(key.toUtf8()); + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeAuthenticateDeviceRequest, data)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeAuthenticateDeviceResponse); + request.setDescription(QString("Authenticate device %1").arg(ieeeAddress.toString())); + request.setTimoutIntervall(5000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandNodeDescriptorRequest(quint16 shortAddress) +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << shortAddress; + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse); + request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); + request.setTimoutIntervall(5000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandSimpleDescriptorRequest(quint16 shortAddress, 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) + "endpoint " + QString::number(endpoint)); + request.setTimoutIntervall(5000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandPowerDescriptorRequest(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(5000); + + return sendRequest(request); +} + +ZigbeeInterfaceReply *ZigbeeBridgeController::commandUserDescriptorRequest(quint16 shortAddress, quint16 address) +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << shortAddress; + stream << address; + + ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeUserDescriptorRequest, data)); + request.setExpectedAdditionalMessageType(Zigbee::MessageTypeUserDescriptorResponse); + request.setDescription("Node user descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress) + " " + ZigbeeUtils::convertUint16ToHexString(address)); + request.setTimoutIntervall(5000); + + return sendRequest(request); +} + void ZigbeeBridgeController::sendMessage(ZigbeeInterfaceReply *reply) { if (!reply) @@ -72,6 +354,16 @@ void ZigbeeBridgeController::onReplyTimeout() } +bool ZigbeeBridgeController::enable(const QString &serialPort, qint32 baudrate) +{ + return m_interface->enable(serialPort, baudrate); +} + +void ZigbeeBridgeController::disable() +{ + m_interface->disable(); +} + ZigbeeInterfaceReply *ZigbeeBridgeController::sendRequest(const ZigbeeInterfaceRequest &request) { // Create Reply diff --git a/libnymea-zigbee/zigbeebridgecontroller.h b/libnymea-zigbee/zigbeebridgecontroller.h index f634ba2..c081950 100644 --- a/libnymea-zigbee/zigbeebridgecontroller.h +++ b/libnymea-zigbee/zigbeebridgecontroller.h @@ -5,6 +5,7 @@ #include #include "zigbee.h" +#include "zigbeenode.h" #include "interface/zigbeeinterface.h" #include "interface/zigbeeinterfacereply.h" #include "interface/zigbeeinterfacerequest.h" @@ -14,10 +15,33 @@ class ZigbeeBridgeController : public QObject { Q_OBJECT public: - explicit ZigbeeBridgeController(const QString &serialPort, qint32 baudrate, QObject *parent = nullptr); + explicit ZigbeeBridgeController(QObject *parent = nullptr); bool available() const; + // Direct commands + ZigbeeInterfaceReply *commandResetController(); + ZigbeeInterfaceReply *commandErasePersistantData(); + ZigbeeInterfaceReply *commandGetVersion(); + ZigbeeInterfaceReply *commandSetExtendedPanId(quint64 extendedPanId); + ZigbeeInterfaceReply *commandSetChannelMask(quint32 channelMask = 0x07fff800); + ZigbeeInterfaceReply *commandSetNodeType(ZigbeeNode::NodeType nodeType); + ZigbeeInterfaceReply *commandStartNetwork(); + ZigbeeInterfaceReply *commandStartScan(); + ZigbeeInterfaceReply *commandPermitJoin(quint16 targetAddress = 0xfffc, const quint8 advertisingIntervall = 180, bool tcSignificance = false); + ZigbeeInterfaceReply *commandGetPermitJoinStatus(); + ZigbeeInterfaceReply *commandRequestLinkQuality(quint16 shortAddress); + ZigbeeInterfaceReply *commandEnableWhiteList(); + ZigbeeInterfaceReply *commandInitiateTouchLink(); + ZigbeeInterfaceReply *commandTouchLinkFactoryReset(); + ZigbeeInterfaceReply *commandNetworkAddressRequest(quint16 targetAddress, quint64 extendedAddress); + ZigbeeInterfaceReply *commandSetSecurityStateAndKey(quint8 keyState, quint8 keySequence, quint8 keyType, const QString &key); + ZigbeeInterfaceReply *commandAuthenticateDevice(const ZigbeeAddress &ieeeAddress, const QString &key); + ZigbeeInterfaceReply *commandNodeDescriptorRequest(quint16 shortAddress); + ZigbeeInterfaceReply *commandSimpleDescriptorRequest(quint16 shortAddress, quint8 endpoint); + ZigbeeInterfaceReply *commandPowerDescriptorRequest(quint16 shortAddress); + ZigbeeInterfaceReply *commandUserDescriptorRequest(quint16 shortAddress, quint16 address); + private: ZigbeeInterface *m_interface = nullptr; ZigbeeInterfaceReply *m_currentReply = nullptr; @@ -27,6 +51,7 @@ private: void sendMessage(ZigbeeInterfaceReply *reply); signals: + void availableChanged(bool available); void messageReceived(const ZigbeeInterfaceMessage &message); private slots: @@ -34,8 +59,10 @@ private slots: void onReplyTimeout(); public slots: - ZigbeeInterfaceReply *sendRequest(const ZigbeeInterfaceRequest &request); + bool enable(const QString &serialPort, qint32 baudrate); + void disable(); + ZigbeeInterfaceReply *sendRequest(const ZigbeeInterfaceRequest &request); }; diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp new file mode 100644 index 0000000..ac1c80a --- /dev/null +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -0,0 +1,143 @@ +#include "zigbeenetwork.h" +#include "loggingcategory.h" + +ZigbeeNetwork::ZigbeeNetwork(ControllerType controllerType, QObject *parent) : + ZigbeeNode(parent), + m_controllerType(controllerType) +{ + +} + +ZigbeeNetwork::State ZigbeeNetwork::state() const +{ + return m_state; +} + +ZigbeeNetwork::ControllerType ZigbeeNetwork::controlerType() const +{ + return m_controllerType; +} + +ZigbeeNetwork::Error ZigbeeNetwork::error() const +{ + return m_error; +} + +QString ZigbeeNetwork::serialPortName() const +{ + return m_serialPortName; +} + +void ZigbeeNetwork::setSerialPortName(const QString &serialPortName) +{ + m_serialPortName = serialPortName; +} + +qint32 ZigbeeNetwork::serialBaudrate() const +{ + return m_serialBaudrate; +} + +void ZigbeeNetwork::setSerialBaudrate(qint32 baudrate) +{ + m_serialBaudrate = baudrate; +} + +quint64 ZigbeeNetwork::extendedPanId() const +{ + return m_extendedPanId; +} + +void ZigbeeNetwork::setExtendedPanId(quint64 extendedPanId) +{ + m_extendedPanId = extendedPanId; +} + +uint ZigbeeNetwork::channel() const +{ + return m_channel; +} + +void ZigbeeNetwork::setChannel(uint channel) +{ + m_channel = channel; +} + +ZigbeeSecurityConfiguration ZigbeeNetwork::securityConfiguration() const +{ + return m_securityConfiguration; +} + +void ZigbeeNetwork::setSecurityConfiguration(const ZigbeeSecurityConfiguration &securityConfiguration) +{ + m_securityConfiguration = securityConfiguration; +} + +QList ZigbeeNetwork::nodes() const +{ + return m_nodes; +} + +ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) +{ + foreach (ZigbeeNode *node, m_nodes) { + if (node->shortAddress() == shortAddress) { + return node; + } + } + + return nullptr; +} + +ZigbeeNode *ZigbeeNetwork::getZigbeeNode(ZigbeeAddress address) +{ + foreach (ZigbeeNode *node, m_nodes) { + if (node->extendedAddress() == address) { + return node; + } + } + + return nullptr; +} + +void ZigbeeNetwork::addNode(ZigbeeNode *node) +{ + if (m_nodes.contains(node)) { + qCWarning(dcZigbeeNetwork()) << "The node" << node << "has already been added."; + return; + } + + m_nodes.append(node); + emit nodeAdded(node); +} + +void ZigbeeNetwork::removeNode(ZigbeeNode *node) +{ + if (!m_nodes.contains(node)) { + qCWarning(dcZigbeeNetwork()) << "Try to remove node" << node << "but not in the node list."; + return; + } + + m_nodes.removeAll(node); + emit nodeRemoved(node); +} + +void ZigbeeNetwork::setState(ZigbeeNetwork::State state) +{ + if (m_state == state) + return; + + qCDebug(dcZigbeeNetwork()) << "State changed" << state; + m_state = state; + emit stateChanged(m_state); +} + +void ZigbeeNetwork::setError(ZigbeeNetwork::Error error) +{ + if (m_error == error) + return; + + if (m_error != ErrorNoError) qCDebug(dcZigbeeNetwork()) << "Error occured" << error; + m_error = error; + emit errorOccured(m_error); +} diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h new file mode 100644 index 0000000..b2802d5 --- /dev/null +++ b/libnymea-zigbee/zigbeenetwork.h @@ -0,0 +1,99 @@ +#ifndef ZIGBEENETWORK_H +#define ZIGBEENETWORK_H + +#include + +#include "zigbeenode.h" +#include "zigbeesecurityconfiguration.h" + +class ZigbeeNetwork : public ZigbeeNode +{ + Q_OBJECT + +public: + enum ControllerType { + ControlerTypeNxp + }; + Q_ENUM(ControllerType) + + enum State { + StateDisconnected, + StateStarting, + StateRunning, + StateStopping + }; + Q_ENUM(State) + + enum Error { + ErrorNoError, + ErrorHardwareUnavailable + }; + Q_ENUM(Error) + + explicit ZigbeeNetwork(ControllerType controllerType, QObject *parent = nullptr); + + State state() const; + ControllerType controlerType() const; + + Error error() const; + + // Serial port configuration + QString serialPortName() const; + void setSerialPortName(const QString &serialPortName); + + qint32 serialBaudrate() const; + void setSerialBaudrate(qint32 baudrate); + + // Network configurations + quint64 extendedPanId() const; + void setExtendedPanId(quint64 extendedPanId); + + uint channel() const; + void setChannel(uint channel); + + ZigbeeSecurityConfiguration securityConfiguration() const; + void setSecurityConfiguration(const ZigbeeSecurityConfiguration &securityConfiguration); + + QList nodes() const; + + ZigbeeNode *getZigbeeNode(quint16 shortAddress); + ZigbeeNode *getZigbeeNode(ZigbeeAddress address); + +private: + ControllerType m_controllerType = ControlerTypeNxp; + State m_state = StateDisconnected; + Error m_error = ErrorNoError; + + // Serial port configuration + QString m_serialPortName = "/dev/ttyUSB0"; + qint32 m_serialBaudrate = 115200; + + // Network configurations + quint64 m_extendedPanId = 0; + uint m_channel = 0; + ZigbeeSecurityConfiguration m_securityConfiguration; + ZigbeeNode::NodeType m_nodeType = ZigbeeNode::NodeTypeCoordinator; + + QList m_nodes; + +protected: + void addNode(ZigbeeNode *node); + void removeNode(ZigbeeNode *node); + + void setState(State state); + void setError(Error error); + +signals: + void nodeAdded(ZigbeeNode *node); + void nodeRemoved(ZigbeeNode *node); + + void stateChanged(State state); + void errorOccured(Error error); + +public slots: + virtual void startNetwork() = 0; + virtual void stopNetwork() = 0; + +}; + +#endif // ZIGBEENETWORK_H diff --git a/libnymea-zigbee/zigbeenetworkmanager.cpp b/libnymea-zigbee/zigbeenetworkmanager.cpp index e2dc14b..80cbf81 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.cpp +++ b/libnymea-zigbee/zigbeenetworkmanager.cpp @@ -6,55 +6,47 @@ #include #include -ZigbeeNetworkManager::ZigbeeNetworkManager(const int &channel, const QString &serialPort, qint32 baudrate, QObject *parent) : - ZigbeeNode(new ZigbeeBridgeController(serialPort, baudrate, parent), parent), - m_serialPort(serialPort) +ZigbeeNetworkManager::ZigbeeNetworkManager(QObject *parent) : + ZigbeeNetwork(ZigbeeNetwork::ControlerTypeNxp, parent) { - 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; - } + //connect(controller(), &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived); - QSettings settings; - qCDebug(dcZigbee()) << "Loading settings from" << settings.fileName(); - settings.beginGroup("Network"); - m_extendedPanId = static_cast(settings.value("panId", 0).toLongLong()); - qCDebug(dcZigbee()) << "Loading saved pan id" << m_extendedPanId; - if (m_extendedPanId == 0) { - m_extendedPanId = generateRandomPanId(); - settings.setValue("panId", m_extendedPanId); - } - settings.endGroup(); + //Q_UNUSED(channel) + // if (controller()->available()) { + // qCDebug(dcZigbeeNetwork()) << "Bridge controller started successfully on" << controller; + // } else { + // qCCritical(dcZigbeeNetwork()) << "The zigbee controller is not available on" << controller; + // return; + // } - qCDebug(dcZigbee()) << "PAN Id:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId); + // QSettings settings; + // qCDebug(dcZigbeeNetwork()) << "Loading settings from" << settings.fileName(); + // settings.beginGroup("Network"); + // m_extendedPanId = static_cast(settings.value("panId", 0).toLongLong()); + // qCDebug(dcZigbeeNetwork()) << "Loading saved pan id" << m_extendedPanId; + // if (m_extendedPanId == 0) { + // m_extendedPanId = generateRandomPanId(); + // settings.setValue("panId", m_extendedPanId); + // } + // settings.endGroup(); - // 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."; - } + // qCDebug(dcZigbeeNetwork()) << "PAN Id:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId); - loadNetwork(); - resetController(); - getVersion(); - init(); -} + // // 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(dcZigbeeNetwork()) << "Using quitest channel for the zigbee network."; + // } else { + // channelMask |= 1 << (channel); + // qCDebug(dcZigbeeNetwork()) << "Using channel" << channel << "for the zigbee network."; + // } -bool ZigbeeNetworkManager::isAvailable() const -{ - if (m_controller){ - return m_controller->available(); - } - - return false; + // loadNetwork(); + // resetController(); + // getVersion(); + // init(); } QString ZigbeeNetworkManager::controllerVersion() const @@ -62,375 +54,147 @@ QString ZigbeeNetworkManager::controllerVersion() const return m_controllerVersion; } -QString ZigbeeNetworkManager::serialPort() const -{ - return m_serialPort; -} - -QList ZigbeeNetworkManager::nodeList() const -{ - return m_nodeList; -} - -quint64 ZigbeeNetworkManager::extendedPanId() const -{ - return m_extendedPanId; -} - bool ZigbeeNetworkManager::networkRunning() const { - return m_networkRunning; + return state() == ZigbeeNetwork::StateRunning; } -quint64 ZigbeeNetworkManager::generateRandomPanId() +void ZigbeeNetworkManager::setStartingState(ZigbeeNetworkManager::StartingState state) { - srand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); - srand(qrand()); - return (ULLONG_MAX - 0) * (qrand()/(double)RAND_MAX); -} + if (m_startingState == state) + return; -void ZigbeeNetworkManager::parseNetworkFormed(const QByteArray &data) -{ - // Parse network status - quint8 networkStatus = static_cast(data.at(0)); - QString networkStatusString; + qCDebug(dcZigbeeNetwork()) << state; + m_startingState = state; - if (networkStatus == 0) { - networkStatusString = "joined"; - } else if (networkStatus == 1) { - networkStatusString = "created"; - } else if (networkStatus >= 128 && networkStatus <= 244) { - networkStatusString = "failed: Zigbee event code: " + QString::number(networkStatus); - } else { - networkStatusString = "unknown"; - } - - quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(data.mid(1, 2)); - quint64 extendedAddress = ZigbeeUtils::convertByteArrayToUint64(data.mid(3, 8)); - - // Parse network channel - quint8 channel = static_cast(data.at(11)); - - qCDebug(dcZigbee()).noquote() << "Network" << networkStatusString; - qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); - qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(extendedAddress); - qCDebug(dcZigbee()) << " Channel:" << channel; - - // Set the node information - setShortAddress(shortAddress); - setExtendedAddress(ZigbeeAddress(extendedAddress)); - -} - -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(5000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onResetControllerFinished); -} - -void ZigbeeNetworkManager::erasePersistentData() -{ - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeErasePersistentData)); - request.setDescription("Erase persistent data"); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onErasePersistentDataFinished); -} - -void ZigbeeNetworkManager::sendDataManagerAvailableResponse() -{ - ZigbeeInterfaceMessage message; - message.setMessageType(Zigbee::MessageTypeDataManagerAvailableResponse); - message.setData(QByteArray::fromRawData("\x00\x00", 2)); - - ZigbeeInterfaceRequest request(message); - request.setDescription("Data manager available response"); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, reply, &ZigbeeInterfaceReply::deleteLater); -} - -void ZigbeeNetworkManager::getVersion() -{ - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeGetVersion)); - request.setDescription("Get version"); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeVersionList); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onGetVersionFinished); -} - -void ZigbeeNetworkManager::setExtendedPanId(const quint64 &panId) -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << panId; - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetExtendetPanId, data)); - request.setDescription("Set extended PAN id " + QString::number(panId) + " " + ZigbeeUtils::convertUint64ToHexString(panId)); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetExtendedPanIdFinished); -} - -void ZigbeeNetworkManager::setChannelMask(const quint32 &channelMask) -{ - // Note: 10 < value < 27 -> using sinle channel value - // 0x07fff800 select from all channels 11 - 26 - // 0x2108800 primary zigbee light link channels 11, 15, 20, 25 - - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << channelMask; - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetChannelMask, data)); - request.setDescription("Set channel mask " + ZigbeeUtils::convertByteArrayToHexString(data)); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetChannelMaskFinished); -} - -void ZigbeeNetworkManager::setDeviceType(const NodeType &deviceType) -{ - quint8 deviceTypeValue = static_cast(deviceType); - - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << deviceTypeValue; - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetDeviceType, data)); - - switch (deviceType) { - case NodeTypeCoordinator: - request.setDescription("Set device type coordinator"); + switch (m_startingState) { + case StartingStateNone: break; - case NodeTypeRouter: - request.setDescription("Set device type router"); - break; - default: + case StartingStateErase: { + ZigbeeInterfaceReply *reply = m_controller->commandErasePersistantData(); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandErasePersistentDataFinished); break; } - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetDeviceTypeFinished); -} - -void ZigbeeNetworkManager::startNetwork() -{ - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeStartNetwork)); - request.setDescription("Start network"); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkJoinedFormed); - request.setTimoutIntervall(12000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onStartNetworkFinished); -} - -void ZigbeeNetworkManager::startScan() -{ - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeStartScan)); - request.setDescription("Start scan"); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkJoinedFormed); - request.setTimoutIntervall(12000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onStartScanFinished); -} - -void ZigbeeNetworkManager::permitJoining(quint16 targetAddress, const quint8 advertisingIntervall, bool tcSignificance) -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << targetAddress; - stream << advertisingIntervall; - stream << static_cast(tcSignificance); - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePermitJoiningRequest, data)); - request.setDescription("Permit joining request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress) + " for " + QString::number(advertisingIntervall) + "[s]"); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onPermitJoiningFinished); -} - -void ZigbeeNetworkManager::requestLinkQuality() -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << shortAddress(); - stream << static_cast(0); - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeManagementLqiRequest, data)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeManagementLqiResponse); - request.setDescription("Request link quality request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress())); - request.setTimoutIntervall(5000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestLinkQualityFinished); - -} - -void ZigbeeNetworkManager::getPermitJoiningStatus() -{ - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeGetPermitJoining)); - request.setDescription("Get permit joining status"); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeGetPermitJoiningResponse); - request.setTimoutIntervall(1000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onGetPermitJoiningStatusFinished); -} - -void ZigbeeNetworkManager::enableWhitelist() -{ - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNetworkWhitelistEnable)); - request.setDescription("Enable whitelist"); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onEnableWhitelistFinished); -} - -void ZigbeeNetworkManager::initiateTouchLink() -{ - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeInitiateTouchlink)); - request.setDescription("Initiate touch link"); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onInitiateTouchLinkFinished); -} - -void ZigbeeNetworkManager::touchLinkFactoryReset() -{ - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeTouchlinkFactoryReset)); - request.setDescription("Touch link factory reset"); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onTouchLinkFactoryResetFinished); -} - -void ZigbeeNetworkManager::networkAddressRequest(quint16 targetAddress, quint64 extendedAddress) -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << targetAddress; - stream << extendedAddress; - stream << static_cast(1); - stream << static_cast(0); - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNetworkAdressRequest, data)); - request.setDescription("Network address request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkAdressResponse); - request.setTimoutIntervall(1000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onNetworkAddressRequestFinished); + case StartingStateReset: { + ZigbeeInterfaceReply *reply = m_controller->commandResetController(); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandResetControllerFinished); + break; + } + case StartingStateGetVersion: { + ZigbeeInterfaceReply *reply = m_controller->commandGetVersion(); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandGetVersionFinished); + break; + } + case StartingStateSetPanId: { + if (extendedPanId() == 0) { + setExtendedPanId(ZigbeeUtils::generateRandomPanId()); + } + ZigbeeInterfaceReply *reply = m_controller->commandSetExtendedPanId(extendedPanId()); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSetExtendedPanIdFinished); + break; + } + case StartingStateSetChannel: { + // Create channel mask + // Note: normal number passed, that specific channel will be used || Bitfield: all channels would be 0x07FFF800 + quint32 channelMask = 0; + if (channel() == 0) { + qCDebug(dcZigbeeNetwork()) << "Autoselect quitest channel for the zigbee network."; + } else { + channelMask |= 1 << (channel()); + qCDebug(dcZigbeeNetwork()) << "Using channel" << channel() << "for the zigbee network."; + } + ZigbeeInterfaceReply *reply = m_controller->commandSetChannelMask(channelMask); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSetChannelMaskFinished); + break; + } + case StartingStateSetSecurity: { + ZigbeeInterfaceReply *reply = m_controller->commandSetSecurityStateAndKey(4, 0, 1, "5A6967426565416C6C69616E63653039"); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSetSecurityFinished); + break; + } + case StartingStateStartNetwork: { + ZigbeeInterfaceReply *reply = m_controller->commandStartNetwork(); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandStartNetworkFinished); + break; + } + case StartingStateReadeNodeDescriptor: { + ZigbeeInterfaceReply *reply = m_controller->commandNodeDescriptorRequest(shortAddress()); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished); + break; + } + case StartingStateReadSimpleDescriptor: { + ZigbeeInterfaceReply *reply = m_controller->commandSimpleDescriptorRequest(shortAddress(), endPoint()); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished); + break; + } + case StartingStateReadPowerDescriptor: { + ZigbeeInterfaceReply *reply = m_controller->commandPowerDescriptorRequest(shortAddress()); + connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished); + break; + } + } } -void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile) -{ +//void ZigbeeNetworkManager::parseNetworkFormed(const QByteArray &data) +//{ +// // Parse network status +// quint8 networkStatus = static_cast(data.at(0)); +// QString networkStatusString; - // TargetAddress profile InputClusterCount InputClusterList OutputClusterCount OutputClusterList +// if (networkStatus == 0) { +// networkStatusString = "joined"; +// } else if (networkStatus == 1) { +// networkStatusString = "created"; +// } else if (networkStatus >= 128 && networkStatus <= 244) { +// networkStatusString = "failed: Zigbee event code: " + QString::number(networkStatus); +// } else { +// networkStatusString = "unknown"; +// } - Q_UNUSED(profile) +// quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(data.mid(1, 2)); +// quint64 extendedAddress = ZigbeeUtils::convertByteArrayToUint64(data.mid(3, 8)); - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << shortAddress; - stream << static_cast(0xFFFF); - stream << static_cast(0); - stream << static_cast(0); - stream << static_cast(0); - stream << static_cast(0); +// // Parse network channel +// quint8 channel = static_cast(data.at(11)); - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeMatchDescriptorRequest, data)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeMatchDescriptorResponse); - request.setDescription("Request match descriptors " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); - request.setTimoutIntervall(5000); +// qCDebug(dcZigbeeNetwork()).noquote() << "Network" << networkStatusString; +// qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); +// qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(extendedAddress); +// qCDebug(dcZigbeeNetwork()) << " Channel:" << channel; - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestMatchDescriptorFinished); -} +// // Set the node information +// setShortAddress(shortAddress); +// setExtendedAddress(ZigbeeAddress(extendedAddress)); -void ZigbeeNetworkManager::setInitialSecurity(quint8 keyState, quint8 keySequence, quint8 keyType, const QString &key) -{ - // Note: calls ZPS_vAplSecSetInitialSecurityState +//} - // Key state: - // ZPS_ZDO_PRECONFIGURED_LINK_KEY = 3 - // This key will be used to encrypt the network key. This is the master or manufacturer key +//void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile) +//{ - // ZPS_ZDO_ZLL_LINK_KEY = 4 - // This key will be generated by the trust center. +// // TargetAddress profile InputClusterCount InputClusterList OutputClusterCount OutputClusterList - // Key Type: - // ZPS_APS_UNIQUE_LINK_KEY = +// Q_UNUSED(profile) - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << keyState; - stream << keySequence; - stream << keyType; - stream << QByteArray::fromHex(key.toUtf8()); +// QByteArray data; +// QDataStream stream(&data, QIODevice::WriteOnly); +// stream << shortAddress; +// stream << static_cast(0xFFFF); +// stream << static_cast(0); +// stream << static_cast(0); +// stream << static_cast(0); +// stream << static_cast(0); - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetSecurity, data)); - request.setDescription("Set security configuration"); +// ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeMatchDescriptorRequest, data)); +// request.setExpectedAdditionalMessageType(Zigbee::MessageTypeMatchDescriptorResponse); +// request.setDescription("Request match descriptors " + ZigbeeUtils::convertUint16ToHexString(shortAddress)); +// request.setTimoutIntervall(5000); - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetSecurityFinished); -} +// ZigbeeInterfaceReply *reply = controller()->sendRequest(request); +// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestMatchDescriptorFinished); +//} -void ZigbeeNetworkManager::authenticateDevice(const ZigbeeAddress &ieeeAddress) -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << ieeeAddress.toUInt64(); - stream << QByteArray::fromHex("5A6967426565416C6C69616E63653039"); - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeAuthenticateDeviceRequest, data)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeAuthenticateDeviceResponse); - request.setDescription(QString("Authenticate device %1").arg(ieeeAddress.toString())); - request.setTimoutIntervall(5000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onAuthenticateDeviceFinished); -} - -void ZigbeeNetworkManager::onResetControllerFinished() +void ZigbeeNetworkManager::onCommandResetControllerFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -443,7 +207,7 @@ void ZigbeeNetworkManager::onResetControllerFinished() qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; } -void ZigbeeNetworkManager::onErasePersistentDataFinished() +void ZigbeeNetworkManager::onCommandErasePersistentDataFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -454,9 +218,10 @@ void ZigbeeNetworkManager::onErasePersistentDataFinished() } qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; + if (m_startingState == StartingStateErase) setStartingState(StartingStateReset); } -void ZigbeeNetworkManager::onGetVersionFinished() +void ZigbeeNetworkManager::onCommandGetVersionFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -478,10 +243,40 @@ void ZigbeeNetworkManager::onGetVersionFinished() quint16 minorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(2, 2)); m_controllerVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion); - qCDebug(dcZigbee()) << "Version:" << m_controllerVersion; + qCDebug(dcZigbeeNetwork()) << "Controller version:" << m_controllerVersion; + + if (m_startingState == StartingStateGetVersion) setStartingState(StartingStateSetPanId); } -void ZigbeeNetworkManager::onSetExtendedPanIdFinished() +void ZigbeeNetworkManager::onCommandSetExtendedPanIdFinished() +{ + 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"; + if (m_startingState == StartingStateSetPanId) setStartingState(StartingStateSetChannel); +} + +void ZigbeeNetworkManager::onCommandSetChannelMaskFinished() +{ + 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"; + if (m_startingState == StartingStateSetChannel) setStartingState(StartingStateSetSecurity); +} + +void ZigbeeNetworkManager::onCommandSetDeviceTypeFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -494,53 +289,23 @@ void ZigbeeNetworkManager::onSetExtendedPanIdFinished() qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; } -void ZigbeeNetworkManager::onSetChannelMaskFinished() +void ZigbeeNetworkManager::onCommandStartNetworkFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); if (reply->status() != ZigbeeInterfaceReply::Success) { - qCWarning(dcZigbee()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); - return; - } - - qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; -} - -void ZigbeeNetworkManager::onSetDeviceTypeFinished() -{ - 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::onStartNetworkFinished() -{ - ZigbeeInterfaceReply *reply = static_cast(sender()); - reply->deleteLater(); - - if (reply->status() != ZigbeeInterfaceReply::Success) { - qCWarning(dcZigbee()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); + qCWarning(dcZigbeeNetwork()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); return; } qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; qCDebug(dcZigbeeController()) << reply->additionalMessage(); - - parseNetworkFormed(reply->additionalMessage().data()); - - init(); - - loadNetwork(); + processNetworkFormed(reply->additionalMessage()); + if (m_startingState == StartingStateStartNetwork) setStartingState(StartingStateReadeNodeDescriptor); } -void ZigbeeNetworkManager::onStartScanFinished() +void ZigbeeNetworkManager::onCommandStartScanFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -552,12 +317,10 @@ void ZigbeeNetworkManager::onStartScanFinished() qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; qCDebug(dcZigbeeController()) << reply->additionalMessage(); - - parseNetworkFormed(reply->additionalMessage().data()); - + processNetworkFormed(reply->additionalMessage()); } -void ZigbeeNetworkManager::onGetPermitJoiningStatusFinished() +void ZigbeeNetworkManager::onCommandGetPermitJoiningStatusFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -571,7 +334,7 @@ void ZigbeeNetworkManager::onGetPermitJoiningStatusFinished() qCDebug(dcZigbeeController()) << reply->additionalMessage(); } -void ZigbeeNetworkManager::onPermitJoiningFinished() +void ZigbeeNetworkManager::onCommandPermitJoiningFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -584,7 +347,7 @@ void ZigbeeNetworkManager::onPermitJoiningFinished() qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; } -void ZigbeeNetworkManager::onRequestMatchDescriptorFinished() +void ZigbeeNetworkManager::onCommandRequestMatchDescriptorFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -598,7 +361,7 @@ void ZigbeeNetworkManager::onRequestMatchDescriptorFinished() qCDebug(dcZigbeeController()) << reply->additionalMessage(); } -void ZigbeeNetworkManager::onSetSecurityFinished() +void ZigbeeNetworkManager::onCommandSetSecurityFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -609,9 +372,10 @@ void ZigbeeNetworkManager::onSetSecurityFinished() } qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; + if (m_startingState == StartingStateSetSecurity) setStartingState(StartingStateStartNetwork); } -void ZigbeeNetworkManager::onNetworkAddressRequestFinished() +void ZigbeeNetworkManager::onCommandNetworkAddressRequestFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -631,17 +395,17 @@ void ZigbeeNetworkManager::onNetworkAddressRequestFinished() quint8 deviceCount = static_cast(reply->additionalMessage().data().at(12)); quint8 startIndex = static_cast(reply->additionalMessage().data().at(13)); - qCDebug(dcZigbee()) << "Network address response:"; - qCDebug(dcZigbee()) << " SQN:" << sequenceNumber; - qCDebug(dcZigbee()) << " Status:" << statusCode; - qCDebug(dcZigbee()) << " Address:" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress); - qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress); - qCDebug(dcZigbee()) << " Deice count:" << deviceCount; - qCDebug(dcZigbee()) << " Start index:" << startIndex; + qCDebug(dcZigbeeNetwork()) << "Network address response:"; + qCDebug(dcZigbeeNetwork()) << " SQN:" << sequenceNumber; + qCDebug(dcZigbeeNetwork()) << " Status:" << statusCode; + qCDebug(dcZigbeeNetwork()) << " Address:" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress); + qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress); + qCDebug(dcZigbeeNetwork()) << " Deice count:" << deviceCount; + qCDebug(dcZigbeeNetwork()) << " Start index:" << startIndex; } -void ZigbeeNetworkManager::onAuthenticateDeviceFinished() +void ZigbeeNetworkManager::onCommandAuthenticateDeviceFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -664,18 +428,55 @@ void ZigbeeNetworkManager::onAuthenticateDeviceFinished() quint64 extendedPanId = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(40, 8)); - qCDebug(dcZigbee()) << "Authentication response:"; - qCDebug(dcZigbee()) << " Gateways address:" << ZigbeeAddress(gatewayIeeeAddress); - qCDebug(dcZigbee()) << " Key:" << encryptedKey; - qCDebug(dcZigbee()) << " MIC:" << mic.toHex(); - qCDebug(dcZigbee()) << " Initiator address:" << ZigbeeAddress(initiatorIeeeAddress); - qCDebug(dcZigbee()) << " Active key sequence number:" << activeKeySequenceNumber; - qCDebug(dcZigbee()) << " Channel:" << channel; - qCDebug(dcZigbee()) << " Short PAN ID:" << ZigbeeUtils::convertUint16ToHexString(shortPan); - qCDebug(dcZigbee()) << " Extended PAN ID:" << extendedPanId << ZigbeeUtils::convertUint64ToHexString(extendedPanId); + qCDebug(dcZigbeeNetwork()) << "Authentication response:"; + qCDebug(dcZigbeeNetwork()) << " Gateways address:" << ZigbeeAddress(gatewayIeeeAddress); + qCDebug(dcZigbeeNetwork()) << " Key:" << encryptedKey; + qCDebug(dcZigbeeNetwork()) << " MIC:" << mic.toHex(); + qCDebug(dcZigbeeNetwork()) << " Initiator address:" << ZigbeeAddress(initiatorIeeeAddress); + qCDebug(dcZigbeeNetwork()) << " Active key sequence number:" << activeKeySequenceNumber; + qCDebug(dcZigbeeNetwork()) << " Channel:" << channel; + qCDebug(dcZigbeeNetwork()) << " Short PAN ID:" << ZigbeeUtils::convertUint16ToHexString(shortPan); + qCDebug(dcZigbeeNetwork()) << " Extended PAN ID:" << extendedPanId << ZigbeeUtils::convertUint64ToHexString(extendedPanId); } -void ZigbeeNetworkManager::onEnableWhitelistFinished() +void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &message) +{ + // Parse network status + QByteArray data = message.data(); + quint8 networkStatus = static_cast(data.at(0)); + QString networkStatusString; + + if (networkStatus == 0) { + networkStatusString = "joined"; + } else if (networkStatus == 1) { + networkStatusString = "created"; + } else if (networkStatus >= 128 && networkStatus <= 244) { + networkStatusString = "failed: Zigbee event code: " + QString::number(networkStatus); + } else { + networkStatusString = "unknown"; + } + + quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(data.mid(1, 2)); + quint64 extendedAddress = ZigbeeUtils::convertByteArrayToUint64(data.mid(3, 8)); + + // Parse network channel + quint8 channel = static_cast(data.at(11)); + + qCDebug(dcZigbeeNetwork()).noquote() << "Network" << networkStatusString; + qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); + qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(extendedAddress); + qCDebug(dcZigbeeNetwork()) << " Channel:" << channel; + + // Set the node information + setShortAddress(shortAddress); + setExtendedAddress(ZigbeeAddress(extendedAddress)); + setChannel(channel); + + addNode(this); + +} + +void ZigbeeNetworkManager::onCommandEnableWhitelistFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -688,7 +489,287 @@ void ZigbeeNetworkManager::onEnableWhitelistFinished() qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; } -void ZigbeeNetworkManager::onInitiateTouchLinkFinished() +void ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished() +{ + 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)); + + Q_UNUSED(sequenceNumber) + Q_UNUSED(status) + + quint16 shortAddress = static_cast(reply->additionalMessage().data().at(2)); + shortAddress <<= 8; + shortAddress |= reply->additionalMessage().data().at(3); + + quint16 manufacturerCode = static_cast(reply->additionalMessage().data().at(4)); + manufacturerCode <<= 8; + manufacturerCode |= reply->additionalMessage().data().at(5); + + quint16 maximalRxSize = static_cast(reply->additionalMessage().data().at(6)); + maximalRxSize <<= 8; + maximalRxSize |= reply->additionalMessage().data().at(7); + + quint16 maximalTxSize = static_cast(reply->additionalMessage().data().at(8)); + maximalTxSize <<= 8; + maximalTxSize |= reply->additionalMessage().data().at(9); + + quint16 serverMask = static_cast(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 = static_cast(reply->additionalMessage().data().at(15)); + bitField <<= 8; + bitField |= reply->additionalMessage().data().at(16); + + // Get node object + ZigbeeNode *node = getZigbeeNode(shortAddress); + + // Set node data + node->setManufacturerCode(manufacturerCode); + node->setMaximumRxSize(maximalRxSize); + node->setMaximumTxSize(maximalTxSize); + node->setMaximumBufferSize(maxBufferSize); + node->setServerMask(serverMask); + node->setDescriptorFlag(descriptorFlag); + node->setMacCapabilitiesFlag(macFlags); + + // Parse bit field + bool isCoordinator = ((bitField >> 0) & 0x0001); + bool isRouter = ((bitField >> 1) & 0x0001); + bool isEndDevice = ((bitField >> 2) & 0x0001); + + node->setComplexDescriptorAvailable((bitField >> 3) & 0x0001); + node->setUserDescriptorAvailable((bitField >> 4) & 0x0001); + + if (isCoordinator && !isRouter && !isEndDevice) { + node->setNodeType(NodeTypeCoordinator); + } else if (!isCoordinator && isRouter && !isEndDevice) { + node->setNodeType(NodeTypeRouter); + } else if (!isCoordinator && !isRouter && isEndDevice) { + node->setNodeType(NodeTypeEndDevice); + } + + + // qCDebug(dcZigbeeNetwork()) << "Node descriptor:"; + // qCDebug(dcZigbeeNetwork()) << " Node type:" << node->nodeType(); + // qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + // qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); + // qCDebug(dcZigbeeNetwork()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); + // qCDebug(dcZigbeeNetwork()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode); + // qCDebug(dcZigbeeNetwork()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(node->maximumRxSize()); + // qCDebug(dcZigbeeNetwork()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(node->maximumTxSize()); + // qCDebug(dcZigbeeNetwork()) << " Server mask:" << ZigbeeUtils::convertUint16ToHexString(serverMask); + // qCDebug(dcZigbeeNetwork()) << " Primary Trust center:" << m_isPrimaryTrustCenter; + // qCDebug(dcZigbeeNetwork()) << " Backup Trust center:" << m_isBackupTrustCenter; + // qCDebug(dcZigbeeNetwork()) << " Primary Binding cache:" << m_isPrimaryBindingCache; + // qCDebug(dcZigbeeNetwork()) << " Backup Binding cache:" << m_isBackupBindingCache; + // qCDebug(dcZigbeeNetwork()) << " Primary Discovery cache:" << m_isPrimaryDiscoveryCache; + // qCDebug(dcZigbeeNetwork()) << " Backup Discovery cache:" << m_isBackupDiscoveryCache; + // qCDebug(dcZigbeeNetwork()) << " Network Manager:" << m_isNetworkManager; + // qCDebug(dcZigbeeNetwork()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorFlag); + // qCDebug(dcZigbeeNetwork()) << " Extended active endpoint list available:" << extendedActiveEndpointListAvailable; + // qCDebug(dcZigbeeNetwork()) << " Extended simple descriptor list available:" << extendedSimpleDescriptorListAvailable; + // qCDebug(dcZigbeeNetwork()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macFlags); + // qCDebug(dcZigbeeNetwork()) << " Receiver on when idle:" << m_receiverOnWhenIdle; + // qCDebug(dcZigbeeNetwork()) << " Security capability:" << m_securityCapability; + // qCDebug(dcZigbeeNetwork()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(maxBufferSize); + // qCDebug(dcZigbeeNetwork()) << " Bit field:" << ZigbeeUtils::convertUint16ToHexString(bitField); + // qCDebug(dcZigbeeNetwork()) << " Is coordinator:" << isCoordinator; + // qCDebug(dcZigbeeNetwork()) << " Is router:" << isRouter; + // qCDebug(dcZigbeeNetwork()) << " Is end device:" << isEndDevice; + // qCDebug(dcZigbeeNetwork()) << " Complex desciptor available:" << complexDescriptorAvailable; + // qCDebug(dcZigbeeNetwork()) << " User desciptor available:" << userDescriptorAvailable; + + if (m_startingState == StartingStateReadeNodeDescriptor) setStartingState(StartingStateReadSimpleDescriptor); +} + +void ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished() +{ + 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 = static_cast(reply->additionalMessage().data().at(2)); + nwkAddress <<= 8; + nwkAddress |= reply->additionalMessage().data().at(3); + + quint8 length = static_cast(reply->additionalMessage().data().at(4)); + + if (length == 0) { + qCWarning(dcZigbeeNetwork()) << "Length 0"; + return; + } + + quint8 endPoint = static_cast(reply->additionalMessage().data().at(5)); + + quint16 profileId = static_cast(reply->additionalMessage().data().at(6)); + profileId <<= 8; + profileId |= reply->additionalMessage().data().at(7); + + quint16 deviceId = static_cast(reply->additionalMessage().data().at(8)); + deviceId <<= 8; + deviceId |= reply->additionalMessage().data().at(9); + + quint8 bitField = static_cast(reply->additionalMessage().data().at(10)); + + qCDebug(dcZigbeeNetwork()) << "Node simple descriptor:"; + qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); + qCDebug(dcZigbeeNetwork()) << " Nwk address:" << ZigbeeUtils::convertUint16ToHexString(nwkAddress); + qCDebug(dcZigbeeNetwork()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); + qCDebug(dcZigbeeNetwork()) << " End Point:" << ZigbeeUtils::convertByteToHexString(endPoint); + qCDebug(dcZigbeeNetwork()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast(profileId)); + + if (profileId == Zigbee::ZigbeeProfileLightLink) { + qCDebug(dcZigbeeNetwork()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); + } else { + qCDebug(dcZigbeeNetwork()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId) << static_cast(deviceId); + } + + qCDebug(dcZigbeeNetwork()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField); + + quint8 inputClusterCount = static_cast(reply->additionalMessage().data().at(10)); + + qCDebug(dcZigbeeNetwork()) << " Input clusters:"; + QByteArray inputClusterListData = reply->additionalMessage().data().mid(11, inputClusterCount * 2); + for (int i = 0; i < inputClusterListData.count(); i+=2) { + quint16 clusterId = static_cast(inputClusterListData.at(i)); + clusterId <<= 8; + clusterId |= inputClusterListData .at(i+1); + + qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + } + + quint8 outputClusterCount = static_cast(reply->additionalMessage().data().at(12 + inputClusterCount * 2)); + + qCDebug(dcZigbeeNetwork()) << " Output clusters:"; + QByteArray outputClusterListData = reply->additionalMessage().data().mid(12 + inputClusterCount * 2, outputClusterCount * 2); + for (int i = 0; i < outputClusterListData.count(); i+=2) { + quint16 clusterId = static_cast(outputClusterListData.at(i)); + clusterId <<= 8; + clusterId |= outputClusterListData .at(i+1); + + qCDebug(dcZigbeeNetwork()) << " Cluster ID:" << ZigbeeUtils::convertUint16ToHexString(clusterId) << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + } + + if (m_startingState == StartingStateReadSimpleDescriptor) setStartingState(StartingStateReadPowerDescriptor); +} + +void ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished() +{ + 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 = static_cast(reply->additionalMessage().data().at(2)); + bitField <<= 8; + bitField |= reply->additionalMessage().data().at(3); + + // Bit 0 - 3 Power mode + // 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor + // 0001: Receiver switched on periodically + // 0010: Receiver switched on when stimulated, e.g. by pressing a button + + if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { + m_powerMode = PowerModeAlwaysOn; + } else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { + m_powerMode = PowerModeOnPeriodically; + } else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) { + m_powerMode = PowerModeOnWhenStimulated; + } + + // Bit 4 - 7 Available power sources + // Bit 0: Permanent mains supply + // Bit 1: Rechargeable battery + // Bit 2: Disposable battery + // Bit 4: Reserved + + if (ZigbeeUtils::checkBitUint16(bitField, 4)) { + m_availablePowerSources.append(PowerSourcePermanentMainSupply); + } else if (ZigbeeUtils::checkBitUint16(bitField, 5)) { + m_availablePowerSources.append(PowerSourceRecharchableBattery); + } else if (ZigbeeUtils::checkBitUint16(bitField, 6)) { + m_availablePowerSources.append(PowerSourceDisposableBattery); + } + + // Bit 8 - 11 Active source: according to the same schema as available power sources + if (ZigbeeUtils::checkBitUint16(bitField, 8)) { + m_powerSource = PowerSourcePermanentMainSupply; + } else if (ZigbeeUtils::checkBitUint16(bitField, 9)) { + m_powerSource = PowerSourceRecharchableBattery; + } else if (ZigbeeUtils::checkBitUint16(bitField, 10)) { + m_powerSource = PowerSourceDisposableBattery; + } + + // Bit 12 - 15: Battery level if available + // 0000: Critically low + // 0100: Approximately 33% + // 1000: Approximately 66% + // 1100: Approximately 100% (near fully charged) + + if (!ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) { + m_powerLevel = PowerLevelCriticalLow; + } else if (ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) { + m_powerLevel = PowerLevelLow; + } else if (!ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) { + m_powerLevel = PowerLevelOk; + } else if (ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) { + m_powerLevel = PowerLevelFull; + } + + qCDebug(dcZigbeeNetwork()) << "Node power descriptor:"; + qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); + qCDebug(dcZigbeeNetwork()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField); + qCDebug(dcZigbeeNetwork()) << " Power mode:" << m_powerMode; + qCDebug(dcZigbeeNetwork()) << " Available power sources:"; + foreach (const PowerSource &source, m_availablePowerSources) { + qCDebug(dcZigbeeNetwork()) << " " << source; + } + qCDebug(dcZigbeeNetwork()) << " Power source:" << m_powerSource; + qCDebug(dcZigbeeNetwork()) << " Power level:" << m_powerLevel; + + if (m_startingState == StartingStateReadPowerDescriptor) { + setStartingState(StartingStateNone); + setState(StateRunning); + } +} + +void ZigbeeNetworkManager::onCommandInitiateTouchLinkFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -701,7 +782,7 @@ void ZigbeeNetworkManager::onInitiateTouchLinkFinished() qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; } -void ZigbeeNetworkManager::onTouchLinkFactoryResetFinished() +void ZigbeeNetworkManager::onCommandTouchLinkFactoryResetFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -714,7 +795,7 @@ void ZigbeeNetworkManager::onTouchLinkFactoryResetFinished() qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; } -void ZigbeeNetworkManager::onRequestLinkQualityFinished() +void ZigbeeNetworkManager::onCommandRequestLinkQualityFinished() { ZigbeeInterfaceReply *reply = static_cast(sender()); reply->deleteLater(); @@ -733,18 +814,18 @@ void ZigbeeNetworkManager::onRequestLinkQualityFinished() quint8 neighborTableListCount = static_cast(reply->additionalMessage().data().at(3)); quint8 startIndex = static_cast(reply->additionalMessage().data().at(4)); - qCDebug(dcZigbee()) << "LQI response:"; - qCDebug(dcZigbee()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); - qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(statusCode); - qCDebug(dcZigbee()) << " Neighbor table entries:" << neighborTableEntries; - qCDebug(dcZigbee()) << " Neighbor table list count:" << neighborTableListCount; - qCDebug(dcZigbee()) << " Start index:" << startIndex; + qCDebug(dcZigbeeNetwork()) << "LQI response:"; + qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(statusCode); + qCDebug(dcZigbeeNetwork()) << " Neighbor table entries:" << neighborTableEntries; + qCDebug(dcZigbeeNetwork()) << " Neighbor table list count:" << neighborTableListCount; + qCDebug(dcZigbeeNetwork()) << " Start index:" << startIndex; int offset = 5; // Note: according to docs, if the table has no neigbors the list will be empty if (neighborTableEntries == 0) { - qCDebug(dcZigbee()) << " There are no neigbors"; + qCDebug(dcZigbeeNetwork()) << " There are no neigbors"; return; } @@ -759,15 +840,15 @@ void ZigbeeNetworkManager::onRequestLinkQualityFinished() offset += 21; - qCDebug(dcZigbee()) << " Neighbor:" << i; - qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); - qCDebug(dcZigbee()) << " PAN id:" << panId; - qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress); - qCDebug(dcZigbee()) << " Depth:" << depth; - qCDebug(dcZigbee()) << " Link quality:" << linkQuality; - qCDebug(dcZigbee()) << " BitMap:" << ZigbeeUtils::convertByteToHexString(bitMap); + qCDebug(dcZigbeeNetwork()) << " Neighbor:" << i; + qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); + qCDebug(dcZigbeeNetwork()) << " PAN id:" << panId; + qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress); + qCDebug(dcZigbeeNetwork()) << " Depth:" << depth; + qCDebug(dcZigbeeNetwork()) << " Link quality:" << linkQuality; + qCDebug(dcZigbeeNetwork()) << " BitMap:" << ZigbeeUtils::convertByteToHexString(bitMap); - foreach (ZigbeeNode *node, m_nodeList) { + foreach (ZigbeeNode *node, nodes()) { if (node->extendedAddress() == ZigbeeAddress(ieeeAddress)) { node->setShortAddress(shortAddress); } @@ -837,7 +918,9 @@ void ZigbeeNetworkManager::processFactoryNewRestart(const ZigbeeInterfaceMessage break; } - qCDebug(dcZigbee()) << "Restart finished. Current controller state:" << controllerStatusString; + + qCDebug(dcZigbeeNetwork()) << "Restart finished. Current controller state:" << controllerStatusString; + if (m_startingState == StartingStateReset) setStartingState(StartingStateGetVersion); } void ZigbeeNetworkManager::processNodeClusterList(const ZigbeeInterfaceMessage &message) @@ -856,7 +939,7 @@ void ZigbeeNetworkManager::processNodeClusterList(const ZigbeeInterfaceMessage & QByteArray clusterListData = message.data().right(message.data().count() - 3); for (int i = 0; i < clusterListData.count(); i += 2) { - quint16 clusterId = clusterListData.at(i); + quint16 clusterId = static_cast(clusterListData.at(i)); clusterId <<= 8; clusterId |= clusterListData .at(i + 1); @@ -899,7 +982,7 @@ void ZigbeeNetworkManager::processNodeCommandIdList(const ZigbeeInterfaceMessage QByteArray commandListData = message.data().right(message.data().count() - 5); for (int i = 0; i < commandListData.count(); i++) { - quint8 attribute = commandListData.at(i); + quint8 attribute = static_cast(commandListData.at(i)); qCDebug(dcZigbeeController()) << " Command:" << ZigbeeUtils::convertByteToHexString(attribute); } } @@ -911,20 +994,22 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m quint8 macCapability = static_cast(message.data().at(10)); - qCDebug(dcZigbee()) << "Device announced:"; - qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); - qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress); - qCDebug(dcZigbee()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapability); + qCDebug(dcZigbeeNetwork()) << "Device announced:"; + qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress); + qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress); + qCDebug(dcZigbeeNetwork()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapability); - ZigbeeNode *node = new ZigbeeNode(controller(), this); + ZigbeeNode *node = new ZigbeeNode(this); node->setShortAddress(shortAddress); node->setExtendedAddress(ZigbeeAddress(ieeeAddress)); - m_nodeList.append(node); + // FIXME: check if node already added, and if we have to update it + // Start node initialization process + addNode(node); - node->init(); + //node->init(); - saveNetwork(); + //saveNetwork(); } void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &message) @@ -941,23 +1026,23 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage & 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); + qCDebug(dcZigbeeNetwork()) << "Attribute report:"; + qCDebug(dcZigbeeNetwork()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); + qCDebug(dcZigbeeNetwork()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceAddress); + qCDebug(dcZigbeeNetwork()) << " End point:" << ZigbeeUtils::convertByteToHexString(endPoint); + qCDebug(dcZigbeeNetwork()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast(clusterId)); + qCDebug(dcZigbeeNetwork()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId); + qCDebug(dcZigbeeNetwork()) << " Attribut status:" << ZigbeeUtils::convertByteToHexString(attributStatus); + qCDebug(dcZigbeeNetwork()) << " Attribut data type:" << dataType; + qCDebug(dcZigbeeNetwork()) << " Attribut size:" << attributeSize; + qCDebug(dcZigbeeNetwork()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(data); switch (dataType) { case Zigbee::CharString: - qCDebug(dcZigbee()) << " Data(converted)" << QString::fromUtf8(data); + qCDebug(dcZigbeeNetwork()) << " Data(converted)" << QString::fromUtf8(data); break; case Zigbee::Bool: - qCDebug(dcZigbee()) << " Data(converted)" << QVariant(data).toBool(); + qCDebug(dcZigbeeNetwork()) << " Data(converted)" << QVariant(data).toBool(); break; default: break; @@ -972,7 +1057,7 @@ void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage & quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(0, 2)); quint8 rejoining = static_cast(message.data().at(2)); - qCDebug(dcZigbee()) << "Node leaving:" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << rejoining; + qCDebug(dcZigbeeNetwork()) << "Node leaving:" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << rejoining; // TODO: remove node } @@ -985,21 +1070,48 @@ void ZigbeeNetworkManager::processRestartProvisioned(const ZigbeeInterfaceMessag quint8 status = static_cast(message.data().at(0)); switch (status) { case 0: - qCDebug(dcZigbee()) << "Restart provisioned: start up"; + qCDebug(dcZigbeeNetwork()) << "Restart provisioned: start up"; break; case 2: - qCDebug(dcZigbee()) << "Restart provisioned: NFN start"; + qCDebug(dcZigbeeNetwork()) << "Restart provisioned: NFN start"; break; case 6: - qCDebug(dcZigbee()) << "Restart provisioned: running"; + qCDebug(dcZigbeeNetwork()) << "Restart provisioned: running"; break; default: - qCDebug(dcZigbee()) << "Restart provisioned: unknown"; + qCDebug(dcZigbeeNetwork()) << "Restart provisioned: unknown"; break; } } +void ZigbeeNetworkManager::startNetwork() +{ + if (m_controller) { + delete m_controller; + m_controller = nullptr; + } + + m_controller = new ZigbeeBridgeController(this); + connect(m_controller, &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived); + connect(m_controller, &ZigbeeBridgeController::availableChanged, this, &ZigbeeNetworkManager::onControllerAvailableChanged); + + if (!m_controller->enable(serialPortName(), serialBaudrate())) { + setState(StateDisconnected); + setStartingState(StartingStateNone); + setError(ErrorHardwareUnavailable); + } else { + // Reset + setState(StateStarting); + setStartingState(StartingStateErase); + } +} + +void ZigbeeNetworkManager::stopNetwork() +{ + +} + void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &message) { switch (message.messageType()) { @@ -1028,7 +1140,7 @@ void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &messa processLeaveIndication(message); break; case Zigbee::MessageTypeNetworkJoinedFormed: - parseNetworkFormed(message.data()); + processNetworkFormed(message); break; case Zigbee::MessageTypeRestartProvisioned: processRestartProvisioned(message); @@ -1039,4 +1151,18 @@ void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &messa } } +void ZigbeeNetworkManager::onControllerAvailableChanged(bool available) +{ + qCDebug(dcZigbeeNetwork()) << "Hardware controller is" << (available ? "now available" : "not available"); + + if (!available) { + setError(ErrorHardwareUnavailable); + setState(StateDisconnected); + } else { + setError(ErrorNoError); + setState(StateStarting); + setStartingState(StartingStateErase); + } +} + diff --git a/libnymea-zigbee/zigbeenetworkmanager.h b/libnymea-zigbee/zigbeenetworkmanager.h index 99c6c48..f26cccf 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.h +++ b/libnymea-zigbee/zigbeenetworkmanager.h @@ -3,100 +3,77 @@ #include -#include "zigbeenode.h" +#include "zigbeenetwork.h" #include "zigbeeaddress.h" #include "zigbeebridgecontroller.h" +#include "zigbeesecurityconfiguration.h" -class ZigbeeNetworkManager : public ZigbeeNode +class ZigbeeNetworkManager : public ZigbeeNetwork { Q_OBJECT public: - explicit ZigbeeNetworkManager(const int &channel = 0, const QString &serialPort = "/dev/ttyS0", qint32 baudrate = 115200, QObject *parent = nullptr); - - bool isAvailable() const; + explicit ZigbeeNetworkManager(QObject *parent = nullptr); QString controllerVersion() const; - QString serialPort() const; - QList nodeList() const; - quint64 extendedPanId() const; bool networkRunning() const; - // Controller methods - void resetController(); - void erasePersistentData(); - void sendDataManagerAvailableResponse(); - void getVersion(); - void setExtendedPanId(const quint64 &panId); - void setChannelMask(const quint32 &channelMask = 0x07fff800); - void setDeviceType(const NodeType &deviceType); - void startNetwork(); - void startScan(); - - void permitJoining(quint16 targetAddress = 0xfffc, const quint8 advertisingIntervall = 180, bool tcSignificance = false); - - void requestLinkQuality(); - - void getPermitJoiningStatus(); - void enableWhitelist(); - - void initiateTouchLink(); - void touchLinkFactoryReset(); - - void networkAddressRequest(quint16 targetAddress, quint64 extendedAddress); - - void requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile); - - void setInitialSecurity(quint8 keyState, quint8 keySequence, quint8 keyType, const QString &key); - - void authenticateDevice(const ZigbeeAddress &ieeeAddress); - private: + enum StartingState { + StartingStateNone, + StartingStateErase, + StartingStateReset, + StartingStateGetVersion, + StartingStateSetPanId, + StartingStateSetChannel, + StartingStateSetSecurity, + StartingStateStartNetwork, + StartingStateReadeNodeDescriptor, + StartingStateReadSimpleDescriptor, + StartingStateReadPowerDescriptor + }; + ZigbeeBridgeController *m_controller = nullptr; - QString m_serialPort; QString m_controllerVersion; - quint64 m_extendedPanId = 0; - QList m_nodeList; - - bool m_networkRunning = false; - - quint64 generateRandomPanId(); - - void parseNetworkFormed(const QByteArray &data); + StartingState m_startingState = StartingStateNone; + void setStartingState(StartingState state); signals: void runningChanged(const bool &running); private slots: void onMessageReceived(const ZigbeeInterfaceMessage &message); + void onControllerAvailableChanged(bool available); - void loadNetwork(); - void saveNetwork(); + // Controller command finished slots + void onCommandResetControllerFinished(); + void onCommandErasePersistentDataFinished(); + void onCommandGetVersionFinished(); + void onCommandSetExtendedPanIdFinished(); + void onCommandSetChannelMaskFinished(); + void onCommandSetDeviceTypeFinished(); + void onCommandStartNetworkFinished(); + void onCommandStartScanFinished(); + void onCommandGetPermitJoiningStatusFinished(); + void onCommandPermitJoiningFinished(); + void onCommandEnableWhitelistFinished(); - // Controller methods finished slots - void onResetControllerFinished(); - void onErasePersistentDataFinished(); - void onGetVersionFinished(); - void onSetExtendedPanIdFinished(); - void onSetChannelMaskFinished(); - void onSetDeviceTypeFinished(); - void onStartNetworkFinished(); - void onStartScanFinished(); - void onGetPermitJoiningStatusFinished(); - void onPermitJoiningFinished(); - void onEnableWhitelistFinished(); + void onCommandNodeDescriptorRequestFinished(); + void onCommandSimpleDescriptorRequestFinished(); + void onCommandPowerDescriptorRequestFinished(); - void onInitiateTouchLinkFinished(); - void onTouchLinkFactoryResetFinished(); - void onRequestLinkQualityFinished(); + void onCommandInitiateTouchLinkFinished(); + void onCommandTouchLinkFactoryResetFinished(); + void onCommandRequestLinkQualityFinished(); - void onRequestMatchDescriptorFinished(); - void onSetSecurityFinished(); - void onNetworkAddressRequestFinished(); - void onAuthenticateDeviceFinished(); + void onCommandRequestMatchDescriptorFinished(); + void onCommandSetSecurityFinished(); + void onCommandNetworkAddressRequestFinished(); + void onCommandAuthenticateDeviceFinished(); // Process controller notifications/messages + void processNetworkFormed(const ZigbeeInterfaceMessage &message); void processLoggingMessage(const ZigbeeInterfaceMessage &message); void processFactoryNewRestart(const ZigbeeInterfaceMessage &message); void processNodeClusterList(const ZigbeeInterfaceMessage &message); @@ -106,6 +83,11 @@ private slots: void processAttributeReport(const ZigbeeInterfaceMessage &message); void processLeaveIndication(const ZigbeeInterfaceMessage &message); void processRestartProvisioned(const ZigbeeInterfaceMessage &message); + +public slots: + void startNetwork() override; + void stopNetwork() override; + }; #endif // ZIGBEEMANAGER_H diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index ffbaf5a..fb4450d 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -4,6 +4,12 @@ #include +ZigbeeNode::ZigbeeNode(QObject *parent) : + QObject(parent) +{ + +} + quint16 ZigbeeNode::shortAddress() const { return m_shortAddress; @@ -14,7 +20,7 @@ ZigbeeAddress ZigbeeNode::extendedAddress() const return m_extendedAddress; } -int ZigbeeNode::endPoint() const +quint8 ZigbeeNode::endPoint() const { return m_endPoint; } @@ -29,9 +35,9 @@ ZigbeeNode::FrequencyBand ZigbeeNode::frequencyBand() const return m_frequencyBand; } -ZigbeeNode::Relationship ZigbeeNode::relationShip() const +ZigbeeNode::Relationship ZigbeeNode::relationship() const { - return m_relationShip; + return m_relationship; } Zigbee::ZigbeeProfile ZigbeeNode::profile() const @@ -44,6 +50,31 @@ quint16 ZigbeeNode::manufacturerCode() const return m_manufacturerCode; } +bool ZigbeeNode::complexDescriptorAvailable() const +{ + return m_complexDescriptorAvailable; +} + +bool ZigbeeNode::userDescriptorAvailable() const +{ + return m_userDescriptorAvailable; +} + +quint16 ZigbeeNode::maximumRxSize() const +{ + return m_maximumRxSize; +} + +quint16 ZigbeeNode::maximumTxSize() const +{ + return m_maximumTxSize; +} + +quint8 ZigbeeNode::maximumBufferSize() const +{ + return m_maximumBufferSize; +} + ZigbeeNode::PowerMode ZigbeeNode::powerMode() const { return m_powerMode; @@ -64,16 +95,9 @@ ZigbeeNode::PowerLevel ZigbeeNode::powerLevel() const return m_powerLevel; } -void ZigbeeNode::init() -{ - requestNodeDescription(); - requestSimpleNodeDescription(); - requestPowerDescriptor(); -} - -void ZigbeeNode::identify() -{ +//void ZigbeeNode::identify() +//{ // QByteArray data; // QDataStream stream(&data, QIODevice::WriteOnly); // stream << m_shortAddress; @@ -86,98 +110,26 @@ void ZigbeeNode::identify() // ZigbeeInterfaceReply *reply = controller()->sendRequest(request); // connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestLinkQuality); -} +//} -void ZigbeeNode::toggle(int addressMode) -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << static_cast(addressMode); // adress mode - stream << m_shortAddress; - stream << static_cast(1); // source endpoint - stream << static_cast(1); // destination endpoint - stream << static_cast(2); // command toggle +//void ZigbeeNode::toggle(int addressMode) +//{ +// QByteArray data; +// QDataStream stream(&data, QIODevice::WriteOnly); +// stream << static_cast(addressMode); // adress mode +// stream << m_shortAddress; +// stream << static_cast(1); // source endpoint +// stream << static_cast(1); // destination endpoint +// stream << static_cast(2); // command toggle - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeCluserOnOff, data)); - request.setDescription("Toggle request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress)); +// ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeCluserOnOff, data)); +// request.setDescription("Toggle request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress)); - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onToggleFinished); -} +// ZigbeeInterfaceReply *reply = controller()->sendRequest(request); +// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onToggleFinished); +//} -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(5000); - - 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(5000); - - 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(5000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestPowerDescriptorFinished); -} - -void ZigbeeNode::requestUserDescriptor() -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << m_shortAddress; - stream << static_cast(0); - - ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeUserDescriptorRequest, data)); - request.setExpectedAdditionalMessageType(Zigbee::MessageTypeUserDescriptorResponse); - request.setDescription("Node user descriptor request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress)); - request.setTimoutIntervall(5000); - - ZigbeeInterfaceReply *reply = controller()->sendRequest(request); - connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestUserDescriptorFinished); -} - -ZigbeeNode::ZigbeeNode(ZigbeeBridgeController *controller, QObject *parent) : - QObject(parent), - m_controller(controller) -{ - -} - -ZigbeeBridgeController *ZigbeeNode::controller() -{ - return m_controller; -} void ZigbeeNode::setShortAddress(const quint16 &shortAddress) { @@ -189,55 +141,53 @@ void ZigbeeNode::setExtendedAddress(const ZigbeeAddress &extendedAddress) m_extendedAddress = extendedAddress; } -void ZigbeeNode::onRequestNodeDescriptionFinished() +void ZigbeeNode::setEndPoint(quint8 endPoint) { - ZigbeeInterfaceReply *reply = static_cast(sender()); - reply->deleteLater(); + m_endPoint = endPoint; +} - if (reply->status() != ZigbeeInterfaceReply::Success) { - qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); - return; - } +void ZigbeeNode::setNodeType(ZigbeeNode::NodeType nodeType) +{ + m_nodeType = nodeType; +} - qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; +void ZigbeeNode::setFrequencyBand(ZigbeeNode::FrequencyBand frequencyBand) +{ + m_frequencyBand = frequencyBand; +} - quint8 sequenceNumber = static_cast(reply->additionalMessage().data().at(0)); - quint8 status = static_cast(reply->additionalMessage().data().at(1)); +void ZigbeeNode::setRelationship(ZigbeeNode::Relationship relationship) +{ + m_relationship = relationship; +} - quint16 shortAddress = reply->additionalMessage().data().at(2); - shortAddress <<= 8; - shortAddress |= reply->additionalMessage().data().at(3); +void ZigbeeNode::setZigbeeProfile(Zigbee::ZigbeeProfile profile) +{ + m_profile = profile; +} - 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); - - // Set node data +void ZigbeeNode::setManufacturerCode(quint16 manufacturerCode) +{ m_manufacturerCode = manufacturerCode; - m_maximalRxSize = maximalRxSize; - m_maximalTxSize = maximalTxSize; +} - // Parse server mask +void ZigbeeNode::setMaximumRxSize(quint16 size) +{ + m_maximumRxSize = size; +} + +void ZigbeeNode::setMaximumTxSize(quint16 size) +{ + m_maximumTxSize = size; +} + +void ZigbeeNode::setMaximumBufferSize(quint8 size) +{ + m_maximumBufferSize = size; +} + +void ZigbeeNode::setServerMask(quint16 serverMask) +{ m_isPrimaryTrustCenter = ((serverMask >> 0) & 0x0001); m_isBackupTrustCenter = ((serverMask >> 1) & 0x0001); m_isPrimaryBindingCache = ((serverMask >> 2) & 0x0001); @@ -245,298 +195,94 @@ void ZigbeeNode::onRequestNodeDescriptionFinished() m_isPrimaryDiscoveryCache = ((serverMask >> 4) & 0x0001); m_isBackupDiscoveryCache = ((serverMask >> 5) & 0x0001); m_isNetworkManager = ((serverMask >> 6) & 0x0001); +} - // Parse desciptor flag - bool extendedActiveEndpointListAvailable = ((descriptorFlag >> 0) & 0x01); - bool extendedSimpleDescriptorListAvailable = ((descriptorFlag >> 1) & 0x01); +void ZigbeeNode::setComplexDescriptorAvailable(bool complexDescriptorAvailable) +{ + m_complexDescriptorAvailable = complexDescriptorAvailable; +} +void ZigbeeNode::setUserDescriptorAvailable(bool userDescriptorAvailable) +{ + m_userDescriptorAvailable = userDescriptorAvailable; +} + +void ZigbeeNode::setMacCapabilitiesFlag(quint16 macFlag) +{ // Parse MAC capabilities - m_receiverOnWhenIdle = ((macFlags >> 3) & 0x01); - m_securityCapability = ((macFlags >> 6) & 0x01); - - // Parse bit field - bool isCoordinator = ((bitField >> 0) & 0x0001); - bool isRouter = ((bitField >> 1) & 0x0001); - bool isEndDevice = ((bitField >> 2) & 0x0001); - bool complexDescriptorAvailable = ((bitField >> 3) & 0x0001); - bool userDescriptorAvailable = ((bitField >> 4) & 0x0001); - - if (isCoordinator && !isRouter && !isEndDevice) { - m_nodeType = NodeTypeCoordinator; - } else if (!isCoordinator && isRouter && !isEndDevice) { - m_nodeType = NodeTypeRouter; - } else if (!isCoordinator && !isRouter && isEndDevice) { - m_nodeType = NodeTypeEndDevice; + m_alternatePanCoordinator = ((macFlag >> 0) & 0x01); + if (((macFlag >> 1) & 0x01)) { + m_deviceType = DeviceTypeFullFunction; } else { - if (m_isNetworkManager) { - m_nodeType = NodeTypeCoordinator; - } else { - m_nodeType = NodeTypeEndDevice; - } + m_deviceType = DeviceTypeReducedFunction; } - - // Note: Frequency always 2,4 GHz - - qCDebug(dcZigbee()) << "Node descriptor:"; - qCDebug(dcZigbee()) << " Node type:" << m_nodeType; - 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(m_maximalRxSize); - qCDebug(dcZigbee()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximalTxSize); - qCDebug(dcZigbee()) << " Server mask:" << ZigbeeUtils::convertUint16ToHexString(serverMask); - qCDebug(dcZigbee()) << " Primary Trust center:" << m_isPrimaryTrustCenter; - qCDebug(dcZigbee()) << " Backup Trust center:" << m_isBackupTrustCenter; - qCDebug(dcZigbee()) << " Primary Binding cache:" << m_isPrimaryBindingCache; - qCDebug(dcZigbee()) << " Backup Binding cache:" << m_isBackupBindingCache; - qCDebug(dcZigbee()) << " Primary Discovery cache:" << m_isPrimaryDiscoveryCache; - qCDebug(dcZigbee()) << " Backup Discovery cache:" << m_isBackupDiscoveryCache; - qCDebug(dcZigbee()) << " Network Manager:" << m_isNetworkManager; - qCDebug(dcZigbee()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorFlag); - qCDebug(dcZigbee()) << " Extended active endpoint list available:" << extendedActiveEndpointListAvailable; - qCDebug(dcZigbee()) << " Extended simple descriptor list available:" << extendedSimpleDescriptorListAvailable; - qCDebug(dcZigbee()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macFlags); - qCDebug(dcZigbee()) << " Receiver on when idle:" << m_receiverOnWhenIdle; - qCDebug(dcZigbee()) << " Security capability:" << m_securityCapability; - qCDebug(dcZigbee()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(maxBufferSize); - qCDebug(dcZigbee()) << " Bit field:" << ZigbeeUtils::convertUint16ToHexString(bitField); - qCDebug(dcZigbee()) << " Is coordinator:" << isCoordinator; - qCDebug(dcZigbee()) << " Is router:" << isRouter; - qCDebug(dcZigbee()) << " Is end device:" << isEndDevice; - qCDebug(dcZigbee()) << " Complex desciptor available:" << complexDescriptorAvailable; - qCDebug(dcZigbee()) << " User desciptor available:" << userDescriptorAvailable; - - - if (userDescriptorAvailable) { - requestUserDescriptor(); - } - + m_powerSourceFlagMainPower = ((macFlag >> 2) & 0x01); + m_receiverOnWhenIdle = ((macFlag >> 3) & 0x01); + m_securityCapability = ((macFlag >> 6) & 0x01); + m_allocateAddress = ((macFlag >> 7) & 0x01); } -void ZigbeeNode::onRequestSimpleNodeDescriptionFinished() +void ZigbeeNode::setDescriptorFlag(quint8 descriptorFlag) { - 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)); - - if (length == 0) { - qCWarning(dcZigbee()) << "Length 0"; - return; - } - - 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)); - } - + m_extendedActiveEndpointListAvailable = ((descriptorFlag >> 0) & 0x01); + m_extendedSimpleDescriptorListAvailable = ((descriptorFlag >> 1) & 0x01); } -void ZigbeeNode::onRequestPowerDescriptorFinished() -{ - ZigbeeInterfaceReply *reply = static_cast(sender()); - reply->deleteLater(); +//void ZigbeeNode::onRequestUserDescriptorFinished() +//{ +// ZigbeeInterfaceReply *reply = static_cast(sender()); +// reply->deleteLater(); - if (reply->status() != ZigbeeInterfaceReply::Success) { - qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); - return; - } +// 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(); +// 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)); +// 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); +// quint16 nwkAddress = static_cast(reply->additionalMessage().data().at(2)); +// nwkAddress <<= 8; +// nwkAddress |= reply->additionalMessage().data().at(3); - // Bit 0 - 3 Power mode - // 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor - // 0001: Receiver switched on periodically - // 0010: Receiver switched on when stimulated, e.g. by pressing a button +// quint8 length = static_cast(reply->additionalMessage().data().at(4)); - if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { - m_powerMode = PowerModeAlwaysOn; - } else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) { - m_powerMode = PowerModeOnPeriodically; - } else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) { - m_powerMode = PowerModeOnWhenStimulated; - } +// QByteArray data; +// if (length > 0) { +// data = reply->additionalMessage().data().mid(5, length); +// } - // Bit 4 - 7 Available power sources - // Bit 0: Permanent mains supply - // Bit 1: Rechargeable battery - // Bit 2: Disposable battery - // Bit 4: Reserved +// qCDebug(dcZigbeeNetwork()) << "User descriptor:"; +// qCDebug(dcZigbeeNetwork()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); +// qCDebug(dcZigbeeNetwork()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); +// qCDebug(dcZigbeeNetwork()) << " Attribute address:" << ZigbeeUtils::convertUint16ToHexString(nwkAddress); +// qCDebug(dcZigbeeNetwork()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); +// qCDebug(dcZigbeeNetwork()) << " Data:" << data; +//} - if (ZigbeeUtils::checkBitUint16(bitField, 4)) { - m_availablePowerSources.append(PowerSourcePermanentMainSupply); - } else if (ZigbeeUtils::checkBitUint16(bitField, 5)) { - m_availablePowerSources.append(PowerSourceRecharchableBattery); - } else if (ZigbeeUtils::checkBitUint16(bitField, 6)) { - m_availablePowerSources.append(PowerSourceDisposableBattery); - } +//void ZigbeeNode::onToggleFinished() +//{ +// ZigbeeInterfaceReply *reply = static_cast(sender()); +// reply->deleteLater(); - // Bit 8 - 11 Active source: according to the same schema as available power sources - if (ZigbeeUtils::checkBitUint16(bitField, 8)) { - m_powerSource = PowerSourcePermanentMainSupply; - } else if (ZigbeeUtils::checkBitUint16(bitField, 9)) { - m_powerSource = PowerSourceRecharchableBattery; - } else if (ZigbeeUtils::checkBitUint16(bitField, 10)) { - m_powerSource = PowerSourceDisposableBattery; - } +// if (reply->status() != ZigbeeInterfaceReply::Success) { +// qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage(); +// return; +// } - // Bit 12 - 15: Battery level if available - // 0000: Critically low - // 0100: Approximately 33% - // 1000: Approximately 66% - // 1100: Approximately 100% (near fully charged) +// qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully"; +//} - if (!ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) { - m_powerLevel = PowerLevelCriticalLow; - } else if (ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) { - m_powerLevel = PowerLevelLow; - } else if (!ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) { - m_powerLevel = PowerLevelOk; - } else if (ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) { - m_powerLevel = PowerLevelFull; - } - - qCDebug(dcZigbee()) << "Node power descriptor:"; - qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); - qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); - qCDebug(dcZigbee()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField); - qCDebug(dcZigbee()) << " Power mode:" << m_powerMode; - qCDebug(dcZigbee()) << " Available power sources:"; - foreach (const PowerSource &source, m_availablePowerSources) { - qCDebug(dcZigbee()) << " " << source; - } - qCDebug(dcZigbee()) << " Power source:" << m_powerSource; - qCDebug(dcZigbee()) << " Power level:" << m_powerLevel; - -} - -void ZigbeeNode::onRequestUserDescriptorFinished() -{ - 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)); - - QByteArray data; - if (length > 0) { - data = reply->additionalMessage().data().mid(5, length); - } - - qCDebug(dcZigbee()) << "User descriptor:"; - qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber); - qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status); - qCDebug(dcZigbee()) << " Attribute address:" << ZigbeeUtils::convertUint16ToHexString(nwkAddress); - qCDebug(dcZigbee()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length); - qCDebug(dcZigbee()) << " Data:" << data; -} - -void ZigbeeNode::onToggleFinished() -{ - 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 ZigbeeNode::onIdentifyFinished() -{ +//void ZigbeeNode::onIdentifyFinished() +//{ -} +//} QDebug operator<<(QDebug debug, ZigbeeNode *node) { - debug.nospace().noquote() << "Node(" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress()) << " | " << node->extendedAddress().toString() << ") "; - debug.nospace().noquote() << " " << ZigbeeUtils::convertUint16ToHexString(node->shortAddress()) << " | " << node->extendedAddress().toString() << ") "; + debug.nospace().noquote() << "ZigbeeNode(" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress()) << ", " << node->extendedAddress().toString() << ") "; return debug; } diff --git a/libnymea-zigbee/zigbeenode.h b/libnymea-zigbee/zigbeenode.h index 6f18668..d81f884 100644 --- a/libnymea-zigbee/zigbeenode.h +++ b/libnymea-zigbee/zigbeenode.h @@ -5,9 +5,6 @@ #include "zigbee.h" #include "zigbeeaddress.h" -#include "zigbeebridgecontroller.h" - -class ZigbeeNetworkManager; class ZigbeeNode : public QObject { @@ -30,6 +27,12 @@ public: }; Q_ENUM(FrequencyBand) + enum DeviceType { + DeviceTypeFullFunction, + DeviceTypeReducedFunction + }; + Q_ENUM(DeviceType) + enum Relationship { Parent, Child, @@ -59,44 +62,56 @@ public: }; Q_ENUM(PowerLevel) + ZigbeeNode(QObject *parent = nullptr); + quint16 shortAddress() const; ZigbeeAddress extendedAddress() const; - int endPoint() const; + quint8 endPoint() const; // Information from node descriptor NodeType nodeType() const; FrequencyBand frequencyBand() const; - Relationship relationShip() const; + Relationship relationship() const; Zigbee::ZigbeeProfile profile() const; quint16 manufacturerCode() const; + bool complexDescriptorAvailable() const; + bool userDescriptorAvailable() const; + + quint16 maximumRxSize() const; + quint16 maximumTxSize() const; + quint8 maximumBufferSize() const; + + // Information from node power descriptor PowerMode powerMode() const; PowerSource powerSource() const; QList availablePowerSources() const; PowerLevel powerLevel() const; // Node specific zigbee commands - void init(); - void identify(); - void toggle(int addressMode); +// void init(); +// void identify(); +// void toggle(int addressMode); private: - ZigbeeBridgeController *m_controller; - quint16 m_shortAddress = 0; ZigbeeAddress m_extendedAddress; - int m_endPoint = 0; + quint8 m_endPoint = 1; NodeType m_nodeType = NodeTypeRouter; FrequencyBand m_frequencyBand = FrequencyBand2400Mhz; - Relationship m_relationShip = Parent; - + Relationship m_relationship = Parent; Zigbee::ZigbeeProfile m_profile; quint16 m_manufacturerCode = 0; - quint16 m_maximalRxSize = 0; - quint16 m_maximalTxSize = 0; + bool m_complexDescriptorAvailable = false; + bool m_userDescriptorAvailable = false; + quint16 m_maximumRxSize = 0; + quint16 m_maximumTxSize = 0; + quint8 m_maximumBufferSize = 0; + + // Server Mask bool m_isPrimaryTrustCenter = false; bool m_isBackupTrustCenter = false; bool m_isPrimaryBindingCache = false; @@ -111,36 +126,38 @@ private: QList m_availablePowerSources; PowerLevel m_powerLevel; - // Mac capabilities + // Mac capabilities flag + bool m_alternatePanCoordinator = false; + DeviceType m_deviceType = DeviceTypeFullFunction; + bool m_powerSourceFlagMainPower = false; bool m_receiverOnWhenIdle = false; bool m_securityCapability = false; + bool m_allocateAddress = false; - void requestNodeDescription(); - void requestSimpleNodeDescription(); - void requestPowerDescriptor(); - void requestUserDescriptor(); - - void saveToSettings(); + // Descriptor capability + bool m_extendedActiveEndpointListAvailable = false; + bool m_extendedSimpleDescriptorListAvailable = false; protected: - ZigbeeNode(ZigbeeBridgeController *controller, QObject *parent = nullptr); - - ZigbeeBridgeController *controller(); - void setShortAddress(const quint16 &shortAddress); void setExtendedAddress(const ZigbeeAddress &extendedAddress); + void setEndPoint(quint8 endPoint); -signals: + void setNodeType(NodeType nodeType); + void setFrequencyBand(FrequencyBand frequencyBand); + void setRelationship(Relationship relationship); + void setZigbeeProfile(Zigbee::ZigbeeProfile profile); + void setManufacturerCode(quint16 manufacturerCode); -private slots: - void onRequestNodeDescriptionFinished(); - void onRequestSimpleNodeDescriptionFinished(); - void onRequestPowerDescriptorFinished(); - void onRequestUserDescriptorFinished(); - void onToggleFinished(); - void onIdentifyFinished(); + void setMaximumRxSize(quint16 size); + void setMaximumTxSize(quint16 size); + void setMaximumBufferSize(quint8 size); -public slots: + void setServerMask(quint16 serverMask); + void setComplexDescriptorAvailable(bool complexDescriptorAvailable); + void setUserDescriptorAvailable(bool userDescriptorAvailable); + void setMacCapabilitiesFlag(quint16 macFlag); + void setDescriptorFlag(quint8 descriptorFlag); }; diff --git a/libnymea-zigbee/zigbeesecurityconfiguration.cpp b/libnymea-zigbee/zigbeesecurityconfiguration.cpp new file mode 100644 index 0000000..2ce5787 --- /dev/null +++ b/libnymea-zigbee/zigbeesecurityconfiguration.cpp @@ -0,0 +1,26 @@ +#include "zigbeesecurityconfiguration.h" + +ZigbeeSecurityConfiguration::ZigbeeSecurityConfiguration() +{ + +} + +QString ZigbeeSecurityConfiguration::networkKey() const +{ + return m_networkKey; +} + +void ZigbeeSecurityConfiguration::setNetworkKey(const QString &networkKey) +{ + m_networkKey = networkKey; +} + +QString ZigbeeSecurityConfiguration::globalTrustCenterLinkKey() const +{ + return m_globalTrustCenterLinkKey; +} + +void ZigbeeSecurityConfiguration::setGlobalTrustCenterlinkKey(const QString &globalTrustCenterLinkKey) +{ + m_globalTrustCenterLinkKey = globalTrustCenterLinkKey; +} diff --git a/libnymea-zigbee/zigbeesecurityconfiguration.h b/libnymea-zigbee/zigbeesecurityconfiguration.h new file mode 100644 index 0000000..8f18c80 --- /dev/null +++ b/libnymea-zigbee/zigbeesecurityconfiguration.h @@ -0,0 +1,26 @@ +#ifndef ZIGBEESECURITYCONFIGURATION_H +#define ZIGBEESECURITYCONFIGURATION_H + +#include + +class ZigbeeSecurityConfiguration +{ +public: + ZigbeeSecurityConfiguration(); + + QString networkKey() const; + void setNetworkKey(const QString &networkKey); + + QString globalTrustCenterLinkKey() const; + void setGlobalTrustCenterlinkKey(const QString & globalTrustCenterLinkKey); + +private: + // This is the local network key + QString m_networkKey; + + // Note: this is the zigbee master key from (ZigBeeAlliance09) + QString m_globalTrustCenterLinkKey = "5A6967426565416C6C69616E63653039"; + +}; + +#endif // ZIGBEESECURITYCONFIGURATION_H diff --git a/libnymea-zigbee/zigbeeutils.cpp b/libnymea-zigbee/zigbeeutils.cpp index 3796011..3562d92 100644 --- a/libnymea-zigbee/zigbeeutils.cpp +++ b/libnymea-zigbee/zigbeeutils.cpp @@ -1,5 +1,6 @@ #include "zigbeeutils.h" +#include #include #include @@ -22,7 +23,7 @@ QByteArray ZigbeeUtils::convertBitArrayToByteArray(const QBitArray &bitArray) QByteArray byteArray; for(int b = 0; b < bitArray.count(); ++b) { - byteArray[b / 8] = (byteArray.at( b / 8) | ((bitArray[b] ? 1 : 0) << (7 - ( b % 8)))); + byteArray[b / 8] = static_cast((byteArray.at( b / 8) | ((bitArray[b] ? 1 : 0) << (7 - ( b % 8))))); } return byteArray; } @@ -75,7 +76,7 @@ QString ZigbeeUtils::convertByteArrayToHexString(const QByteArray &byteArray) { QString hexString; for (int i = 0; i < byteArray.count(); i++) { - hexString.append(convertByteToHexString((quint8)byteArray.at(i))); + hexString.append(convertByteToHexString(static_cast(byteArray.at(i)))); if (i != byteArray.count() - 1) { hexString.append(" "); } @@ -129,3 +130,10 @@ QString ZigbeeUtils::profileIdToString(const Zigbee::ZigbeeProfile &profileId) return enumString.remove("Zigbee::ZigbeeProfile(ZigbeeProfile").remove(")"); } + +quint64 ZigbeeUtils::generateRandomPanId() +{ + srand(static_cast(QDateTime::currentMSecsSinceEpoch() / 1000)); + srand(static_cast(qrand())); + return static_cast((ULLONG_MAX - 0) * (qrand()/static_cast(RAND_MAX))); +} diff --git a/libnymea-zigbee/zigbeeutils.h b/libnymea-zigbee/zigbeeutils.h index fdf30f9..08b8e92 100644 --- a/libnymea-zigbee/zigbeeutils.h +++ b/libnymea-zigbee/zigbeeutils.h @@ -32,6 +32,8 @@ public: static QString clusterIdToString(const Zigbee::ClusterId &clusterId); static QString profileIdToString(const Zigbee::ZigbeeProfile &profileId); + static quint64 generateRandomPanId(); + }; #endif // ZIGBEEUTILS_H diff --git a/nymea-zigbee.pro b/nymea-zigbee.pro index 18385e6..2fbd465 100644 --- a/nymea-zigbee.pro +++ b/nymea-zigbee.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS += libnymea-zigbee zigbee-cli +SUBDIRS += libnymea-zigbee #zigbee-cli diff --git a/zigbee-cli/core.cpp b/zigbee-cli/core.cpp index 59676be..387a5e3 100644 --- a/zigbee-cli/core.cpp +++ b/zigbee-cli/core.cpp @@ -12,7 +12,10 @@ Core::Core(const QString &serialPort, qint32 baudrate, const int &channel, QObje m_channelMask = 0; m_channelMask |= 1 << (channel); - m_manager = new ZigbeeNetworkManager(channel, m_serialPort, m_baudRate, this); + ZigbeeBridgeController *controller = new ZigbeeBridgeController(this); + controller->enable(serialPort, baudrate); + + //m_manager = new ZigbeeNetworkManager(channel, controller, this); // Set commands TerminalCommand runCommand("run", "Run the zigbee controller in a normal non interactive mode."); @@ -95,8 +98,8 @@ void Core::onCommandReceived(const QStringList &tokens) m_manager->setChannelMask(0x2108800); m_manager->setDeviceType(nodeType); // Note: this is the leaked philips ZLL master key - m_manager->setInitialSecurity(3, 0, 1, "9F5595F10257C8A469CBF42BC93FEE31"); - //m_manager->setInitialSecurity(4, 0, 1, "5A6967426565416C6C69616E63653039"); + //m_manager->setInitialSecurity(3, 0, 1, "9F5595F10257C8A469CBF42BC93FEE31"); + m_manager->setInitialSecurity(4, 0, 1, "5A6967426565416C6C69616E63653039"); } else if (command.command() == "start") { m_manager->startNetwork();