add descriptor parsing and device types
This commit is contained in:
parent
3d0385363f
commit
a3a9252092
2
core.cpp
2
core.cpp
@ -4,5 +4,5 @@
|
|||||||
Core::Core(QObject *parent) :
|
Core::Core(QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
m_manager = new ZigbeeManager("/dev/ttyS0", this);
|
m_manager = new ZigbeeNetworkManager("/dev/ttyS0", this);
|
||||||
}
|
}
|
||||||
|
|||||||
4
core.h
4
core.h
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "zigbeemanager.h"
|
#include "zigbeenetworkmanager.h"
|
||||||
|
|
||||||
class Core : public QObject
|
class Core : public QObject
|
||||||
{
|
{
|
||||||
@ -12,7 +12,7 @@ public:
|
|||||||
explicit Core(QObject *parent = nullptr);
|
explicit Core(QObject *parent = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ZigbeeManager *m_manager;
|
ZigbeeNetworkManager *m_manager;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "zigbeeinterface.h"
|
#include "zigbeeinterface.h"
|
||||||
#include "loggingcategory.h"
|
#include "loggingcategory.h"
|
||||||
|
#include "zigbeeutils.h"
|
||||||
|
|
||||||
ZigbeeInterface::ZigbeeInterface(QObject *parent) :
|
ZigbeeInterface::ZigbeeInterface(QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
@ -9,11 +10,21 @@ ZigbeeInterface::ZigbeeInterface(QObject *parent) :
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZigbeeInterface::~ZigbeeInterface()
|
||||||
|
{
|
||||||
|
disable();
|
||||||
|
}
|
||||||
|
|
||||||
bool ZigbeeInterface::available() const
|
bool ZigbeeInterface::available() const
|
||||||
{
|
{
|
||||||
return m_serialPort->isOpen();
|
return m_serialPort->isOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ZigbeeInterface::serialPort() const
|
||||||
|
{
|
||||||
|
return m_serialPort->portName();
|
||||||
|
}
|
||||||
|
|
||||||
quint8 ZigbeeInterface::calculateCrc(const quint16 &messageTypeValue, const quint16 &lenghtValue, const QByteArray &data)
|
quint8 ZigbeeInterface::calculateCrc(const quint16 &messageTypeValue, const quint16 &lenghtValue, const QByteArray &data)
|
||||||
{
|
{
|
||||||
quint8 crc = 0;
|
quint8 crc = 0;
|
||||||
@ -35,16 +46,16 @@ void ZigbeeInterface::streamByte(quint8 byte, bool specialCharacter)
|
|||||||
{
|
{
|
||||||
if (!specialCharacter && byte < 0x10) {
|
if (!specialCharacter && byte < 0x10) {
|
||||||
// Byte stuffing ESC char before stuffed data byte
|
// Byte stuffing ESC char before stuffed data byte
|
||||||
qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << Zigbee::convertByteToHexString(0x02);
|
qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << ZigbeeUtils::convertByteToHexString(0x02);
|
||||||
if (m_serialPort->write(QByteArray::fromRawData("\x02", 1)) < 0) {
|
if (m_serialPort->write(QByteArray::fromRawData("\x02", 1)) < 0) {
|
||||||
qCWarning(dcZigbeeInterface()) << "Could not stream ESC byte" << Zigbee::convertByteArrayToHexString(QByteArray::fromRawData("\x02", 1));
|
qCWarning(dcZigbeeInterface()) << "Could not stream ESC byte" << ZigbeeUtils::convertByteArrayToHexString(QByteArray::fromRawData("\x02", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
byte ^= 0x10;
|
byte ^= 0x10;
|
||||||
}
|
}
|
||||||
qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << Zigbee::convertByteToHexString(byte);
|
qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << ZigbeeUtils::convertByteToHexString(byte);
|
||||||
if (m_serialPort->write(QByteArray(1, (char)byte)) < 0) {
|
if (m_serialPort->write(QByteArray(1, (char)byte)) < 0) {
|
||||||
qCWarning(dcZigbeeInterface()) << "Could not stream byte" << Zigbee::convertByteToHexString(byte);
|
qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteToHexString(byte);
|
||||||
}
|
}
|
||||||
m_serialPort->flush();
|
m_serialPort->flush();
|
||||||
}
|
}
|
||||||
@ -66,7 +77,7 @@ void ZigbeeInterface::onReadyRead()
|
|||||||
for (int i = 0; i < data.length(); i++) {
|
for (int i = 0; i < data.length(); i++) {
|
||||||
quint8 byte = static_cast<quint8>(data.at(i));
|
quint8 byte = static_cast<quint8>(data.at(i));
|
||||||
|
|
||||||
qCDebug(dcZigbeeInterfaceTraffic()) << "[ in]" << Zigbee::convertByteToHexString(byte);
|
qCDebug(dcZigbeeInterfaceTraffic()) << "[ in]" << ZigbeeUtils::convertByteToHexString(byte);
|
||||||
|
|
||||||
switch (byte) {
|
switch (byte) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
@ -83,14 +94,17 @@ void ZigbeeInterface::onReadyRead()
|
|||||||
break;
|
break;
|
||||||
case 0x03: {
|
case 0x03: {
|
||||||
Zigbee::InterfaceMessageType messageType = static_cast<Zigbee::InterfaceMessageType>(m_messageTypeValue);
|
Zigbee::InterfaceMessageType messageType = static_cast<Zigbee::InterfaceMessageType>(m_messageTypeValue);
|
||||||
|
|
||||||
|
// Check message sanity
|
||||||
quint8 crc = calculateCrc(m_messageTypeValue, m_lengthValue, m_data);
|
quint8 crc = calculateCrc(m_messageTypeValue, m_lengthValue, m_data);
|
||||||
if (crc != m_crcValue) {
|
if (crc != m_crcValue) {
|
||||||
qCWarning(dcZigbeeInterface()) << "Invalid CRC value" << crc << "!=" << m_crcValue;
|
qCWarning(dcZigbeeInterface()) << "Invalid CRC value" << crc << "!=" << m_crcValue;
|
||||||
} else if (m_data.count() != m_lengthValue) {
|
} else if (m_data.count() != m_lengthValue) {
|
||||||
qCWarning(dcZigbeeInterface()) << "ERROR:s Invalid data length" << m_data.count() << "!=" << m_lengthValue;
|
qCWarning(dcZigbeeInterface()) << "ERROR:s Invalid data length" << m_data.count() << "!=" << m_lengthValue;
|
||||||
} else {
|
} else {
|
||||||
|
// We got a valid message
|
||||||
ZigbeeInterfaceMessage message(messageType, m_data);
|
ZigbeeInterfaceMessage message(messageType, m_data);
|
||||||
qCDebug(dcZigbeeInterface()) << "<--" << message;
|
qCDebug(dcZigbeeInterface()) << "<--" << message << "|" << "crc:" << ZigbeeUtils::convertByteToHexString(m_crcValue) << ", length:" << ZigbeeUtils::convertUint16ToHexString(m_lengthValue);
|
||||||
emit messageReceived(message);
|
emit messageReceived(message);
|
||||||
}
|
}
|
||||||
setReadingState(WaitForStart);
|
setReadingState(WaitForStart);
|
||||||
@ -144,7 +158,9 @@ void ZigbeeInterface::onReadyRead()
|
|||||||
|
|
||||||
void ZigbeeInterface::onError(const QSerialPort::SerialPortError &error)
|
void ZigbeeInterface::onError(const QSerialPort::SerialPortError &error)
|
||||||
{
|
{
|
||||||
qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString();
|
if (error != QSerialPort::NoError) {
|
||||||
|
qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZigbeeInterface::enable(const QString &serialPort)
|
bool ZigbeeInterface::enable(const QString &serialPort)
|
||||||
@ -194,7 +210,7 @@ void ZigbeeInterface::sendMessage(const ZigbeeInterfaceMessage &message)
|
|||||||
|
|
||||||
quint8 crcValue = calculateCrc(messageTypeValue, lengthValue, message.data());
|
quint8 crcValue = calculateCrc(messageTypeValue, lengthValue, message.data());
|
||||||
|
|
||||||
qCDebug(dcZigbeeInterface()) << "-->" << message << "crc:" << Zigbee::convertByteToHexString(crcValue) << ", length:" << Zigbee::convertByte16ToHexString(lengthValue);
|
qCDebug(dcZigbeeInterface()) << "-->" << message << "|" << "crc:" << ZigbeeUtils::convertByteToHexString(crcValue) << ", length:" << ZigbeeUtils::convertUint16ToHexString(lengthValue);
|
||||||
|
|
||||||
streamByte(0x01, true);
|
streamByte(0x01, true);
|
||||||
streamByte((messageTypeValue >> 8) & 0xff);
|
streamByte((messageTypeValue >> 8) & 0xff);
|
||||||
@ -23,8 +23,10 @@ public:
|
|||||||
Q_ENUM(ReadingState)
|
Q_ENUM(ReadingState)
|
||||||
|
|
||||||
explicit ZigbeeInterface(QObject *parent = nullptr);
|
explicit ZigbeeInterface(QObject *parent = nullptr);
|
||||||
|
~ZigbeeInterface();
|
||||||
|
|
||||||
bool available() const;
|
bool available() const;
|
||||||
|
QString serialPort() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSerialPort *m_serialPort;
|
QSerialPort *m_serialPort;
|
||||||
@ -1,4 +1,5 @@
|
|||||||
#include "zigbeeinterfacemessage.h"
|
#include "zigbeeinterfacemessage.h"
|
||||||
|
#include "zigbeeutils.h"
|
||||||
|
|
||||||
ZigbeeInterfaceMessage::ZigbeeInterfaceMessage()
|
ZigbeeInterfaceMessage::ZigbeeInterfaceMessage()
|
||||||
{
|
{
|
||||||
@ -32,8 +33,13 @@ void ZigbeeInterfaceMessage::setData(const QByteArray &data)
|
|||||||
m_data = data;
|
m_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ZigbeeInterfaceMessage::isValid() const
|
||||||
|
{
|
||||||
|
return m_messageType != Zigbee::MessageTypeNone;
|
||||||
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug dbg, const ZigbeeInterfaceMessage &message)
|
QDebug operator<<(QDebug dbg, const ZigbeeInterfaceMessage &message)
|
||||||
{
|
{
|
||||||
dbg.nospace().noquote() << "InterfaceMessage(" << message.messageType() << Zigbee::convertByteArrayToHexString(message.data()) << ")";
|
dbg.nospace().noquote() << ZigbeeUtils::messageTypeToString(message.messageType()) << "(" << ZigbeeUtils::convertUint16ToHexString(static_cast<quint16>(message.messageType())) << ")" << " | " << ZigbeeUtils::convertByteArrayToHexString(message.data());
|
||||||
return dbg.space();
|
return dbg.space();
|
||||||
}
|
}
|
||||||
@ -18,8 +18,10 @@ public:
|
|||||||
QByteArray data() const;
|
QByteArray data() const;
|
||||||
void setData(const QByteArray &data);
|
void setData(const QByteArray &data);
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Zigbee::InterfaceMessageType m_messageType;
|
Zigbee::InterfaceMessageType m_messageType = Zigbee::MessageTypeNone;
|
||||||
QByteArray m_data;
|
QByteArray m_data;
|
||||||
|
|
||||||
};
|
};
|
||||||
111
interface/zigbeeinterfacereply.cpp
Normal file
111
interface/zigbeeinterfacereply.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#include "zigbeeinterfacereply.h"
|
||||||
|
#include "loggingcategory.h"
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply::ZigbeeInterfaceReply(const ZigbeeInterfaceRequest &request, QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_request(request)
|
||||||
|
{
|
||||||
|
m_timer = new QTimer(this);
|
||||||
|
m_timer->setSingleShot(true);
|
||||||
|
|
||||||
|
connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceReply::onTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest ZigbeeInterfaceReply::request() const
|
||||||
|
{
|
||||||
|
return m_request;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeInterfaceMessage ZigbeeInterfaceReply::statusMessage() const
|
||||||
|
{
|
||||||
|
return m_statusMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeInterfaceMessage ZigbeeInterfaceReply::additionalMessage() const
|
||||||
|
{
|
||||||
|
return m_additionalMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply::Status ZigbeeInterfaceReply::status() const
|
||||||
|
{
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint8 ZigbeeInterfaceReply::statusCode() const
|
||||||
|
{
|
||||||
|
return m_statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint8 ZigbeeInterfaceReply::sequenceNumber() const
|
||||||
|
{
|
||||||
|
return m_sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeInterfaceReply::statusErrorMessage() const
|
||||||
|
{
|
||||||
|
return m_statusErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceReply::setStatusMessage(const ZigbeeInterfaceMessage &statusMessage)
|
||||||
|
{
|
||||||
|
m_statusMessage = statusMessage;
|
||||||
|
|
||||||
|
// Parse status message
|
||||||
|
m_statusCode = static_cast<quint8>(statusMessage.data().at(0));
|
||||||
|
|
||||||
|
// Well known error
|
||||||
|
if (m_statusCode < 6) {
|
||||||
|
m_status = static_cast<Status>(m_statusCode);
|
||||||
|
} else if (m_statusCode >= 128 && m_statusCode <= 244) {
|
||||||
|
qCWarning(dcZigbeeInterface()) << "Got zigbee status code" << m_statusCode;
|
||||||
|
m_status = ZigbeeErrorEvent;
|
||||||
|
} else {
|
||||||
|
qCWarning(dcZigbeeInterface()) << "Got unknown status code";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sequence number
|
||||||
|
m_sequenceNumber = static_cast<quint8>(statusMessage.data().at(0));
|
||||||
|
|
||||||
|
// TODO: compare with the request messageType: 2 bytes of request messageType
|
||||||
|
|
||||||
|
// Got error message
|
||||||
|
if (statusMessage.data().count() > 4) {
|
||||||
|
m_statusErrorMessage = QString::fromUtf8(statusMessage.data().right(statusMessage.data().count() -4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceReply::setAdditionalMessage(const ZigbeeInterfaceMessage &additionalMessage)
|
||||||
|
{
|
||||||
|
m_additionalMessage = additionalMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZigbeeInterfaceReply::isComplete() const
|
||||||
|
{
|
||||||
|
// No status received
|
||||||
|
if (!m_statusMessage.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Status received, check if additional message is expected
|
||||||
|
if (!request().expectsAdditionalMessage())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return m_additionalMessage.isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceReply::startTimer(const int &timeout)
|
||||||
|
{
|
||||||
|
m_timer->start(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceReply::setFinished()
|
||||||
|
{
|
||||||
|
m_timer->stop();
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceReply::onTimeout()
|
||||||
|
{
|
||||||
|
m_timeouted = true;
|
||||||
|
m_status = Timeouted;
|
||||||
|
emit timeout();
|
||||||
|
}
|
||||||
73
interface/zigbeeinterfacereply.h
Normal file
73
interface/zigbeeinterfacereply.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#ifndef ZIGBEEINTERFACEREPLY_H
|
||||||
|
#define ZIGBEEINTERFACEREPLY_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "zigbeeinterfacerequest.h"
|
||||||
|
|
||||||
|
class ZigbeeBridgeController;
|
||||||
|
|
||||||
|
class ZigbeeInterfaceReply : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class ZigbeeBridgeController;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Status {
|
||||||
|
Success = 0,
|
||||||
|
InvalidParameter = 1,
|
||||||
|
UnhandledCommand = 2,
|
||||||
|
CommandFailed = 3,
|
||||||
|
Busy = 4,
|
||||||
|
StackAlreadyStarted = 5,
|
||||||
|
ZigbeeErrorEvent = 6,
|
||||||
|
Timeouted = 7
|
||||||
|
};
|
||||||
|
Q_ENUM(Status)
|
||||||
|
|
||||||
|
explicit ZigbeeInterfaceReply(const ZigbeeInterfaceRequest &request, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest request() const;
|
||||||
|
ZigbeeInterfaceMessage statusMessage() const;
|
||||||
|
ZigbeeInterfaceMessage additionalMessage() const;
|
||||||
|
|
||||||
|
bool timeouted() const;
|
||||||
|
|
||||||
|
Status status() const;
|
||||||
|
quint8 statusCode() const;
|
||||||
|
quint8 sequenceNumber() const;
|
||||||
|
QString statusErrorMessage() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTimer *m_timer = nullptr;
|
||||||
|
bool m_timeouted = false;
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest m_request;
|
||||||
|
ZigbeeInterfaceMessage m_statusMessage;
|
||||||
|
ZigbeeInterfaceMessage m_additionalMessage;
|
||||||
|
|
||||||
|
// Status content
|
||||||
|
Status m_status;
|
||||||
|
quint8 m_statusCode;
|
||||||
|
quint8 m_sequenceNumber;
|
||||||
|
QString m_statusErrorMessage;
|
||||||
|
|
||||||
|
// Called by ZigbeeBridgeController
|
||||||
|
void setStatusMessage(const ZigbeeInterfaceMessage &statusMessage);
|
||||||
|
void setAdditionalMessage(const ZigbeeInterfaceMessage &additionalMessage);
|
||||||
|
|
||||||
|
bool isComplete() const;
|
||||||
|
void startTimer(const int &timeout = 500);
|
||||||
|
void setFinished();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished();
|
||||||
|
void timeout();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onTimeout();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ZIGBEEINTERFACEREPLY_H
|
||||||
58
interface/zigbeeinterfacerequest.cpp
Normal file
58
interface/zigbeeinterfacerequest.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "zigbeeinterfacerequest.h"
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest::ZigbeeInterfaceRequest()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest::ZigbeeInterfaceRequest(const ZigbeeInterfaceMessage &message):
|
||||||
|
m_message(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceRequest::setDescription(const QString &description)
|
||||||
|
{
|
||||||
|
m_description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeInterfaceRequest::description() const
|
||||||
|
{
|
||||||
|
return m_description;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceRequest::setMessage(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
m_message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeInterfaceMessage ZigbeeInterfaceRequest::message() const
|
||||||
|
{
|
||||||
|
return m_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZigbeeInterfaceRequest::expectsAdditionalMessage() const
|
||||||
|
{
|
||||||
|
return m_expectsAdditionalMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceRequest::setExpectedAdditionalMessageType(const Zigbee::InterfaceMessageType &messageType)
|
||||||
|
{
|
||||||
|
m_expectedAdditionalMessageType = messageType;
|
||||||
|
m_expectsAdditionalMessage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Zigbee::InterfaceMessageType ZigbeeInterfaceRequest::expectedAdditionalMessageType() const
|
||||||
|
{
|
||||||
|
return m_expectedAdditionalMessageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeInterfaceRequest::setTimoutIntervall(const int &timeoutIntervall)
|
||||||
|
{
|
||||||
|
m_timeoutIntervall = timeoutIntervall;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ZigbeeInterfaceRequest::timeoutIntervall() const
|
||||||
|
{
|
||||||
|
return m_timeoutIntervall;
|
||||||
|
}
|
||||||
35
interface/zigbeeinterfacerequest.h
Normal file
35
interface/zigbeeinterfacerequest.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef ZIGBEEINTERFACEREQUEST_H
|
||||||
|
#define ZIGBEEINTERFACEREQUEST_H
|
||||||
|
|
||||||
|
#include "zigbeeinterfacemessage.h"
|
||||||
|
|
||||||
|
class ZigbeeInterfaceRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ZigbeeInterfaceRequest();
|
||||||
|
ZigbeeInterfaceRequest(const ZigbeeInterfaceMessage &message);
|
||||||
|
|
||||||
|
void setDescription(const QString &description);
|
||||||
|
QString description() const;
|
||||||
|
|
||||||
|
void setMessage(const ZigbeeInterfaceMessage &message);
|
||||||
|
ZigbeeInterfaceMessage message() const;
|
||||||
|
|
||||||
|
bool expectsAdditionalMessage() const;
|
||||||
|
|
||||||
|
void setExpectedAdditionalMessageType(const Zigbee::InterfaceMessageType &messageType);
|
||||||
|
Zigbee::InterfaceMessageType expectedAdditionalMessageType() const;
|
||||||
|
|
||||||
|
void setTimoutIntervall(const int &timeoutIntervall);
|
||||||
|
int timeoutIntervall() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_description;
|
||||||
|
ZigbeeInterfaceMessage m_message;
|
||||||
|
Zigbee::InterfaceMessageType m_expectedAdditionalMessageType = Zigbee::MessageTypeNone;
|
||||||
|
bool m_expectsAdditionalMessage = false;
|
||||||
|
int m_timeoutIntervall = 500;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ZIGBEEINTERFACEREQUEST_H
|
||||||
@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
Q_LOGGING_CATEGORY(dcZigbee, "Zigbee")
|
Q_LOGGING_CATEGORY(dcZigbee, "Zigbee")
|
||||||
Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface")
|
Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface")
|
||||||
|
Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController")
|
||||||
Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic")
|
Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic")
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcZigbee)
|
Q_DECLARE_LOGGING_CATEGORY(dcZigbee)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface)
|
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface)
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic)
|
Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic)
|
||||||
|
|
||||||
#endif // LOGGINGCATEGORY_H
|
#endif // LOGGINGCATEGORY_H
|
||||||
|
|||||||
26
main.cpp
26
main.cpp
@ -58,9 +58,31 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
QCoreApplication application(argc, argv);
|
QCoreApplication application(argc, argv);
|
||||||
|
|
||||||
|
// Command line parser
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.addHelpOption();
|
||||||
|
parser.addVersionOption();
|
||||||
|
parser.setApplicationDescription(QString("\nDaemon for the zigbee NXP uart bridge.\n\nCopyright %1 2016 Simon Stürz <simon.stuerz@guh.io>\nAll rights reserved.").arg(QChar(0xA9)));
|
||||||
|
|
||||||
|
QCommandLineOption debugLevelOption(QStringList() << "d" << "debug-level", "Set debug level [1-4].");
|
||||||
|
debugLevelOption.setDefaultValue("1");
|
||||||
|
debugLevelOption.setValueName("level");
|
||||||
|
parser.addOption(debugLevelOption);
|
||||||
|
|
||||||
|
parser.process(application);
|
||||||
|
|
||||||
|
bool debugLevelValueOk = false;
|
||||||
|
int debugLevel = parser.value(debugLevelOption).toInt(&debugLevelValueOk);
|
||||||
|
|
||||||
|
if (debugLevel < 1 || debugLevel > 4 || !debugLevelValueOk) {
|
||||||
|
qWarning() << "Invalid debug level passed:" << parser.value(debugLevelOption);
|
||||||
|
debugLevel = 1;
|
||||||
|
}
|
||||||
|
|
||||||
s_loggingFilters.insert("Zigbee", true);
|
s_loggingFilters.insert("Zigbee", true);
|
||||||
s_loggingFilters.insert("ZigbeeInterface", true);
|
s_loggingFilters.insert("ZigbeeController", (debugLevel > 1));
|
||||||
s_loggingFilters.insert("ZigbeeInterfaceTraffic", false);
|
s_loggingFilters.insert("ZigbeeInterface", (debugLevel > 2));
|
||||||
|
s_loggingFilters.insert("ZigbeeInterfaceTraffic", (debugLevel > 3));
|
||||||
|
|
||||||
QLoggingCategory::installFilter(loggingCategoryFilter);
|
QLoggingCategory::installFilter(loggingCategoryFilter);
|
||||||
|
|
||||||
|
|||||||
@ -11,16 +11,28 @@ INSTALLS += target
|
|||||||
|
|
||||||
SOURCES += main.cpp \
|
SOURCES += main.cpp \
|
||||||
core.cpp \
|
core.cpp \
|
||||||
zigbeeinterface.cpp \
|
interface/zigbeeinterface.cpp \
|
||||||
zigbeemanager.cpp \
|
interface/zigbeeinterfacemessage.cpp \
|
||||||
|
interface/zigbeeinterfacerequest.cpp \
|
||||||
|
interface/zigbeeinterfacereply.cpp \
|
||||||
|
zigbeenetworkmanager.cpp \
|
||||||
zigbee.cpp \
|
zigbee.cpp \
|
||||||
zigbeeinterfacemessage.cpp \
|
loggingcategory.cpp \
|
||||||
loggingcategory.cpp
|
zigbeebridgecontroller.cpp \
|
||||||
|
zigbeeutils.cpp \
|
||||||
|
zigbeenode.cpp \
|
||||||
|
zigbeeaddress.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
core.h \
|
core.h \
|
||||||
zigbeeinterface.h \
|
interface/zigbeeinterface.h \
|
||||||
zigbeemanager.h \
|
interface/zigbeeinterfacemessage.h \
|
||||||
|
interface/zigbeeinterfacerequest.h \
|
||||||
|
interface/zigbeeinterfacereply.h \
|
||||||
|
zigbeenetworkmanager.h \
|
||||||
zigbee.h \
|
zigbee.h \
|
||||||
zigbeeinterfacemessage.h \
|
loggingcategory.h \
|
||||||
loggingcategory.h
|
zigbeebridgecontroller.h \
|
||||||
|
zigbeeutils.h \
|
||||||
|
zigbeenode.h \
|
||||||
|
zigbeeaddress.h
|
||||||
|
|||||||
31
zigbee.cpp
31
zigbee.cpp
@ -1,33 +1,2 @@
|
|||||||
#include "zigbee.h"
|
#include "zigbee.h"
|
||||||
|
|
||||||
QString Zigbee::convertByteToHexString(const quint8 &byte)
|
|
||||||
{
|
|
||||||
QString hexString;
|
|
||||||
QString byteString = QString::number(byte, 16);
|
|
||||||
if (byteString.count() == 1) {
|
|
||||||
hexString = QString("0x0%1").arg(byteString);
|
|
||||||
} else {
|
|
||||||
hexString = QString("0x%1").arg(byteString);
|
|
||||||
}
|
|
||||||
return hexString.toStdString().data();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Zigbee::convertByteArrayToHexString(const QByteArray &byteArray)
|
|
||||||
{
|
|
||||||
QString hexString;
|
|
||||||
for (int i = 0; i < byteArray.count(); i++) {
|
|
||||||
hexString.append(convertByteToHexString((quint8)byteArray.at(i)));
|
|
||||||
if (i != byteArray.count() -1) {
|
|
||||||
hexString.append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hexString.toStdString().data();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Zigbee::convertByte16ToHexString(const quint16 &byte)
|
|
||||||
{
|
|
||||||
quint8 msbByte = (byte >> 8) & 0xff;
|
|
||||||
quint8 lsbByte = (byte >> 0) & 0xff;
|
|
||||||
|
|
||||||
return convertByteToHexString(msbByte) + convertByteToHexString(lsbByte).remove("0x");
|
|
||||||
}
|
|
||||||
|
|||||||
474
zigbee.h
474
zigbee.h
@ -10,194 +10,352 @@ class Zigbee
|
|||||||
Q_GADGET
|
Q_GADGET
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum ZigbeeProfile {
|
||||||
|
ZigbeeProfileHomeAutomation = 0x0104,
|
||||||
|
ZigbeeProfileLightLink = 0xC05E
|
||||||
|
};
|
||||||
|
Q_ENUM(ZigbeeProfile)
|
||||||
|
|
||||||
enum InterfaceMessageType {
|
enum InterfaceMessageType {
|
||||||
/* Common Commands */
|
// Common Commands
|
||||||
Status = 0x8000,
|
MessageTypeNone = 0x0000,
|
||||||
Logging = 0x8001,
|
MessageTypeStatus = 0x8000,
|
||||||
|
MessageTypeLogging = 0x8001,
|
||||||
|
|
||||||
DataIndication = 0x8002,
|
MessageTypeDataIndication = 0x8002,
|
||||||
|
|
||||||
NodeClusterList = 0x8003,
|
MessageTypeNodeClusterList = 0x8003,
|
||||||
NodeAttributeList = 0x8004,
|
MessageTypeNodeAttributeList = 0x8004,
|
||||||
NodeCommandIdList = 0x8005,
|
MessageTypeNodeCommandIdList = 0x8005,
|
||||||
RestartProvisioned = 0x8006,
|
MessageTypeRestartProvisioned = 0x8006,
|
||||||
RestartFactoryNew = 0x8007,
|
MessageTypeFactoryNewRestart = 0x8007,
|
||||||
GetVersion = 0x0010,
|
MessageTypeGetVersion = 0x0010,
|
||||||
VersionList = 0x8010,
|
MessageTypeVersionList = 0x8010,
|
||||||
|
|
||||||
SetExtendetPanId = 0x0020,
|
MessageTypeSetExtendetPanId = 0x0020,
|
||||||
SetChannelMask = 0x0021,
|
MessageTypeSetChannelMask = 0x0021,
|
||||||
SetSecurity = 0x0022,
|
MessageTypeSetSecurity = 0x0022,
|
||||||
SetDeviceType = 0x0023,
|
MessageTypeSetDeviceType = 0x0023,
|
||||||
StartNetwork = 0x0024,
|
MessageTypeStartNetwork = 0x0024,
|
||||||
StartScan = 0x0025,
|
MessageTypeStartScan = 0x0025,
|
||||||
NetworkJoinedFormed = 0x8024,
|
MessageTypeNetworkJoinedFormed = 0x8024,
|
||||||
NetworkRemoveDevice = 0x0026,
|
MessageTypeNetworkRemoveDevice = 0x0026,
|
||||||
NetworkWhitelistEnable = 0x0027,
|
MessageTypeNetworkWhitelistEnable = 0x0027,
|
||||||
AuthenticateDeviceRequest = 0x0028,
|
MessageTypeAuthenticateDeviceRequest = 0x0028,
|
||||||
AuthenticateDeviceResponse = 0x8028,
|
MessageTypeAuthenticateDeviceResponse = 0x8028,
|
||||||
OutOfBandCommisioningDataRequest = 0x0029,
|
MessageTypeOutOfBandCommisioningDataRequest = 0x0029,
|
||||||
OutOfBandCommisioningDataResponse = 0x8029,
|
MessageTypeOutOfBandCommisioningDataResponse = 0x8029,
|
||||||
|
|
||||||
Reset = 0x0011,
|
MessageTypeReset = 0x0011,
|
||||||
ErasePersistentData = 0x0012,
|
MessageTypeErasePersistentData = 0x0012,
|
||||||
ZllFactoryNew = 0x0013,
|
MessageTypeZllFactoryNew = 0x0013,
|
||||||
GetPermitJoin = 0x0014,
|
MessageTypeGetPermitJoining = 0x0014,
|
||||||
GetPermitJoinResponse = 0x8014,
|
MessageTypeGetPermitJoiningResponse = 0x8014,
|
||||||
Bind = 0x0030,
|
MessageTypeBind = 0x0030,
|
||||||
BindResponse = 0x8030,
|
MessageTypeBindResponse = 0x8030,
|
||||||
Unbind = 0x0031,
|
MessageTypeUnbind = 0x0031,
|
||||||
UnbindResponse = 0x8031,
|
MessageTypeUnbindResponse = 0x8031,
|
||||||
|
|
||||||
NetworkAdressRequest = 0x0040,
|
MessageTypeNetworkAdressRequest = 0x0040,
|
||||||
NetworkAdressResponse = 0x8040,
|
MessageTypeNetworkAdressResponse = 0x8040,
|
||||||
IeeeAddressResponse = 0x0041,
|
MessageTypeIeeeAddressResponse = 0x0041,
|
||||||
IeeeAddressRequest = 0x8041,
|
MessageTypeIeeeAddressRequest = 0x8041,
|
||||||
NodeDescriptorRequest = 0x0042,
|
MessageTypeNodeDescriptorRequest = 0x0042,
|
||||||
NodeDescriptorRsponse = 0x8042,
|
MessageTypeNodeDescriptorRsponse = 0x8042,
|
||||||
SimpleDescriptorRequest = 0x0043,
|
MessageTypeSimpleDescriptorRequest = 0x0043,
|
||||||
SimpleDescriptorResponse = 0x8043,
|
MessageTypeSimpleDescriptorResponse = 0x8043,
|
||||||
PowerDescriptorRequest = 0x0044,
|
MessageTypePowerDescriptorRequest = 0x0044,
|
||||||
PowerDescriptorResponse = 0x8044,
|
MessageTypePowerDescriptorResponse = 0x8044,
|
||||||
ActiveEndpointRequest = 0x0045,
|
MessageTypeActiveEndpointRequest = 0x0045,
|
||||||
ActiveEndpointResponse = 0x8045,
|
MessageTypeActiveEndpointResponse = 0x8045,
|
||||||
MatchDescriptorRequest = 0x0046,
|
MessageTypeMatchDescriptorRequest = 0x0046,
|
||||||
MatchDescriptorResponse = 0x8046,
|
MessageTypeMatchDescriptorResponse = 0x8046,
|
||||||
ManagementLeaveRequest = 0x0047,
|
MessageTypeManagementLeaveRequest = 0x0047,
|
||||||
ManagementLeaveResponse = 0x8047,
|
MessageTypeManagementLeaveResponse = 0x8047,
|
||||||
LeaveIndication = 0x8048,
|
MessageTypeLeaveIndication = 0x8048,
|
||||||
PermitJoiningRequest = 0x0049,
|
MessageTypePermitJoiningRequest = 0x0049,
|
||||||
ManagementNetworkUpdateRequest = 0x004A,
|
MessageTypeManagementNetworkUpdateRequest = 0x004A,
|
||||||
ManagementNetworkUpdateResponse = 0x804A,
|
MessageTypeManagementNetworkUpdateResponse = 0x804A,
|
||||||
SystemServerDiscoveryRequest = 0x004B,
|
MessageTypeSystemServerDiscoveryRequest = 0x004B,
|
||||||
SystemServerDiscoveryResponse = 0x804B,
|
MessageTypeSystemServerDiscoveryResponse = 0x804B,
|
||||||
DeviceAnnounce = 0x004D,
|
MessageTypeDeviceAnnounce = 0x004D,
|
||||||
ManagementLqiRequest = 0x004E,
|
MessageTypeManagementLqiRequest = 0x004E,
|
||||||
ManagementLqiResponse = 0x804E,
|
MessageTypeManagementLqiResponse = 0x804E,
|
||||||
|
|
||||||
/* Group Cluster */
|
// Group Cluster
|
||||||
AddGroupRequest = 0x0060,
|
MessageTypeAddGroupRequest = 0x0060,
|
||||||
AddGroupResponse = 0x8060,
|
MessageTypeAddGroupResponse = 0x8060,
|
||||||
ViewGroupRequest = 0x0061,
|
MessageTypeViewGroupRequest = 0x0061,
|
||||||
ViewGroupResponse = 0x8061,
|
MessageTypeViewGroupResponse = 0x8061,
|
||||||
GetGroupMembershipRequest = 0x0062,
|
MessageTypeGetGroupMembershipRequest = 0x0062,
|
||||||
GetGroupMembershipResponse = 0x8062,
|
MessageTypeGetGroupMembershipResponse = 0x8062,
|
||||||
RemoveGroupRequest = 0x0063,
|
MessageTypeRemoveGroupRequest = 0x0063,
|
||||||
RemoveGroupResponse = 0x8063,
|
MessageTypeRemoveGroupResponse = 0x8063,
|
||||||
RemoveAllGroups = 0x0064,
|
MessageTypeRemoveAllGroups = 0x0064,
|
||||||
GroupIfIdentify = 0x0065,
|
MessageTypeGroupIfIdentify = 0x0065,
|
||||||
|
|
||||||
/* Identify Cluster */
|
// Identify Cluster
|
||||||
IdentifySend = 0x0070,
|
MessageTypeIdentifySend = 0x0070,
|
||||||
IdentifyQuery = 0x0071,
|
MessageTypeIdentifyQuery = 0x0071,
|
||||||
|
|
||||||
/* Level Cluster */
|
// Level Cluster
|
||||||
MoveToLevel = 0x0080,
|
MessageTypeMoveToLevel = 0x0080,
|
||||||
MoveToLevelOnOff = 0x0081,
|
MessageTypeMoveToLevelOnOff = 0x0081,
|
||||||
MoveStep = 0x0082,
|
MessageTypeMoveStep = 0x0082,
|
||||||
MoveStopMove = 0x0083,
|
MessageTypeMoveStopMove = 0x0083,
|
||||||
MoveStopMoveOnOff = 0x0084,
|
MessageTypeMoveStopMoveOnOff = 0x0084,
|
||||||
|
|
||||||
/* Scenes Cluster */
|
// Scenes Cluster
|
||||||
ViewScene = 0x00A0,
|
MessageTypeViewScene = 0x00A0,
|
||||||
ViewSceneResponse = 0x80A0,
|
MessageTypeViewSceneResponse = 0x80A0,
|
||||||
AddScene = 0x00A1,
|
MessageTypeAddScene = 0x00A1,
|
||||||
AddSceneResponse = 0x80A1,
|
MessageTypeAddSceneResponse = 0x80A1,
|
||||||
RemoveScene = 0x00A2,
|
MessageTypeRemoveScene = 0x00A2,
|
||||||
RemoveSceneResponse = 0x80A2,
|
MessageTypeRemoveSceneResponse = 0x80A2,
|
||||||
RemoveAllScenes = 0x00A3,
|
MessageTypeRemoveAllScenes = 0x00A3,
|
||||||
RemoveAllScenesResponse = 0x80A3,
|
MessageTypeRemoveAllScenesResponse = 0x80A3,
|
||||||
StoreScene = 0x00A4,
|
MessageTypeStoreScene = 0x00A4,
|
||||||
StoreSceneResponse = 0x80A4,
|
MessageTypeStoreSceneResponse = 0x80A4,
|
||||||
RecallScene = 0x00A5,
|
MessageTypeRecallScene = 0x00A5,
|
||||||
SceneMembershipRequest = 0x00A6,
|
MessageTypeSceneMembershipRequest = 0x00A6,
|
||||||
SceneMembershipResponse = 0x80A6,
|
MessageTypeSceneMembershipResponse = 0x80A6,
|
||||||
|
|
||||||
/* Colour Cluster */
|
//Colour Cluster
|
||||||
MoveToHue = 0x00B0,
|
MessageTypeMoveToHue = 0x00B0,
|
||||||
MoveHue = 0x00B1,
|
MessageTypeMoveHue = 0x00B1,
|
||||||
StepHue = 0x00B2,
|
MessageTypeStepHue = 0x00B2,
|
||||||
MoveToSaturation = 0x00B3,
|
MessageTypeMoveToSaturation = 0x00B3,
|
||||||
MoveSaturation = 0x00B4,
|
MessageTypeMoveSaturation = 0x00B4,
|
||||||
StepStaturation = 0x00B5,
|
MessageTypeStepStaturation = 0x00B5,
|
||||||
MoveToHueSaturation = 0x00B6,
|
MessageTypeMoveToHueSaturation = 0x00B6,
|
||||||
MoveToColor = 0x00B7,
|
MessageTypeMoveToColor = 0x00B7,
|
||||||
MoveColor = 0x00B8,
|
MessageTypeMoveColor = 0x00B8,
|
||||||
StepColor = 0x00B9,
|
MessageTypeStepColor = 0x00B9,
|
||||||
|
|
||||||
/* ZLL Commands */
|
// ZLL Commands
|
||||||
/* Touchlink */
|
/* Touchlink */
|
||||||
InitiateTouchlink = 0x00D0,
|
MessageTypeInitiateTouchlink = 0x00D0,
|
||||||
TouchlinkStatus = 0x00D1,
|
MessageTypeTouchlinkStatus = 0x00D1,
|
||||||
TouchlinkFactoryReset = 0x00D2,
|
MessageTypeTouchlinkFactoryReset = 0x00D2,
|
||||||
|
|
||||||
/* Identify Cluster */
|
// Identify Cluster
|
||||||
IdentifyTriggerEffect = 0x00E0,
|
MessageTypeIdentifyTriggerEffect = 0x00E0,
|
||||||
|
|
||||||
/* On/Off Cluster */
|
// On/Off Cluster
|
||||||
CluserOnOff = 0x0092,
|
MessageTypeCluserOnOff = 0x0092,
|
||||||
CluserOnOffTimed = 0x0093,
|
MessageTypeCluserOnOffTimed = 0x0093,
|
||||||
CluserOnOffEffects = 0x0094,
|
MessageTypeCluserOnOffEffects = 0x0094,
|
||||||
CluserOnOffUpdate = 0x8095,
|
MessageTypeCluserOnOffUpdate = 0x8095,
|
||||||
|
|
||||||
/* Scenes Cluster */
|
// Scenes Cluster
|
||||||
AddEnhancedScene = 0x00A7,
|
MessageTypeAddEnhancedScene = 0x00A7,
|
||||||
ViewEnhancedScene = 0x00A8,
|
MessageTypeViewEnhancedScene = 0x00A8,
|
||||||
CopyScene = 0x00A9,
|
MessageTypeCopyScene = 0x00A9,
|
||||||
|
|
||||||
/* Colour Cluster */
|
// Colour Cluster
|
||||||
EnhancedMoveToHue = 0x00BA,
|
MessageTypeEnhancedMoveToHue = 0x00BA,
|
||||||
EnhancedMoveHue = 0x00BB,
|
MessageTypeEnhancedMoveHue = 0x00BB,
|
||||||
EnhancedStepHue = 0x00BC,
|
MessageTypeEnhancedStepHue = 0x00BC,
|
||||||
EnhancedMoveToHueSaturation = 0x00BD,
|
MessageTypeEnhancedMoveToHueSaturation = 0x00BD,
|
||||||
ColourLoopSet = 0x00BE,
|
MessageTypeColourLoopSet = 0x00BE,
|
||||||
StopMoveStep = 0x00BF,
|
MessageTypeStopMoveStep = 0x00BF,
|
||||||
MoveToColorTemperature = 0x00C0,
|
MessageTypeMoveToColorTemperature = 0x00C0,
|
||||||
MoveColorTemperature = 0x00C1,
|
MessageTypeMoveColorTemperature = 0x00C1,
|
||||||
StepColorTemperature = 0x00C2,
|
MessageTypeStepColorTemperature = 0x00C2,
|
||||||
|
|
||||||
/* ZHA Commands */
|
// ZHA Commands
|
||||||
/* Door Lock Cluster */
|
// Door Lock Cluster
|
||||||
LockUnlockDoor = 0x00F0,
|
MessageTypeLockUnlockDoor = 0x00F0,
|
||||||
|
|
||||||
/* Attributes */
|
// Attributes
|
||||||
ReadAttributeRequest = 0x0100,
|
MessageTypeReadAttributeRequest = 0x0100,
|
||||||
ReadAttributeResponse = 0x8100,
|
MessageTypeReadAttributeResponse = 0x8100,
|
||||||
DefaultResponse = 0x8101,
|
MessageTypeDefaultResponse = 0x8101,
|
||||||
AttributeReport = 0x8102,
|
MessageTypeAttributeReport = 0x8102,
|
||||||
WriteAttributeRequest = 0x0110,
|
MessageTypeWriteAttributeRequest = 0x0110,
|
||||||
WriteAttributeResponse = 0x8110,
|
MessageTypeWriteAttributeResponse = 0x8110,
|
||||||
ConfigReportingRequest = 0x0120,
|
MessageTypeConfigReportingRequest = 0x0120,
|
||||||
ConfigReportingResponse = 0x8120,
|
MessageTypeConfigReportingResponse = 0x8120,
|
||||||
ReportAttributes = 0x8121,
|
MessageTypeReportAttributes = 0x8121,
|
||||||
AttributeDiscoveryRequest = 0x0140,
|
MessageTypeAttributeDiscoveryRequest = 0x0140,
|
||||||
AttributeDiscoveryResponse = 0x8140,
|
MessageTypeAttributeDiscoveryResponse = 0x8140,
|
||||||
|
|
||||||
/* Persistant data manager messages */
|
/* Persistant data manager messages */
|
||||||
DataManagerAvailableRequest = 0x0300,
|
MessageTypeDataManagerAvailableRequest = 0x0300,
|
||||||
DataManagerAvailableResponse = 0x8300,
|
MessageTypeDataManagerAvailableResponse = 0x8300,
|
||||||
DataManagerSaveRecordRequest = 0x0200,
|
MessageTypeDataManagerSaveRecordRequest = 0x0200,
|
||||||
DataManagerSaveRecordResponse = 0x8200,
|
MessageTypeDataManagerSaveRecordResponse = 0x8200,
|
||||||
DataManagerLoadRecordRequest = 0x0201,
|
MessageTypeDataManagerLoadRecordRequest = 0x0201,
|
||||||
DataManagerLoadRecordResponse = 0x8201,
|
MessageTypeDataManagerLoadRecordResponse = 0x8201,
|
||||||
DataManagerDeleteAllRecordsRequest = 0x0202,
|
MessageTypeDataManagerDeleteAllRecordsRequest = 0x0202,
|
||||||
DataManagerDeleteAllRecordsResponse = 0x8202,
|
MessageTypeDataManagerDeleteAllRecordsResponse = 0x8202,
|
||||||
|
|
||||||
/* Appliance Statistics Cluster 0x0B03 */
|
/* Appliance Statistics Cluster 0x0B03 */
|
||||||
// http://www.nxp.com/documents/user_manual/JN-UG-3076.pdf
|
// http://www.nxp.com/documents/user_manual/JN-UG-3076.pdf
|
||||||
StatisticsClusterLogMessage = 0x0301, // Was 0x0500, was 0x0301
|
MessageTypeStatisticsClusterLogMessage = 0x0301, // Was 0x0500, was 0x0301
|
||||||
StatisticsClusterLogMessageResponse = 0x8301,
|
MessageTypeStatisticsClusterLogMessageResponse = 0x8301,
|
||||||
|
|
||||||
/* IAS Cluster */
|
/* IAS Cluster */
|
||||||
SendIasZoneEnroolResponse = 0x0400,
|
MessageTypeSendIasZoneEnroolResponse = 0x0400,
|
||||||
IasZoneStatusChangeNotify = 0x8401,
|
MessageTypeIasZoneStatusChangeNotify = 0x8401,
|
||||||
};
|
};
|
||||||
Q_ENUM(InterfaceMessageType)
|
Q_ENUM(InterfaceMessageType)
|
||||||
|
|
||||||
static QString convertByteToHexString(const quint8 &byte);
|
|
||||||
static QString convertByteArrayToHexString(const QByteArray &byteArray);
|
|
||||||
static QString convertByte16ToHexString(const quint16 &byte);
|
|
||||||
|
|
||||||
|
enum ClusterId {
|
||||||
|
// Basics
|
||||||
|
ClusterIdBasic = 0x0000,
|
||||||
|
ClusterIdPower = 0x0001,
|
||||||
|
ClusterIdDeviceTemperature = 0x0002,
|
||||||
|
ClusterIdIdentify = 0x0003,
|
||||||
|
ClusterIdGroups = 0x0004,
|
||||||
|
ClusterIdScenes = 0x0005,
|
||||||
|
ClusterIdOnOff = 0x0006,
|
||||||
|
ClusterIdOnOffCOnfiguration = 0x0007,
|
||||||
|
ClusterIdLevelControl = 0x0008,
|
||||||
|
ClusterIdAlarms = 0x0009,
|
||||||
|
ClusterIdTime = 0x000A,
|
||||||
|
ClusterIdRssiLocation = 0x000B,
|
||||||
|
ClusterIdAnalogInputBasic = 0x000C,
|
||||||
|
ClusterIdAnalogOutputBasic = 0x000D,
|
||||||
|
ClusterIdValueBasic = 0x000E,
|
||||||
|
ClusterIdBinaryInputBasic = 0x000F,
|
||||||
|
ClusterIdBinaryOutputBasic = 0x0010,
|
||||||
|
ClusterIdBinaryValueBasic = 0x0011,
|
||||||
|
ClusterIdMultiStateInputBasic = 0x0012,
|
||||||
|
ClusterIdMultiStateOutputBasic = 0x0013,
|
||||||
|
ClusterIdMultiStateValueBasic = 0x0014,
|
||||||
|
ClusterIdCommissoning = 0x0015,
|
||||||
|
|
||||||
|
// Over the air uppgrade (OTA)
|
||||||
|
ClusterIdOtaUpgrade = 0x0019,
|
||||||
|
|
||||||
|
// Closures
|
||||||
|
ClusterIdShadeConfiguration = 0x0100,
|
||||||
|
|
||||||
|
// Door Lock
|
||||||
|
ClusterIdDoorLock = 0x0101,
|
||||||
|
|
||||||
|
// Heating, Ventilation and Air-Conditioning (HVAC)
|
||||||
|
ClusterIdPumpConfigurationControl = 0x0200,
|
||||||
|
ClusterIdThermostat = 0x0201,
|
||||||
|
ClusterIdFanControll = 0x0202,
|
||||||
|
ClusterIdDehumiditationControll = 0x0203,
|
||||||
|
ClusterIdThermostatUserControll = 0x0204,
|
||||||
|
|
||||||
|
// Lighting
|
||||||
|
ClusterIdColorControl = 0x0300,
|
||||||
|
ClusterIdBallastConfiguration = 0x0301,
|
||||||
|
|
||||||
|
// Sensing
|
||||||
|
ClusterIdMeasurementIlluminance = 0x0400,
|
||||||
|
ClusterIdIlluminanceLevelSensing = 0x0401,
|
||||||
|
ClusterIdTemperatureMeasurement = 0x0402,
|
||||||
|
ClusterIdPressureMeasurement = 0x0403,
|
||||||
|
ClusterIdFlowMeasurement = 0x0404,
|
||||||
|
ClusterIdRelativeHumidityMeasurement = 0x0405,
|
||||||
|
ClusterIdOccapancySensing = 0x0406,
|
||||||
|
|
||||||
|
// Security and Safty
|
||||||
|
ClusterIdIasZone = 0x0500,
|
||||||
|
ClusterIdIasAce = 0x0501,
|
||||||
|
ClusterIdIasWd = 0x0502,
|
||||||
|
|
||||||
|
// Smart energy
|
||||||
|
ClusterIdPrice = 0x0700,
|
||||||
|
ClusterIdLoadControl = 0x0701,
|
||||||
|
ClusterIdSimpleMetering = 0x0702,
|
||||||
|
|
||||||
|
// Electrical Measurement
|
||||||
|
ClusterIdElectricalMeasurement = 0x0B04,
|
||||||
|
|
||||||
|
// ZLL
|
||||||
|
ClusterIdTouchlinkCommissioning = 0x1000
|
||||||
|
};
|
||||||
|
Q_ENUM(ClusterId)
|
||||||
|
|
||||||
|
enum LightLinkDevice {
|
||||||
|
|
||||||
|
// Lightning devices
|
||||||
|
LightLinkDeviceOnOffLight = 0x0000,
|
||||||
|
LightLinkDeviceOnOffPlug = 0x0010,
|
||||||
|
LightLinkDeviceDimmableLight = 0x0100,
|
||||||
|
LightLinkDeviceDimmablePlug = 0x0110,
|
||||||
|
LightLinkDeviceColourLight = 0x0200,
|
||||||
|
LightLinkDeviceExtendedColourLight = 0x0210,
|
||||||
|
LightLinkDeviceColourTemperatureLight = 0x0220,
|
||||||
|
|
||||||
|
// Controller devices
|
||||||
|
LightLinkDeviceColourController = 0x8000,
|
||||||
|
LightLinkDeviceColourSceneController = 0x8010,
|
||||||
|
LightLinkDeviceNonColourController = 0x8020,
|
||||||
|
LightLinkDeviceNonColourSceneController = 0x8030,
|
||||||
|
LightLinkDeviceControlBridge = 0x8040,
|
||||||
|
LightLinkDeviceOnOffSensor = 0x8050
|
||||||
|
};
|
||||||
|
Q_ENUM(LightLinkDevice)
|
||||||
|
|
||||||
|
|
||||||
|
enum HomeAutomationDevice {
|
||||||
|
// Generic devices
|
||||||
|
HomeAutomationDeviceOnOffSwitch = 0x0000,
|
||||||
|
HomeAutomationDeviceOnOffOutput = 0x0002,
|
||||||
|
HomeAutomationDeviceRemoteControl = 0x0006,
|
||||||
|
HomeAutomationDeviceDoorLock = 0x000A,
|
||||||
|
HomeAutomationDeviceDoorLockController = 0x000B,
|
||||||
|
HomeAutomationDeviceSimpleSensor = 0x000C,
|
||||||
|
HomeAutomationDeviceSmartPlug = 0x0051,
|
||||||
|
|
||||||
|
// Lightning devices
|
||||||
|
HomeAutomationDeviceOnOffLight = 0x0100,
|
||||||
|
HomeAutomationDeviceDimmableLight = 0x0101,
|
||||||
|
HomeAutomationDeviceDimmableColorLight = 0x0102,
|
||||||
|
HomeAutomationDeviceOnOffLightSwitch = 0x0103,
|
||||||
|
HomeAutomationDeviceDimmableSwitch = 0x0104,
|
||||||
|
HomeAutomationDeviceColourDimmerSwitch = 0x0105,
|
||||||
|
HomeAutomationDeviceLightSensor = 0x0106,
|
||||||
|
HomeAutomationDeviceOccupacySensor = 0x0106,
|
||||||
|
|
||||||
|
// Heating, Ventilation and Air-Conditioning (HVAC) devices
|
||||||
|
HomeAutomationDeviceThermostat = 0x0301,
|
||||||
|
|
||||||
|
// Intruder Alarm System (IAS) devices
|
||||||
|
HomeAutomationDeviceIsaControlEquipment = 0x0400, // CIE
|
||||||
|
HomeAutomationDeviceIsaAncillaryControlEquipment = 0x0401, // ACE
|
||||||
|
HomeAutomationDeviceIsaZone = 0x0401,
|
||||||
|
HomeAutomationDeviceIsaWarningDevice = 0x0401 // WD
|
||||||
|
};
|
||||||
|
Q_ENUM(HomeAutomationDevice)
|
||||||
|
|
||||||
|
// enum DeviceType {
|
||||||
|
// DeviceTypeUnknown = 0xFFFF, // Unknown type
|
||||||
|
// DeviceTypeBasic = 0x0002, // Gateway
|
||||||
|
// DeviceTypeGateway = 0x0002, // Gateway
|
||||||
|
// DeviceTypeSimpleSensor = 0x000C, // ZHA Simple Sensor
|
||||||
|
// DeviceTypeSmartPlug = 0x0051, // ZHA Smart Plug
|
||||||
|
// DeviceTypeControlBridge = 0x0840, // Control Bridge
|
||||||
|
// DeviceTypeLampOnOff = 0x0000, // ZLL on/off lamp
|
||||||
|
// DeviceTypeLampDimm = 0x0100, // ZLL mono lamp
|
||||||
|
|
||||||
|
//#define SIMPLE_DESCR_LAMP_DIMM_ZLL 0x0100 // ZLL mono lamp
|
||||||
|
//#define SIMPLE_DESCR_LAMP_ONOFF 0x0100 // ZHA on/off lamp
|
||||||
|
//#define SIMPLE_DESCR_LAMP_DIMM 0x0101 // ZHA dimmable lamp
|
||||||
|
//#define SIMPLE_DESCR_LAMP_COLOUR 0x0102 // ZHA dimmable colour lamp
|
||||||
|
//#define SIMPLE_DESCR_LAMP_CCTW 0x01FF // ZHA / ZLL CCTW lamp
|
||||||
|
//#define SIMPLE_DESCR_LAMP_COLOUR_DIMM 0x0200 // ZLL dimmable colour lamp
|
||||||
|
//#define SIMPLE_DESCR_LAMP_COLOUR_EXT 0x0210 // ZLL extended colour lamp
|
||||||
|
//#define SIMPLE_DESCR_LAMP_COLOUR_TEMP 0x0220 // ZLL colour temperature lamp
|
||||||
|
//#define SIMPLE_DESCR_HVAC_HC_UNIT 0x0300 // ZHA HVAC HC Unit (HeatingManager)
|
||||||
|
//#define SIMPLE_DESCR_THERMOSTAT 0x0301 // ZHA Thermostat
|
||||||
|
//#define SIMPLE_DESCR_HVAC_PUMP 0x0303 // ZHA NVAC Pump
|
||||||
|
//#define SIMPLE_DESCR_SWITCH_ONOFF 0x0103 // ZHA On/Off Switch
|
||||||
|
//#define SIMPLE_DESCR_SWITCH_DIMM 0x0104 // ZHA Dimm Switch
|
||||||
|
//#define SIMPLE_DESCR_SWITCH_COLL_DIMM 0x0105 // ZHA Color Dimm Switch
|
||||||
|
//#define SIMPLE_DESCR_LIGHT_SENSOR 0x0106 // ZHA Light sensor
|
||||||
|
//#define SIMPLE_DESCR_SMOKE_SENSOR 0x0012 // CES - TriTech CO/smoke sensor
|
||||||
|
//#define SIMPLE_DESCR_WINDOW_SENSOR 0x0014 // CES - window sensor
|
||||||
|
//#define SIMPLE_DESCR_OCCUPANCY_SENSOR 0x0107 // ZH/ZLO - Occupancy Sensor
|
||||||
|
// };
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
88
zigbeeaddress.cpp
Normal file
88
zigbeeaddress.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include "zigbeeaddress.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
ZigbeeAddress::ZigbeeAddress()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeAddress::ZigbeeAddress(quint64 address)
|
||||||
|
{
|
||||||
|
m_address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeAddress::ZigbeeAddress(const QString &address)
|
||||||
|
{
|
||||||
|
QString a = address;
|
||||||
|
|
||||||
|
if (a.length() == 17)
|
||||||
|
a.remove(QLatin1Char(':'));
|
||||||
|
|
||||||
|
if (a.length() == 12) {
|
||||||
|
bool ok;
|
||||||
|
m_address = a.toULongLong(&ok, 16);
|
||||||
|
if (!ok)
|
||||||
|
clear();
|
||||||
|
} else {
|
||||||
|
m_address = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeAddress::ZigbeeAddress(const ZigbeeAddress &other)
|
||||||
|
{
|
||||||
|
m_address = other.toUInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeAddress::~ZigbeeAddress()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 ZigbeeAddress::toUInt64() const
|
||||||
|
{
|
||||||
|
return m_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeAddress::toString() const
|
||||||
|
{
|
||||||
|
QString s(QStringLiteral("%1:%2:%3:%4:%5:%6"));
|
||||||
|
|
||||||
|
for (int i = 5; i >= 0; --i) {
|
||||||
|
const quint8 a = (m_address >> (i*8)) & 0xff;
|
||||||
|
s = s.arg(a, 2, 16, QLatin1Char('0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.toUpper();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZigbeeAddress::isNull() const
|
||||||
|
{
|
||||||
|
return m_address == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeAddress::clear()
|
||||||
|
{
|
||||||
|
m_address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZigbeeAddress::operator<(const ZigbeeAddress &other) const
|
||||||
|
{
|
||||||
|
return m_address < other.toUInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZigbeeAddress::operator==(const ZigbeeAddress &other) const
|
||||||
|
{
|
||||||
|
return m_address == other.toUInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZigbeeAddress::operator!=(const ZigbeeAddress &other) const
|
||||||
|
{
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, const ZigbeeAddress &address)
|
||||||
|
{
|
||||||
|
debug << address.toString();
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
34
zigbeeaddress.h
Normal file
34
zigbeeaddress.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef ZIGBEEADDRESS_H
|
||||||
|
#define ZIGBEEADDRESS_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class ZigbeeAddress
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ZigbeeAddress();
|
||||||
|
explicit ZigbeeAddress(quint64 address);
|
||||||
|
explicit ZigbeeAddress(const QString &address);
|
||||||
|
ZigbeeAddress(const ZigbeeAddress &other);
|
||||||
|
~ZigbeeAddress();
|
||||||
|
|
||||||
|
quint64 toUInt64() const;
|
||||||
|
QString toString() const;
|
||||||
|
|
||||||
|
bool isNull() const;
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
ZigbeeAddress &operator=(const ZigbeeAddress &other);
|
||||||
|
bool operator<(const ZigbeeAddress &other) const;
|
||||||
|
bool operator==(const ZigbeeAddress &other) const;
|
||||||
|
inline bool operator!=(const ZigbeeAddress &other) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint64 m_address;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, const ZigbeeAddress &address);
|
||||||
|
|
||||||
|
#endif // ZIGBEEADDRESS_H
|
||||||
89
zigbeebridgecontroller.cpp
Normal file
89
zigbeebridgecontroller.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "zigbeebridgecontroller.h"
|
||||||
|
#include "loggingcategory.h"
|
||||||
|
|
||||||
|
ZigbeeBridgeController::ZigbeeBridgeController(const QString &serialPort, QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
m_interface = new ZigbeeInterface(this);
|
||||||
|
|
||||||
|
connect(m_interface, &ZigbeeInterface::messageReceived, this, &ZigbeeBridgeController::onMessageReceived);
|
||||||
|
|
||||||
|
if (!m_interface->enable(serialPort)) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not enable ZigbeeInterface on" << serialPort;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZigbeeBridgeController::available() const
|
||||||
|
{
|
||||||
|
return m_interface->available();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeBridgeController::sendMessage(ZigbeeInterfaceReply *reply)
|
||||||
|
{
|
||||||
|
if (!reply)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_currentReply = reply;
|
||||||
|
qCDebug(dcZigbeeController()) << "Sending request:" << reply->request().description();
|
||||||
|
|
||||||
|
m_interface->sendMessage(reply->request().message());
|
||||||
|
reply->startTimer(reply->request().timeoutIntervall());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeBridgeController::onMessageReceived(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
// Check if we have a current reply
|
||||||
|
if (m_currentReply) {
|
||||||
|
if (message.messageType() == Zigbee::MessageTypeStatus) {
|
||||||
|
// We have a status message for the current reply
|
||||||
|
m_currentReply->setStatusMessage(message);
|
||||||
|
|
||||||
|
// TODO: check if success, if not, finish reply
|
||||||
|
|
||||||
|
} else if (message.messageType() == m_currentReply->request().expectedAdditionalMessageType()) {
|
||||||
|
m_currentReply->setAdditionalMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if request is complete
|
||||||
|
if (m_currentReply->isComplete()) {
|
||||||
|
m_currentReply->setFinished();
|
||||||
|
// Note: the request class has to take care about the reply object
|
||||||
|
m_currentReply = nullptr;
|
||||||
|
|
||||||
|
if (!m_replyQueue.isEmpty())
|
||||||
|
sendMessage(m_replyQueue.dequeue());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a reply message
|
||||||
|
emit messageReceived(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeBridgeController::onReplyTimeout()
|
||||||
|
{
|
||||||
|
m_currentReply->setFinished();
|
||||||
|
m_currentReply = nullptr;
|
||||||
|
|
||||||
|
if (!m_replyQueue.isEmpty())
|
||||||
|
sendMessage(m_replyQueue.dequeue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *ZigbeeBridgeController::sendRequest(const ZigbeeInterfaceRequest &request)
|
||||||
|
{
|
||||||
|
// Create Reply
|
||||||
|
ZigbeeInterfaceReply *reply = new ZigbeeInterfaceReply(request);
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::timeout, this, &ZigbeeBridgeController::onReplyTimeout);
|
||||||
|
|
||||||
|
// If reply running, enqueue, else send request
|
||||||
|
if (m_currentReply) {
|
||||||
|
m_replyQueue.enqueue(reply);
|
||||||
|
} else {
|
||||||
|
sendMessage(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
42
zigbeebridgecontroller.h
Normal file
42
zigbeebridgecontroller.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef ZIGBEEBRIDGECONTROLLER_H
|
||||||
|
#define ZIGBEEBRIDGECONTROLLER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
#include "zigbee.h"
|
||||||
|
#include "interface/zigbeeinterface.h"
|
||||||
|
#include "interface/zigbeeinterfacereply.h"
|
||||||
|
#include "interface/zigbeeinterfacerequest.h"
|
||||||
|
#include "interface/zigbeeinterfacemessage.h"
|
||||||
|
|
||||||
|
class ZigbeeBridgeController : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ZigbeeBridgeController(const QString &serialPort, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
bool available() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ZigbeeInterface *m_interface = nullptr;
|
||||||
|
ZigbeeInterfaceReply *m_currentReply = nullptr;
|
||||||
|
|
||||||
|
QQueue<ZigbeeInterfaceReply *> m_replyQueue;
|
||||||
|
|
||||||
|
void sendMessage(ZigbeeInterfaceReply *reply);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void messageReceived(const ZigbeeInterfaceMessage &message);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onMessageReceived(const ZigbeeInterfaceMessage &message);
|
||||||
|
void onReplyTimeout();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
ZigbeeInterfaceReply *sendRequest(const ZigbeeInterfaceRequest &request);
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ZIGBEEBRIDGECONTROLLER_H
|
||||||
@ -1,49 +0,0 @@
|
|||||||
#include "zigbeemanager.h"
|
|
||||||
#include "loggingcategory.h"
|
|
||||||
|
|
||||||
ZigbeeManager::ZigbeeManager(const QString &serialPort, QObject *parent) :
|
|
||||||
QObject(parent),
|
|
||||||
m_serialPort(serialPort)
|
|
||||||
{
|
|
||||||
m_interface = new ZigbeeInterface(this);
|
|
||||||
|
|
||||||
connect(m_interface, &ZigbeeInterface::messageReceived, this, &ZigbeeManager::onMessageReceived);
|
|
||||||
|
|
||||||
|
|
||||||
if (!m_interface->enable(m_serialPort)) {
|
|
||||||
qCWarning(dcZigbee()) << "Could not enable ZigbeeInterface on" << m_serialPort;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
initController();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ZigbeeManager::serialPort() const
|
|
||||||
{
|
|
||||||
return m_serialPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZigbeeManager::setSerialPort(const QString &serialPort)
|
|
||||||
{
|
|
||||||
if (m_serialPort == serialPort)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_serialPort = serialPort;
|
|
||||||
m_interface->disable();
|
|
||||||
m_interface->enable(m_serialPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZigbeeManager::initController()
|
|
||||||
{
|
|
||||||
ZigbeeInterfaceMessage message;
|
|
||||||
message.setMessageType(Zigbee::DataManagerAvailableResponse);
|
|
||||||
message.setData(QByteArray::fromRawData("\x00\x00", 2));
|
|
||||||
|
|
||||||
m_interface->sendMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZigbeeManager::onMessageReceived(const ZigbeeInterfaceMessage &message)
|
|
||||||
{
|
|
||||||
qCDebug(dcZigbee()) << message;
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#ifndef ZIGBEEMANAGER_H
|
|
||||||
#define ZIGBEEMANAGER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include "zigbee.h"
|
|
||||||
#include "zigbeeinterface.h"
|
|
||||||
#include "zigbeeinterfacemessage.h"
|
|
||||||
|
|
||||||
class ZigbeeManager : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit ZigbeeManager(const QString &serialPort = "/dev/ttyS0", QObject *parent = nullptr);
|
|
||||||
|
|
||||||
QString serialPort() const;
|
|
||||||
void setSerialPort(const QString &serialPort);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ZigbeeInterface *m_interface;
|
|
||||||
QString m_serialPort;
|
|
||||||
|
|
||||||
// Controller methods
|
|
||||||
void initController();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onMessageReceived(const ZigbeeInterfaceMessage &message);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ZIGBEEMANAGER_H
|
|
||||||
776
zigbeenetworkmanager.cpp
Normal file
776
zigbeenetworkmanager.cpp
Normal file
@ -0,0 +1,776 @@
|
|||||||
|
#include "zigbeenetworkmanager.h"
|
||||||
|
#include "loggingcategory.h"
|
||||||
|
#include "zigbeeutils.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
|
ZigbeeNetworkManager::ZigbeeNetworkManager(const QString &serialPort, QObject *parent) :
|
||||||
|
ZigbeeNode(parent),
|
||||||
|
m_serialPort(serialPort)
|
||||||
|
{
|
||||||
|
// TODO: load PAN id and serial port
|
||||||
|
reset();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeNetworkManager::serialPort() const
|
||||||
|
{
|
||||||
|
return m_serialPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::setSerialPort(const QString &serialPort)
|
||||||
|
{
|
||||||
|
if (m_serialPort == serialPort)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_serialPort = serialPort;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeNetworkManager::controllerVersion() const
|
||||||
|
{
|
||||||
|
return m_controllerVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::reset()
|
||||||
|
{
|
||||||
|
if (m_controller) {
|
||||||
|
delete m_controller;
|
||||||
|
m_controller = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//m_extendedPanId = generateRandomPanId();
|
||||||
|
m_extendedPanId = 1180461015847120384;
|
||||||
|
qCDebug(dcZigbee()) << "PAN ID" << m_extendedPanId;
|
||||||
|
|
||||||
|
m_controller = new ZigbeeBridgeController(m_serialPort, this);
|
||||||
|
connect(m_controller, &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived);
|
||||||
|
|
||||||
|
if (m_controller->available()) {
|
||||||
|
qCDebug(dcZigbee()) << "Bridge controller started successfully on" << m_serialPort;
|
||||||
|
} else {
|
||||||
|
qCWarning(dcZigbee()) << "The zigbee controller is not available";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call init methods
|
||||||
|
erasePersistentData();
|
||||||
|
//reset();
|
||||||
|
getVersion();
|
||||||
|
setExtendedPanId(m_extendedPanId);
|
||||||
|
setChannelMask(0);
|
||||||
|
setDeviceType(NodeTypeCoordinator);
|
||||||
|
startNetwork();
|
||||||
|
//startScan();
|
||||||
|
getPermitJoiningStatus();
|
||||||
|
permitJoining();
|
||||||
|
getPermitJoiningStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 ZigbeeNetworkManager::generateRandomPanId()
|
||||||
|
{
|
||||||
|
srand(static_cast<int>(QDateTime::currentMSecsSinceEpoch() / 1000));
|
||||||
|
srand(qrand());
|
||||||
|
return (ULLONG_MAX - 0) * (qrand()/(double)RAND_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::resetController()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeReset));
|
||||||
|
request.setDescription("Reset controller");
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *reply = m_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 = m_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 = m_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 = m_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");
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *reply = m_controller->sendRequest(request);
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetExtendedPanIdFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::setChannelMask(const quint32 &channelMask)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||||
|
stream << channelMask;
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetChannelMask, data));
|
||||||
|
request.setDescription("Set channel mask");
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *reply = m_controller->sendRequest(request);
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetChannelMaskFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::setDeviceType(const NodeType &deviceType)
|
||||||
|
{
|
||||||
|
quint8 deviceTypeValue = static_cast<quint8>(deviceType);
|
||||||
|
|
||||||
|
QByteArray data;
|
||||||
|
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||||
|
stream << deviceTypeValue;
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetDeviceType, data));
|
||||||
|
request.setDescription("Set device type");
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *reply = m_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 = m_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 = m_controller->sendRequest(request);
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onStartScanFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::permitJoining(quint16 targetAddress, const quint8 advertisingIntervall)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||||
|
stream << targetAddress;
|
||||||
|
stream << advertisingIntervall;
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePermitJoiningRequest, data));
|
||||||
|
request.setDescription("Permit joining request");
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *reply = m_controller->sendRequest(request);
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onPermitJoiningFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::getPermitJoiningStatus()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeGetPermitJoining));
|
||||||
|
request.setDescription("Get permit joining status");
|
||||||
|
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeGetPermitJoiningResponse);
|
||||||
|
request.setTimoutIntervall(1000);
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *reply = m_controller->sendRequest(request);
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onGetPermitJoiningStatusFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::requestNodeDescription(const 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");
|
||||||
|
request.setTimoutIntervall(10000);
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *reply = m_controller->sendRequest(request);
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestNodeDescriptionFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::requestSimpleNodeDescription(const quint16 &shortAddress, const quint8 &endpoint)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||||
|
stream << shortAddress;
|
||||||
|
stream << endpoint;
|
||||||
|
|
||||||
|
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSimpleDescriptorRequest, data));
|
||||||
|
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeSimpleDescriptorResponse);
|
||||||
|
request.setDescription("Simple node descriptor request");
|
||||||
|
request.setTimoutIntervall(10000);
|
||||||
|
|
||||||
|
ZigbeeInterfaceReply *reply = m_controller->sendRequest(request);
|
||||||
|
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestSimpleNodeDescriptionFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onResetControllerFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onErasePersistentDataFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onGetVersionFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply->additionalMessage().data().count() != 4) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << ":" << "Invalid payload size";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
|
||||||
|
// Parse major version
|
||||||
|
quint16 majorVersion = reply->additionalMessage().data().at(0);
|
||||||
|
majorVersion <<= 8;
|
||||||
|
majorVersion |= reply->additionalMessage().data().at(1);
|
||||||
|
|
||||||
|
// Parse minor version
|
||||||
|
quint16 minorVersion = reply->additionalMessage().data().at(2);
|
||||||
|
minorVersion <<= 8;
|
||||||
|
minorVersion |= reply->additionalMessage().data().at(3);
|
||||||
|
|
||||||
|
m_controllerVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
|
||||||
|
qCDebug(dcZigbee()) << "Version:" << m_controllerVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onSetExtendedPanIdFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onSetChannelMaskFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(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<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onStartNetworkFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(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";
|
||||||
|
qCDebug(dcZigbeeController()) << reply->additionalMessage();
|
||||||
|
|
||||||
|
// Parse network status
|
||||||
|
quint8 networkStatus = static_cast<quint8>(reply->additionalMessage().data().at(0));
|
||||||
|
QString networkStatusString;
|
||||||
|
|
||||||
|
if (networkStatus == 0) {
|
||||||
|
networkStatusString = "joined";
|
||||||
|
} else if (networkStatus == 1) {
|
||||||
|
networkStatusString = "formed";
|
||||||
|
} else if (networkStatus >= 128 && networkStatus <= 244) {
|
||||||
|
networkStatusString = "failed: Zigbee event code: " + QString::number(networkStatus);
|
||||||
|
} else {
|
||||||
|
networkStatusString = "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Parse short network address
|
||||||
|
quint16 shortAddress = reply->additionalMessage().data().at(1);
|
||||||
|
shortAddress <<= 8;
|
||||||
|
shortAddress |= reply->additionalMessage().data().at(2);
|
||||||
|
|
||||||
|
// Parse extended network address
|
||||||
|
quint64 extendedAddress = reply->additionalMessage().data().at(3);
|
||||||
|
extendedAddress <<= 8;
|
||||||
|
extendedAddress |= reply->additionalMessage().data().at(4);
|
||||||
|
extendedAddress <<= 8;
|
||||||
|
extendedAddress |= reply->additionalMessage().data().at(5);
|
||||||
|
extendedAddress <<= 8;
|
||||||
|
extendedAddress |= reply->additionalMessage().data().at(6);
|
||||||
|
extendedAddress <<= 8;
|
||||||
|
extendedAddress |= reply->additionalMessage().data().at(7);
|
||||||
|
extendedAddress <<= 8;
|
||||||
|
extendedAddress |= reply->additionalMessage().data().at(8);
|
||||||
|
extendedAddress <<= 8;
|
||||||
|
extendedAddress |= reply->additionalMessage().data().at(9);
|
||||||
|
extendedAddress <<= 8;
|
||||||
|
extendedAddress |= reply->additionalMessage().data().at(10);
|
||||||
|
|
||||||
|
// Parse network channel
|
||||||
|
quint8 channel = static_cast<quint8>(reply->additionalMessage().data().at(11));
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << "Network" << networkStatusString;
|
||||||
|
qCDebug(dcZigbee()) << " short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
|
||||||
|
qCDebug(dcZigbee()) << " extended address:" << ZigbeeUtils::convertUint64ToHexString(extendedAddress);
|
||||||
|
qCDebug(dcZigbee()) << " channel:" << channel;
|
||||||
|
|
||||||
|
// Set the node information
|
||||||
|
setShortAddress(shortAddress);
|
||||||
|
setExtendedAddress(extendedAddress);
|
||||||
|
|
||||||
|
// Request data
|
||||||
|
requestNodeDescription(shortAddress);
|
||||||
|
requestSimpleNodeDescription(shortAddress);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onStartScanFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
qCDebug(dcZigbeeController()) << reply->additionalMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onGetPermitJoiningStatusFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
qCDebug(dcZigbeeController()) << reply->additionalMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onPermitJoiningFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onRequestNodeDescriptionFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
|
||||||
|
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
|
||||||
|
quint8 status = static_cast<quint8>(reply->additionalMessage().data().at(1));
|
||||||
|
|
||||||
|
quint16 shortAddress = reply->additionalMessage().data().at(2);
|
||||||
|
shortAddress <<= 8;
|
||||||
|
shortAddress |= reply->additionalMessage().data().at(3);
|
||||||
|
|
||||||
|
quint16 manufacturerCode = reply->additionalMessage().data().at(4);
|
||||||
|
manufacturerCode <<= 8;
|
||||||
|
manufacturerCode |= reply->additionalMessage().data().at(5);
|
||||||
|
|
||||||
|
quint16 maximalRxSize = reply->additionalMessage().data().at(6);
|
||||||
|
maximalRxSize <<= 8;
|
||||||
|
maximalRxSize |= reply->additionalMessage().data().at(7);
|
||||||
|
|
||||||
|
quint16 maximalTxSize = reply->additionalMessage().data().at(8);
|
||||||
|
maximalTxSize <<= 8;
|
||||||
|
maximalTxSize |= reply->additionalMessage().data().at(9);
|
||||||
|
|
||||||
|
quint16 serverMask = reply->additionalMessage().data().at(10);
|
||||||
|
serverMask <<= 8;
|
||||||
|
serverMask |= reply->additionalMessage().data().at(11);
|
||||||
|
|
||||||
|
quint8 descriptorFlag = static_cast<quint8>(reply->additionalMessage().data().at(12));
|
||||||
|
quint8 macFlags = static_cast<quint8>(reply->additionalMessage().data().at(13));
|
||||||
|
quint8 maxBufferSize = static_cast<quint8>(reply->additionalMessage().data().at(14));
|
||||||
|
|
||||||
|
quint16 bitField = reply->additionalMessage().data().at(15);
|
||||||
|
bitField <<= 8;
|
||||||
|
bitField |= reply->additionalMessage().data().at(16);
|
||||||
|
|
||||||
|
// TODO: find note for short address and set data
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << "Node descriptor:";
|
||||||
|
qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
|
||||||
|
qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
|
||||||
|
qCDebug(dcZigbee()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
|
||||||
|
qCDebug(dcZigbee()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode);
|
||||||
|
qCDebug(dcZigbee()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(maximalRxSize);
|
||||||
|
qCDebug(dcZigbee()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(maximalTxSize);
|
||||||
|
qCDebug(dcZigbee()) << " Server makk:" << ZigbeeUtils::convertUint16ToHexString(serverMask);
|
||||||
|
qCDebug(dcZigbee()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorFlag);
|
||||||
|
qCDebug(dcZigbee()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macFlags);
|
||||||
|
qCDebug(dcZigbee()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(maxBufferSize);
|
||||||
|
qCDebug(dcZigbee()) << " Bit field:" << ZigbeeUtils::convertUint16ToHexString(bitField);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onRequestSimpleNodeDescriptionFinished()
|
||||||
|
{
|
||||||
|
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->status() != ZigbeeInterfaceReply::Success) {
|
||||||
|
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
|
||||||
|
qCDebug(dcZigbeeController()) << reply->additionalMessage();
|
||||||
|
|
||||||
|
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
|
||||||
|
quint8 status = static_cast<quint8>(reply->additionalMessage().data().at(1));
|
||||||
|
|
||||||
|
quint16 nwkAddress = reply->additionalMessage().data().at(2);
|
||||||
|
nwkAddress <<= 8;
|
||||||
|
nwkAddress |= reply->additionalMessage().data().at(3);
|
||||||
|
|
||||||
|
quint8 length = static_cast<quint8>(reply->additionalMessage().data().at(4));
|
||||||
|
quint8 endPoint = static_cast<quint8>(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<quint8>(reply->additionalMessage().data().at(10));
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << "Node somple 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);
|
||||||
|
qCDebug(dcZigbee()) << " Device ID:" << ZigbeeUtils::convertUint16ToHexString(deviceId);
|
||||||
|
qCDebug(dcZigbee()) << " Bit field:" << ZigbeeUtils::convertByteToHexString(bitField);
|
||||||
|
|
||||||
|
quint8 inputClusterCount = static_cast<quint8>(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) << static_cast<Zigbee::ClusterId>(clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
quint8 outputClusterCount = static_cast<quint8>(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) << static_cast<Zigbee::ClusterId>(clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::processLoggingMessage(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
quint8 logLevel = static_cast<quint8>(message.data().at(0));
|
||||||
|
QString logMessage = QString::fromUtf8(message.data().right(message.data().count() - 1));
|
||||||
|
|
||||||
|
QString logLevelString;
|
||||||
|
switch (logLevel) {
|
||||||
|
case 0:
|
||||||
|
logLevelString = "Emergency:";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
logLevelString = "Alert:";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
logLevelString = "Critical:";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
logLevelString = "Error:";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
logLevelString = "Warning:";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
logLevelString = "Notice:";
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
logLevelString = "Information:";
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
logLevelString = "Debug:";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logLevelString = "Unknown:";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logLevel < 5) {
|
||||||
|
qCWarning(dcZigbeeController()).noquote() << "ControllerLog:" << logLevelString << logMessage;
|
||||||
|
} else {
|
||||||
|
qCDebug(dcZigbeeController()).noquote() << "ControllerLog:" << logLevelString << logMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::processFactoryNewRestart(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
quint8 controllerStatus = static_cast<quint8>(message.data().at(0));
|
||||||
|
QString controllerStatusString;
|
||||||
|
switch (controllerStatus) {
|
||||||
|
case 0:
|
||||||
|
controllerStatusString = "startup";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
controllerStatusString = "NRF start";
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
controllerStatusString = "running";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << "Restart finished. Current controller state:" << controllerStatusString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::processNodeClusterList(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
quint8 sourceEndpoint = static_cast<quint8>(message.data().at(0));
|
||||||
|
|
||||||
|
quint16 profileId = static_cast<quint8>(message.data().at(1));
|
||||||
|
profileId <<= 8;
|
||||||
|
profileId |= static_cast<quint8>(message.data().at(2));
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << "Node cluster list received:";
|
||||||
|
qCDebug(dcZigbee()) << " Souce endpoint:" << sourceEndpoint;
|
||||||
|
qCDebug(dcZigbee()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
|
||||||
|
|
||||||
|
|
||||||
|
QByteArray clusterListData = message.data().right(message.data().count() - 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < clusterListData.count(); i+=2) {
|
||||||
|
quint16 clusterId = clusterListData.at(i);
|
||||||
|
clusterId <<= 8;
|
||||||
|
clusterId |= clusterListData .at(i+1);
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId)) << static_cast<Zigbee::ClusterId>(clusterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::processNodeAttributeList(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
quint8 sourceEndpoint = static_cast<quint8>(message.data().at(0));
|
||||||
|
|
||||||
|
quint16 profileId = static_cast<quint8>(message.data().at(1));
|
||||||
|
profileId <<= 8;
|
||||||
|
profileId |= static_cast<quint8>(message.data().at(2));
|
||||||
|
|
||||||
|
quint16 clusterId = static_cast<quint8>(message.data().at(3));
|
||||||
|
clusterId <<= 8;
|
||||||
|
clusterId |= static_cast<quint8>(message.data().at(4));
|
||||||
|
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << "Node attribute list received:";
|
||||||
|
qCDebug(dcZigbee()) << " Souce endpoint:" << sourceEndpoint;
|
||||||
|
qCDebug(dcZigbee()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
|
||||||
|
qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
|
||||||
|
|
||||||
|
QByteArray attributeListData = message.data().right(message.data().count() - 5);
|
||||||
|
|
||||||
|
for (int i = 0; i < attributeListData.count(); i+=2) {
|
||||||
|
quint16 attribute = attributeListData.at(i);
|
||||||
|
attribute <<= 8;
|
||||||
|
attribute |= attributeListData .at(i+1);
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << " Attribute:" << ZigbeeUtils::convertUint16ToHexString(attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::processNodeCommandIdList(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
quint8 sourceEndpoint = static_cast<quint8>(message.data().at(0));
|
||||||
|
|
||||||
|
quint16 profileId = static_cast<quint8>(message.data().at(1));
|
||||||
|
profileId <<= 8;
|
||||||
|
profileId |= static_cast<quint8>(message.data().at(2));
|
||||||
|
|
||||||
|
quint16 clusterId = static_cast<quint8>(message.data().at(3));
|
||||||
|
clusterId <<= 8;
|
||||||
|
clusterId |= static_cast<quint8>(message.data().at(4));
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << "Node command list received:";
|
||||||
|
qCDebug(dcZigbee()) << " Souce endpoint:" << sourceEndpoint;
|
||||||
|
qCDebug(dcZigbee()) << " Profile:" << ZigbeeUtils::profileIdToString(static_cast<Zigbee::ZigbeeProfile>(profileId));
|
||||||
|
qCDebug(dcZigbee()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
|
||||||
|
|
||||||
|
QByteArray commandListData = message.data().right(message.data().count() - 5);
|
||||||
|
|
||||||
|
for (int i = 0; i < commandListData.count(); i++) {
|
||||||
|
quint8 attribute = commandListData.at(i);
|
||||||
|
qCDebug(dcZigbee()) << " Command:" << ZigbeeUtils::convertByteToHexString(attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
quint16 shortAddress = message.data().at(0);
|
||||||
|
shortAddress <<= 8;
|
||||||
|
shortAddress |= message.data().at(1);
|
||||||
|
|
||||||
|
quint64 ieeeAddress = message.data().at(2);
|
||||||
|
ieeeAddress <<= 8;
|
||||||
|
ieeeAddress |= message.data().at(3);
|
||||||
|
ieeeAddress <<= 8;
|
||||||
|
ieeeAddress |= message.data().at(4);
|
||||||
|
ieeeAddress <<= 8;
|
||||||
|
ieeeAddress |= message.data().at(5);
|
||||||
|
ieeeAddress <<= 8;
|
||||||
|
ieeeAddress |= message.data().at(6);
|
||||||
|
ieeeAddress <<= 8;
|
||||||
|
ieeeAddress |= message.data().at(7);
|
||||||
|
ieeeAddress <<= 8;
|
||||||
|
ieeeAddress |= message.data().at(8);
|
||||||
|
ieeeAddress <<= 8;
|
||||||
|
ieeeAddress |= message.data().at(9);
|
||||||
|
|
||||||
|
quint8 macCapability = message.data().at(10);
|
||||||
|
|
||||||
|
qCDebug(dcZigbee()) << "Device announced:";
|
||||||
|
qCDebug(dcZigbee()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
|
||||||
|
qCDebug(dcZigbee()) << " Extended address:" << ZigbeeUtils::convertUint64ToHexString(ieeeAddress);
|
||||||
|
qCDebug(dcZigbee()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapability);
|
||||||
|
|
||||||
|
// TODO: parse mac capabilities
|
||||||
|
|
||||||
|
requestNodeDescription(shortAddress);
|
||||||
|
requestSimpleNodeDescription(shortAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &message)
|
||||||
|
{
|
||||||
|
switch (message.messageType()) {
|
||||||
|
case Zigbee::MessageTypeLogging:
|
||||||
|
processLoggingMessage(message);
|
||||||
|
break;
|
||||||
|
case Zigbee::MessageTypeFactoryNewRestart:
|
||||||
|
processFactoryNewRestart(message);
|
||||||
|
break;
|
||||||
|
case Zigbee::MessageTypeNodeClusterList:
|
||||||
|
processNodeClusterList(message);
|
||||||
|
break;
|
||||||
|
case Zigbee::MessageTypeNodeAttributeList:
|
||||||
|
processNodeAttributeList(message);
|
||||||
|
break;
|
||||||
|
case Zigbee::MessageTypeNodeCommandIdList:
|
||||||
|
processNodeCommandIdList(message);
|
||||||
|
break;
|
||||||
|
case Zigbee::MessageTypeDeviceAnnounce:
|
||||||
|
processDeviceAnnounce(message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(dcZigbeeController()) << "Message received:" << message;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
74
zigbeenetworkmanager.h
Normal file
74
zigbeenetworkmanager.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef ZIGBEEMANAGER_H
|
||||||
|
#define ZIGBEEMANAGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "zigbeenode.h"
|
||||||
|
#include "zigbeebridgecontroller.h"
|
||||||
|
|
||||||
|
class ZigbeeNetworkManager : public ZigbeeNode
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ZigbeeNetworkManager(const QString &serialPort = "/dev/ttyS0", QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QString serialPort() const;
|
||||||
|
void setSerialPort(const QString &serialPort);
|
||||||
|
|
||||||
|
QString controllerVersion() const;
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ZigbeeBridgeController *m_controller = nullptr;
|
||||||
|
QString m_serialPort;
|
||||||
|
QString m_controllerVersion;
|
||||||
|
quint64 m_extendedPanId;
|
||||||
|
|
||||||
|
quint64 generateRandomPanId();
|
||||||
|
|
||||||
|
// Controller methods
|
||||||
|
void resetController();
|
||||||
|
void erasePersistentData();
|
||||||
|
void sendDataManagerAvailableResponse();
|
||||||
|
void getVersion();
|
||||||
|
void setExtendedPanId(const quint64 &panId);
|
||||||
|
void setChannelMask(const quint32 &channelMask);
|
||||||
|
void setDeviceType(const NodeType &deviceType);
|
||||||
|
void startNetwork();
|
||||||
|
void startScan();
|
||||||
|
void permitJoining(quint16 targetAddress = 0xfffc, const quint8 advertisingIntervall = 254);
|
||||||
|
void getPermitJoiningStatus();
|
||||||
|
void requestNodeDescription(const quint16 &shortAddress);
|
||||||
|
void requestSimpleNodeDescription(const quint16 &shortAddress, const quint8 &endpoint = 1);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onMessageReceived(const ZigbeeInterfaceMessage &message);
|
||||||
|
|
||||||
|
// 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 onRequestNodeDescriptionFinished();
|
||||||
|
void onRequestSimpleNodeDescriptionFinished();
|
||||||
|
|
||||||
|
// Controler notifications
|
||||||
|
void processLoggingMessage(const ZigbeeInterfaceMessage &message);
|
||||||
|
void processFactoryNewRestart(const ZigbeeInterfaceMessage &message);
|
||||||
|
void processNodeClusterList(const ZigbeeInterfaceMessage &message);
|
||||||
|
void processNodeAttributeList(const ZigbeeInterfaceMessage &message);
|
||||||
|
void processNodeCommandIdList(const ZigbeeInterfaceMessage &message);
|
||||||
|
void processDeviceAnnounce(const ZigbeeInterfaceMessage &message);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ZIGBEEMANAGER_H
|
||||||
31
zigbeenode.cpp
Normal file
31
zigbeenode.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include "zigbeenode.h"
|
||||||
|
|
||||||
|
ZigbeeNode::ZigbeeNode(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 ZigbeeNode::shortAddress() const
|
||||||
|
{
|
||||||
|
return m_shortAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 ZigbeeNode::extendedAddress() const
|
||||||
|
{
|
||||||
|
return m_extendedAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigbeeNode::NodeType ZigbeeNode::nodeType() const
|
||||||
|
{
|
||||||
|
return m_nodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNode::setShortAddress(const quint16 &shortAddress)
|
||||||
|
{
|
||||||
|
m_shortAddress = shortAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeNode::setExtendedAddress(const quint64 &extendedAddress)
|
||||||
|
{
|
||||||
|
m_extendedAddress = extendedAddress;
|
||||||
|
}
|
||||||
56
zigbeenode.h
Normal file
56
zigbeenode.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef ZIGBEENODE_H
|
||||||
|
#define ZIGBEENODE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "zigbee.h"
|
||||||
|
|
||||||
|
class ZigbeeNode : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum NodeType {
|
||||||
|
NodeTypeCoordinator = 0,
|
||||||
|
NodeTypeRouter = 1,
|
||||||
|
NodeTypeEndDevice = 2
|
||||||
|
};
|
||||||
|
Q_ENUM(NodeType)
|
||||||
|
|
||||||
|
enum FrequencyBand {
|
||||||
|
FrequencyBand868Mhz,
|
||||||
|
FrequencyBand902Mhz,
|
||||||
|
FrequencyBand2400Mhz
|
||||||
|
};
|
||||||
|
Q_ENUM(FrequencyBand)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
explicit ZigbeeNode(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
quint16 shortAddress() const;
|
||||||
|
quint64 extendedAddress() const;
|
||||||
|
|
||||||
|
// Information from node descriptor
|
||||||
|
NodeType nodeType() const;
|
||||||
|
FrequencyBand frequencyBand() const;
|
||||||
|
|
||||||
|
bool canBeCoordinator() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint16 m_shortAddress = 0;
|
||||||
|
quint64 m_extendedAddress = 0;
|
||||||
|
NodeType m_nodeType;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setShortAddress(const quint16 &shortAddress);
|
||||||
|
void setExtendedAddress(const quint64 &extendedAddress);
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ZIGBEENODE_H
|
||||||
74
zigbeeutils.cpp
Normal file
74
zigbeeutils.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "zigbeeutils.h"
|
||||||
|
|
||||||
|
#include <QMetaEnum>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
|
QString ZigbeeUtils::convertByteToHexString(const quint8 &byte)
|
||||||
|
{
|
||||||
|
QString hexString;
|
||||||
|
QString byteString = QString::number(byte, 16);
|
||||||
|
if (byteString.count() == 1) {
|
||||||
|
hexString = QString("0x0%1").arg(byteString);
|
||||||
|
} else {
|
||||||
|
hexString = QString("0x%1").arg(byteString);
|
||||||
|
}
|
||||||
|
return hexString.toStdString().data();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeUtils::convertByteArrayToHexString(const QByteArray &byteArray)
|
||||||
|
{
|
||||||
|
QString hexString;
|
||||||
|
for (int i = 0; i < byteArray.count(); i++) {
|
||||||
|
hexString.append(convertByteToHexString((quint8)byteArray.at(i)));
|
||||||
|
if (i != byteArray.count() -1) {
|
||||||
|
hexString.append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hexString.toStdString().data();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeUtils::convertUint16ToHexString(const quint16 &byte)
|
||||||
|
{
|
||||||
|
quint8 msbByte = (byte >> 8) & 0xff;
|
||||||
|
quint8 lsbByte = (byte >> 0) & 0xff;
|
||||||
|
|
||||||
|
return convertByteToHexString(msbByte) + convertByteToHexString(lsbByte).remove("0x");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeUtils::convertUint64ToHexString(const quint64 &byte)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||||
|
stream << byte;
|
||||||
|
return QString("0x%1").arg(convertByteArrayToHexString(data).remove(" ").remove("0x"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeUtils::messageTypeToString(const Zigbee::InterfaceMessageType &type)
|
||||||
|
{
|
||||||
|
QMetaObject metaObject = Zigbee::staticMetaObject;
|
||||||
|
QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("InterfaceMessageType"));
|
||||||
|
|
||||||
|
QString enumString = metaEnum.valueToKey(type);
|
||||||
|
|
||||||
|
return enumString.remove("Zigbee::InterfaceMessageType(MessageType").remove(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeUtils::clusterIdToString(const Zigbee::ClusterId &clusterId)
|
||||||
|
{
|
||||||
|
QMetaObject metaObject = Zigbee::staticMetaObject;
|
||||||
|
QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ClusterId"));
|
||||||
|
|
||||||
|
QString enumString = metaEnum.valueToKey(clusterId);
|
||||||
|
|
||||||
|
return enumString.remove("Zigbee::ClusterId(ClusterId").remove(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ZigbeeUtils::profileIdToString(const Zigbee::ZigbeeProfile &profileId)
|
||||||
|
{
|
||||||
|
QMetaObject metaObject = Zigbee::staticMetaObject;
|
||||||
|
QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("ZigbeeProfile"));
|
||||||
|
|
||||||
|
QString enumString = metaEnum.valueToKey(profileId);
|
||||||
|
|
||||||
|
return enumString.remove("Zigbee::ZigbeeProfile(ZigbeeProfile").remove(")");
|
||||||
|
}
|
||||||
26
zigbeeutils.h
Normal file
26
zigbeeutils.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef ZIGBEEUTILS_H
|
||||||
|
#define ZIGBEEUTILS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "zigbee.h"
|
||||||
|
|
||||||
|
class ZigbeeUtils
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Debug utils
|
||||||
|
static QString convertByteToHexString(const quint8 &byte);
|
||||||
|
static QString convertByteArrayToHexString(const QByteArray &byteArray);
|
||||||
|
static QString convertUint16ToHexString(const quint16 &byte);
|
||||||
|
static QString convertUint64ToHexString(const quint64 &byte);
|
||||||
|
|
||||||
|
// Enum prittify print methods
|
||||||
|
static QString messageTypeToString(const Zigbee::InterfaceMessageType &type);
|
||||||
|
static QString clusterIdToString(const Zigbee::ClusterId &clusterId);
|
||||||
|
static QString profileIdToString(const Zigbee::ZigbeeProfile &profileId);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ZIGBEEUTILS_H
|
||||||
Reference in New Issue
Block a user