diff --git a/core.cpp b/core.cpp index 7376347..478671e 100644 --- a/core.cpp +++ b/core.cpp @@ -4,6 +4,5 @@ Core::Core(QObject *parent) : QObject(parent) { - - + m_manager = new ZigbeeManager("/dev/ttyS0", this); } diff --git a/loggingcategory.cpp b/loggingcategory.cpp new file mode 100644 index 0000000..f7d06f9 --- /dev/null +++ b/loggingcategory.cpp @@ -0,0 +1,5 @@ +#include "loggingcategory.h" + +Q_LOGGING_CATEGORY(dcZigbee, "Zigbee") +Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface") +Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic") diff --git a/loggingcategory.h b/loggingcategory.h new file mode 100644 index 0000000..2594faa --- /dev/null +++ b/loggingcategory.h @@ -0,0 +1,11 @@ +#ifndef LOGGINGCATEGORY_H +#define LOGGINGCATEGORY_H + +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(dcZigbee) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic) + +#endif // LOGGINGCATEGORY_H diff --git a/main.cpp b/main.cpp index 9cc984d..0737d78 100644 --- a/main.cpp +++ b/main.cpp @@ -1,11 +1,70 @@ #include +#include +#include +#include + #include "core.h" +#include "loggingcategory.h" + +static const char *const normal = "\033[0m"; +static const char *const warning = "\e[33m"; +static const char *const error = "\e[31m"; + +static QHash s_loggingFilters; + +static void loggingCategoryFilter(QLoggingCategory *category) +{ + // If this is a known category + if (s_loggingFilters.contains(category->categoryName())) { + category->setEnabled(QtDebugMsg, s_loggingFilters.value(category->categoryName())); + category->setEnabled(QtWarningMsg, true); + category->setEnabled(QtCriticalMsg, true); + category->setEnabled(QtFatalMsg, true); + } else { + //Disable default debug messages, print only >= warnings + category->setEnabled(QtDebugMsg, false); + category->setEnabled(QtWarningMsg, true); + category->setEnabled(QtCriticalMsg, true); + category->setEnabled(QtFatalMsg, true); + } +} + +static void consoleLogHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) +{ + switch (type) { + case QtInfoMsg: + fprintf(stdout, " I | %s: %s\n", context.category, message.toUtf8().data()); + break; + case QtDebugMsg: + fprintf(stdout, " I | %s: %s\n", context.category, message.toUtf8().data()); + break; + case QtWarningMsg: + fprintf(stdout, "%s W | %s: %s%s\n", warning, context.category, message.toUtf8().data(), normal); + break; + case QtCriticalMsg: + fprintf(stdout, "%s C | %s: %s%s\n", error, context.category, message.toUtf8().data(), normal); + break; + case QtFatalMsg: + fprintf(stdout, "%s F | %s: %s%s\n", error, context.category, message.toUtf8().data(), normal); + break; + } + fflush(stdout); +} + int main(int argc, char *argv[]) { - QCoreApplication a(argc, argv); + qInstallMessageHandler(consoleLogHandler); + + QCoreApplication application(argc, argv); + + s_loggingFilters.insert("Zigbee", true); + s_loggingFilters.insert("ZigbeeInterface", true); + s_loggingFilters.insert("ZigbeeInterfaceTraffic", false); + + QLoggingCategory::installFilter(loggingCategoryFilter); Core core; - return a.exec(); + return application.exec(); } diff --git a/zigbee-daemon.pro b/zigbee-daemon.pro index 794f98a..1f8b402 100644 --- a/zigbee-daemon.pro +++ b/zigbee-daemon.pro @@ -13,10 +13,14 @@ SOURCES += main.cpp \ core.cpp \ zigbeeinterface.cpp \ zigbeemanager.cpp \ - zigbee.cpp + zigbee.cpp \ + zigbeeinterfacemessage.cpp \ + loggingcategory.cpp HEADERS += \ core.h \ zigbeeinterface.h \ zigbeemanager.h \ - zigbee.h + zigbee.h \ + zigbeeinterfacemessage.h \ + loggingcategory.h diff --git a/zigbee.cpp b/zigbee.cpp index 98cead9..6e7a411 100644 --- a/zigbee.cpp +++ b/zigbee.cpp @@ -1 +1,33 @@ #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"); +} diff --git a/zigbee.h b/zigbee.h index ac4766c..11946e6 100644 --- a/zigbee.h +++ b/zigbee.h @@ -2,12 +2,201 @@ #define ZIGBEE_H #include +#include +#include class Zigbee { Q_GADGET public: + enum InterfaceMessageType { + /* Common Commands */ + Status = 0x8000, + Logging = 0x8001, + + DataIndication = 0x8002, + + NodeClusterList = 0x8003, + NodeAttributeList = 0x8004, + NodeCommandIdList = 0x8005, + RestartProvisioned = 0x8006, + RestartFactoryNew = 0x8007, + GetVersion = 0x0010, + VersionList = 0x8010, + + SetExtendetPanId = 0x0020, + SetChannelMask = 0x0021, + SetSecurity = 0x0022, + SetDeviceType = 0x0023, + StartNetwork = 0x0024, + StartScan = 0x0025, + NetworkJoinedFormed = 0x8024, + NetworkRemoveDevice = 0x0026, + NetworkWhitelistEnable = 0x0027, + AuthenticateDeviceRequest = 0x0028, + AuthenticateDeviceResponse = 0x8028, + OutOfBandCommisioningDataRequest = 0x0029, + OutOfBandCommisioningDataResponse = 0x8029, + + Reset = 0x0011, + ErasePersistentData = 0x0012, + ZllFactoryNew = 0x0013, + GetPermitJoin = 0x0014, + GetPermitJoinResponse = 0x8014, + Bind = 0x0030, + BindResponse = 0x8030, + Unbind = 0x0031, + UnbindResponse = 0x8031, + + NetworkAdressRequest = 0x0040, + NetworkAdressResponse = 0x8040, + IeeeAddressResponse = 0x0041, + IeeeAddressRequest = 0x8041, + NodeDescriptorRequest = 0x0042, + NodeDescriptorRsponse = 0x8042, + SimpleDescriptorRequest = 0x0043, + SimpleDescriptorResponse = 0x8043, + PowerDescriptorRequest = 0x0044, + PowerDescriptorResponse = 0x8044, + ActiveEndpointRequest = 0x0045, + ActiveEndpointResponse = 0x8045, + MatchDescriptorRequest = 0x0046, + MatchDescriptorResponse = 0x8046, + ManagementLeaveRequest = 0x0047, + ManagementLeaveResponse = 0x8047, + LeaveIndication = 0x8048, + PermitJoiningRequest = 0x0049, + ManagementNetworkUpdateRequest = 0x004A, + ManagementNetworkUpdateResponse = 0x804A, + SystemServerDiscoveryRequest = 0x004B, + SystemServerDiscoveryResponse = 0x804B, + DeviceAnnounce = 0x004D, + ManagementLqiRequest = 0x004E, + ManagementLqiResponse = 0x804E, + + /* Group Cluster */ + AddGroupRequest = 0x0060, + AddGroupResponse = 0x8060, + ViewGroupRequest = 0x0061, + ViewGroupResponse = 0x8061, + GetGroupMembershipRequest = 0x0062, + GetGroupMembershipResponse = 0x8062, + RemoveGroupRequest = 0x0063, + RemoveGroupResponse = 0x8063, + RemoveAllGroups = 0x0064, + GroupIfIdentify = 0x0065, + + /* Identify Cluster */ + IdentifySend = 0x0070, + IdentifyQuery = 0x0071, + + /* Level Cluster */ + MoveToLevel = 0x0080, + MoveToLevelOnOff = 0x0081, + MoveStep = 0x0082, + MoveStopMove = 0x0083, + MoveStopMoveOnOff = 0x0084, + + /* Scenes Cluster */ + ViewScene = 0x00A0, + ViewSceneResponse = 0x80A0, + AddScene = 0x00A1, + AddSceneResponse = 0x80A1, + RemoveScene = 0x00A2, + RemoveSceneResponse = 0x80A2, + RemoveAllScenes = 0x00A3, + RemoveAllScenesResponse = 0x80A3, + StoreScene = 0x00A4, + StoreSceneResponse = 0x80A4, + RecallScene = 0x00A5, + SceneMembershipRequest = 0x00A6, + SceneMembershipResponse = 0x80A6, + + /* Colour Cluster */ + MoveToHue = 0x00B0, + MoveHue = 0x00B1, + StepHue = 0x00B2, + MoveToSaturation = 0x00B3, + MoveSaturation = 0x00B4, + StepStaturation = 0x00B5, + MoveToHueSaturation = 0x00B6, + MoveToColor = 0x00B7, + MoveColor = 0x00B8, + StepColor = 0x00B9, + + /* ZLL Commands */ + /* Touchlink */ + InitiateTouchlink = 0x00D0, + TouchlinkStatus = 0x00D1, + TouchlinkFactoryReset = 0x00D2, + + /* Identify Cluster */ + IdentifyTriggerEffect = 0x00E0, + + /* On/Off Cluster */ + CluserOnOff = 0x0092, + CluserOnOffTimed = 0x0093, + CluserOnOffEffects = 0x0094, + CluserOnOffUpdate = 0x8095, + + /* Scenes Cluster */ + AddEnhancedScene = 0x00A7, + ViewEnhancedScene = 0x00A8, + CopyScene = 0x00A9, + + /* Colour Cluster */ + EnhancedMoveToHue = 0x00BA, + EnhancedMoveHue = 0x00BB, + EnhancedStepHue = 0x00BC, + EnhancedMoveToHueSaturation = 0x00BD, + ColourLoopSet = 0x00BE, + StopMoveStep = 0x00BF, + MoveToColorTemperature = 0x00C0, + MoveColorTemperature = 0x00C1, + StepColorTemperature = 0x00C2, + + /* ZHA Commands */ + /* Door Lock Cluster */ + LockUnlockDoor = 0x00F0, + + /* Attributes */ + ReadAttributeRequest = 0x0100, + ReadAttributeResponse = 0x8100, + DefaultResponse = 0x8101, + AttributeReport = 0x8102, + WriteAttributeRequest = 0x0110, + WriteAttributeResponse = 0x8110, + ConfigReportingRequest = 0x0120, + ConfigReportingResponse = 0x8120, + ReportAttributes = 0x8121, + AttributeDiscoveryRequest = 0x0140, + AttributeDiscoveryResponse = 0x8140, + + /* Persistant data manager messages */ + DataManagerAvailableRequest = 0x0300, + DataManagerAvailableResponse = 0x8300, + DataManagerSaveRecordRequest = 0x0200, + DataManagerSaveRecordResponse = 0x8200, + DataManagerLoadRecordRequest = 0x0201, + DataManagerLoadRecordResponse = 0x8201, + DataManagerDeleteAllRecordsRequest = 0x0202, + DataManagerDeleteAllRecordsResponse = 0x8202, + + /* Appliance Statistics Cluster 0x0B03 */ + // http://www.nxp.com/documents/user_manual/JN-UG-3076.pdf + StatisticsClusterLogMessage = 0x0301, // Was 0x0500, was 0x0301 + StatisticsClusterLogMessageResponse = 0x8301, + + /* IAS Cluster */ + SendIasZoneEnroolResponse = 0x0400, + IasZoneStatusChangeNotify = 0x8401, + }; + Q_ENUM(InterfaceMessageType) + + static QString convertByteToHexString(const quint8 &byte); + static QString convertByteArrayToHexString(const QByteArray &byteArray); + static QString convertByte16ToHexString(const quint16 &byte); }; diff --git a/zigbeeinterface.cpp b/zigbeeinterface.cpp index 0969ed1..037e5e2 100644 --- a/zigbeeinterface.cpp +++ b/zigbeeinterface.cpp @@ -1,6 +1,5 @@ #include "zigbeeinterface.h" - -#include +#include "loggingcategory.h" ZigbeeInterface::ZigbeeInterface(QObject *parent) : QObject(parent), @@ -15,44 +14,12 @@ bool ZigbeeInterface::available() const return m_serialPort->isOpen(); } -QString ZigbeeInterface::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 ZigbeeInterface::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 ZigbeeInterface::convertByte16ToHexString(const quint16 &byte) -{ - quint8 msbByte = (byte >> 8) & 0xff; - quint8 lsbByte = (byte >> 0) & 0xff; - - return convertByteToHexString(msbByte) + convertByteToHexString(lsbByte).remove("0x"); -} - -quint8 ZigbeeInterface::calculateCrc(const quint16 &commandValue, const quint16 &lenghtValue, const QByteArray &data) +quint8 ZigbeeInterface::calculateCrc(const quint16 &messageTypeValue, const quint16 &lenghtValue, const QByteArray &data) { quint8 crc = 0; - crc ^= (commandValue >> 8) & 0xff; - crc ^= (commandValue >> 0) & 0xff; + crc ^= (messageTypeValue >> 8) & 0xff; + crc ^= (messageTypeValue >> 0) & 0xff; crc ^= (lenghtValue >> 8) & 0xff; crc ^= (lenghtValue >> 0) & 0xff; @@ -68,16 +35,16 @@ void ZigbeeInterface::streamByte(quint8 byte, bool specialCharacter) { if (!specialCharacter && byte < 0x10) { // Byte stuffing ESC char before stuffed data byte - qDebug() << "[out]" << convertByteToHexString(0x02); + qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << Zigbee::convertByteToHexString(0x02); if (m_serialPort->write(QByteArray::fromRawData("\x02", 1)) < 0) { - qWarning() << "Could not stream ESC byte" << convertByteArrayToHexString(QByteArray::fromRawData("\x02", 1)); + qCWarning(dcZigbeeInterface()) << "Could not stream ESC byte" << Zigbee::convertByteArrayToHexString(QByteArray::fromRawData("\x02", 1)); } byte ^= 0x10; } - qDebug() << "[out]" << convertByteToHexString(byte); + qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << Zigbee::convertByteToHexString(byte); if (m_serialPort->write(QByteArray(1, (char)byte)) < 0) { - qWarning() << "Could not stream byte" << convertByteToHexString(byte); + qCWarning(dcZigbeeInterface()) << "Could not stream byte" << Zigbee::convertByteToHexString(byte); } m_serialPort->flush(); } @@ -88,7 +55,7 @@ void ZigbeeInterface::setReadingState(const ZigbeeInterface::ReadingState &state return; m_readingState = state; - qDebug() << m_readingState; + qCDebug(dcZigbeeInterfaceTraffic()) << m_readingState; } void ZigbeeInterface::onReadyRead() @@ -99,13 +66,12 @@ void ZigbeeInterface::onReadyRead() for (int i = 0; i < data.length(); i++) { quint8 byte = static_cast(data.at(i)); - qDebug() << "[ in]" << convertByteToHexString(byte); + qCDebug(dcZigbeeInterfaceTraffic()) << "[ in]" << Zigbee::convertByteToHexString(byte); switch (byte) { case 0x01: - //qDebug() << "START message received"; m_crcValue = 0; - m_commandValue = 0; + m_messageTypeValue = 0; m_lengthValue = 0; m_escapeDetected = false; m_data.clear(); @@ -113,18 +79,19 @@ void ZigbeeInterface::onReadyRead() setReadingState(WaitForTypeMsb); break; case 0x02: - //qDebug() << "ESC char received"; m_escapeDetected = true; break; case 0x03: { - quint8 crc = calculateCrc(m_commandValue, m_lengthValue, m_data); + Zigbee::InterfaceMessageType messageType = static_cast(m_messageTypeValue); + quint8 crc = calculateCrc(m_messageTypeValue, m_lengthValue, m_data); if (crc != m_crcValue) { - qWarning() << "Invalid CRC value" << crc << "!=" << m_crcValue; + qCWarning(dcZigbeeInterface()) << "Invalid CRC value" << crc << "!=" << m_crcValue; } else if (m_data.count() != m_lengthValue) { - qWarning() << "ERROR: Invalid data length" << m_data.count() << "!=" << m_lengthValue; + qCWarning(dcZigbeeInterface()) << "ERROR:s Invalid data length" << m_data.count() << "!=" << m_lengthValue; } else { - qDebug() << "<--" << (Type)m_commandValue << convertByte16ToHexString(m_commandValue) << "CRC:" << convertByteToHexString(m_crcValue) << convertByte16ToHexString(m_lengthValue) << convertByteArrayToHexString(m_data); - emit messageReceived((Type)m_commandValue, m_data); + ZigbeeInterfaceMessage message(messageType, m_data); + qCDebug(dcZigbeeInterface()) << "<--" << message; + emit messageReceived(message); } setReadingState(WaitForStart); break; @@ -137,17 +104,17 @@ void ZigbeeInterface::onReadyRead() m_escapeDetected = false; } + // Read data bytes depending on the reading state switch (m_readingState) { case WaitForStart: break; case WaitForTypeMsb: - m_commandValue = byte; - m_commandValue <<= 8; + m_messageTypeValue = byte; + m_messageTypeValue <<= 8; setReadingState(WaitForTypeLsb); break; case WaitForTypeLsb: - m_commandValue |= byte; - //qDebug() << "Command:" << convertByte16ToHexString(m_commandValue) << (Type)m_commandValue; + m_messageTypeValue |= byte; setReadingState(WaitForLenghtMsb); break; case WaitForLenghtMsb: @@ -177,7 +144,7 @@ void ZigbeeInterface::onReadyRead() void ZigbeeInterface::onError(const QSerialPort::SerialPortError &error) { - qWarning() << "Serial port error:" << error << m_serialPort->errorString(); + qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString(); } bool ZigbeeInterface::enable(const QString &serialPort) @@ -197,13 +164,13 @@ bool ZigbeeInterface::enable(const QString &serialPort) connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError))); if (!m_serialPort->open(QSerialPort::ReadWrite)) { - qWarning() << "Could not open serial port" << serialPort; + qCWarning(dcZigbeeInterface()) << "Could not open serial port" << serialPort; delete m_serialPort; m_serialPort = nullptr; return false; } - qDebug() << "Interface enabled successfully on" << serialPort; + qCDebug(dcZigbeeInterface()) << "Interface enabled successfully on" << serialPort; return true; } @@ -217,26 +184,27 @@ void ZigbeeInterface::disable() delete m_serialPort; m_serialPort = nullptr; - qDebug() << "Interface disabled"; + qCDebug(dcZigbeeInterface()) << "Interface disabled"; } -void ZigbeeInterface::sendCommand(const ZigbeeInterface::Type &commandType, const QByteArray &data) +void ZigbeeInterface::sendMessage(const ZigbeeInterfaceMessage &message) { - quint16 commandValue = static_cast(commandType); - quint16 lengthValue = static_cast(data.count()); - quint8 crcValue = calculateCrc(commandValue, lengthValue, data); + quint16 messageTypeValue = static_cast(message.messageType()); + quint16 lengthValue = static_cast(message.data().count()); - qDebug() << "-->" << commandType << convertByte16ToHexString(commandValue) << "CRC:" << convertByteToHexString(crcValue) << convertByte16ToHexString(lengthValue) << convertByteArrayToHexString(data); + quint8 crcValue = calculateCrc(messageTypeValue, lengthValue, message.data()); + + qCDebug(dcZigbeeInterface()) << "-->" << message << "crc:" << Zigbee::convertByteToHexString(crcValue) << ", length:" << Zigbee::convertByte16ToHexString(lengthValue); streamByte(0x01, true); - streamByte((commandValue >> 8) & 0xff); - streamByte((commandValue >> 0) & 0xff); + streamByte((messageTypeValue >> 8) & 0xff); + streamByte((messageTypeValue >> 0) & 0xff); streamByte((lengthValue >> 8) & 0xff); streamByte((lengthValue >> 0) & 0xff); streamByte(crcValue); - for (int i = 0; i < data.count(); i++) { - streamByte(data.at(i)); + for (int i = 0; i < message.data().count(); i++) { + streamByte(message.data().at(i)); } streamByte(0x03, true); } diff --git a/zigbeeinterface.h b/zigbeeinterface.h index 4ddc8b0..2a08c6f 100644 --- a/zigbeeinterface.h +++ b/zigbeeinterface.h @@ -4,6 +4,9 @@ #include #include +#include "zigbee.h" +#include "zigbeeinterfacemessage.h" + class ZigbeeInterface : public QObject { Q_OBJECT @@ -19,190 +22,6 @@ public: }; Q_ENUM(ReadingState) - enum Type { - /* Common Commands */ - Status = 0x8000, - Logging = 0x8001, - - DataIndication = 0x8002, - - NodeClusterList = 0x8003, - NodeAttributeList = 0x8004, - NodeCommandIdList = 0x8005, - RestartProvisioned = 0x8006, - RestartFactoryNew = 0x8007, - GetVersion = 0x0010, - VersionList = 0x8010, - - SetExtendetPanId = 0x0020, - SetChannelMask = 0x0021, - SetSecurity = 0x0022, - SetDeviceType = 0x0023, - StartNetwork = 0x0024, - StartScan = 0x0025, - NetworkJoinedFormed = 0x8024, - NetworkRemoveDevice = 0x0026, - NetworkWhitelistEnable = 0x0027, - AuthenticateDeviceRequest = 0x0028, - AuthenticateDeviceResponse = 0x8028, - OutOfBandCommisioningDataRequest = 0x0029, - OutOfBandCommisioningDataResponse = 0x8029, - - Reset = 0x0011, - ErasePersistentData = 0x0012, - ZllFactoryNew = 0x0013, - GetPermitJoin = 0x0014, - GetPermitJoinResponse = 0x8014, - Bind = 0x0030, - BindResponse = 0x8030, - Unbind = 0x0031, - UnbindResponse = 0x8031, - - NetworkAdressRequest = 0x0040, - NetworkAdressResponse = 0x8040, - IeeeAddressResponse = 0x0041, - IeeeAddressRequest = 0x8041, - NodeDescriptorRequest = 0x0042, - NodeDescriptorRsponse = 0x8042, - SimpleDescriptorRequest = 0x0043, - SimpleDescriptorResponse = 0x8043, - PowerDescriptorRequest = 0x0044, - PowerDescriptorResponse = 0x8044, - ActiveEndpointRequest = 0x0045, - ActiveEndpointResponse = 0x8045, - MatchDescriptorRequest = 0x0046, - MatchDescriptorResponse = 0x8046, - ManagementLeaveRequest = 0x0047, - ManagementLeaveResponse = 0x8047, - LeaveIndication = 0x8048, - PermitJoiningRequest = 0x0049, - ManagementNetworkUpdateRequest = 0x004A, - ManagementNetworkUpdateResponse = 0x804A, - SystemServerDiscoveryRequest = 0x004B, - SystemServerDiscoveryResponse = 0x804B, - DeviceAnnounce = 0x004D, - ManagementLqiRequest = 0x004E, - ManagementLqiResponse = 0x804E, - - /* Group Cluster */ - AddGroupRequest = 0x0060, - AddGroupResponse = 0x8060, - ViewGroupRequest = 0x0061, - ViewGroupResponse = 0x8061, - GetGroupMembershipRequest = 0x0062, - GetGroupMembershipResponse = 0x8062, - RemoveGroupRequest = 0x0063, - RemoveGroupResponse = 0x8063, - RemoveAllGroups = 0x0064, - GroupIfIdentify = 0x0065, - - /* Identify Cluster */ - IdentifySend = 0x0070, - IdentifyQuery = 0x0071, - - /* Level Cluster */ - MoveToLevel = 0x0080, - MoveToLevelOnOff = 0x0081, - MoveStep = 0x0082, - MoveStopMove = 0x0083, - MoveStopMoveOnOff = 0x0084, - - /* Scenes Cluster */ - ViewScene = 0x00A0, - ViewSceneResponse = 0x80A0, - AddScene = 0x00A1, - AddSceneResponse = 0x80A1, - RemoveScene = 0x00A2, - RemoveSceneResponse = 0x80A2, - RemoveAllScenes = 0x00A3, - RemoveAllScenesResponse = 0x80A3, - StoreScene = 0x00A4, - StoreSceneResponse = 0x80A4, - RecallScene = 0x00A5, - SceneMembershipRequest = 0x00A6, - SceneMembershipResponse = 0x80A6, - - /* Colour Cluster */ - MoveToHue = 0x00B0, - MoveHue = 0x00B1, - StepHue = 0x00B2, - MoveToSaturation = 0x00B3, - MoveSaturation = 0x00B4, - StepStaturation = 0x00B5, - MoveToHueSaturation = 0x00B6, - MoveToColor = 0x00B7, - MoveColor = 0x00B8, - StepColor = 0x00B9, - - /* ZLL Commands */ - /* Touchlink */ - InitiateTouchlink = 0x00D0, - TouchlinkStatus = 0x00D1, - TouchlinkFactoryReset = 0x00D2, - - /* Identify Cluster */ - IdentifyTriggerEffect = 0x00E0, - - /* On/Off Cluster */ - CluserOnOff = 0x0092, - CluserOnOffTimed = 0x0093, - CluserOnOffEffects = 0x0094, - CluserOnOffUpdate = 0x8095, - - /* Scenes Cluster */ - AddEnhancedScene = 0x00A7, - ViewEnhancedScene = 0x00A8, - CopyScene = 0x00A9, - - /* Colour Cluster */ - EnhancedMoveToHue = 0x00BA, - EnhancedMoveHue = 0x00BB, - EnhancedStepHue = 0x00BC, - EnhancedMoveToHueSaturation = 0x00BD, - ColourLoopSet = 0x00BE, - StopMoveStep = 0x00BF, - MoveToColorTemperature = 0x00C0, - MoveColorTemperature = 0x00C1, - StepColorTemperature = 0x00C2, - - /* ZHA Commands */ - /* Door Lock Cluster */ - LockUnlockDoor = 0x00F0, - - /* Attributes */ - ReadAttributeRequest = 0x0100, - ReadAttributeResponse = 0x8100, - DefaultResponse = 0x8101, - AttributeReport = 0x8102, - WriteAttributeRequest = 0x0110, - WriteAttributeResponse = 0x8110, - ConfigReportingRequest = 0x0120, - ConfigReportingResponse = 0x8120, - ReportAttributes = 0x8121, - AttributeDiscoveryRequest = 0x0140, - AttributeDiscoveryResponse = 0x8140, - - /* Persistant data manager messages */ - DataManagerAvailableRequest = 0x0300, - DataManagerAvailableResponse = 0x8300, - DataManagerSaveRecordRequest = 0x0200, - DataManagerSaveRecordResponse = 0x8200, - DataManagerLoadRecordRequest = 0x0201, - DataManagerLoadRecordResponse = 0x8201, - DataManagerDeleteAllRecordsRequest = 0x0202, - DataManagerDeleteAllRecordsResponse = 0x8202, - - /* Appliance Statistics Cluster 0x0B03 */ - // http://www.nxp.com/documents/user_manual/JN-UG-3076.pdf - StatisticsClusterLogMessage = 0x0301, // Was 0x0500, was 0x0301 - StatisticsClusterLogMessageResponse = 0x8301, - - /* IAS Cluster */ - SendIasZoneEnroolResponse = 0x0400, - IasZoneStatusChangeNotify = 0x8401, - }; - Q_ENUM(Type) - explicit ZigbeeInterface(QObject *parent = nullptr); bool available() const; @@ -215,16 +34,12 @@ private: ReadingState m_readingState; quint8 m_crcValue; quint8 m_currentValue; - quint16 m_commandValue; + quint16 m_messageTypeValue; quint16 m_lengthValue; QByteArray m_data; bool m_escapeDetected; - QString convertByteToHexString(const quint8 &byte); - QString convertByteArrayToHexString(const QByteArray &byteArray); - QString convertByte16ToHexString(const quint16 &byte); - - quint8 calculateCrc(const quint16 &commandValue, const quint16 &lenghtValue, const QByteArray &data); + quint8 calculateCrc(const quint16 &messageTypeValue, const quint16 &lenghtValue, const QByteArray &data); void streamByte(quint8 byte, bool specialCharacter = false); @@ -232,7 +47,7 @@ private: signals: void availableChanged(const bool &available); - void messageReceived(const Type &commandType, const QByteArray &data = QByteArray()); + void messageReceived(const ZigbeeInterfaceMessage &message); private slots: void onReadyRead(); @@ -242,7 +57,7 @@ public slots: bool enable(const QString &serialPort = "/dev/ttyS0"); void disable(); - void sendCommand(const Type &commandType, const QByteArray &data = QByteArray()); + void sendMessage(const ZigbeeInterfaceMessage &message); }; diff --git a/zigbeeinterfacemessage.cpp b/zigbeeinterfacemessage.cpp new file mode 100644 index 0000000..b34a59d --- /dev/null +++ b/zigbeeinterfacemessage.cpp @@ -0,0 +1,39 @@ +#include "zigbeeinterfacemessage.h" + +ZigbeeInterfaceMessage::ZigbeeInterfaceMessage() +{ + +} + +ZigbeeInterfaceMessage::ZigbeeInterfaceMessage(const Zigbee::InterfaceMessageType &messageType, const QByteArray &data): + m_messageType(messageType), + m_data(data) +{ + +} + +Zigbee::InterfaceMessageType ZigbeeInterfaceMessage::messageType() const +{ + return m_messageType; +} + +void ZigbeeInterfaceMessage::setMessageType(const Zigbee::InterfaceMessageType &messageType) +{ + m_messageType = messageType; +} + +QByteArray ZigbeeInterfaceMessage::data() const +{ + return m_data; +} + +void ZigbeeInterfaceMessage::setData(const QByteArray &data) +{ + m_data = data; +} + +QDebug operator<<(QDebug dbg, const ZigbeeInterfaceMessage &message) +{ + dbg.nospace().noquote() << "InterfaceMessage(" << message.messageType() << Zigbee::convertByteArrayToHexString(message.data()) << ")"; + return dbg.space(); +} diff --git a/zigbeeinterfacemessage.h b/zigbeeinterfacemessage.h new file mode 100644 index 0000000..030ed77 --- /dev/null +++ b/zigbeeinterfacemessage.h @@ -0,0 +1,29 @@ +#ifndef ZIGBEEINTERFACEMESSAGE_H +#define ZIGBEEINTERFACEMESSAGE_H + +#include +#include + +#include "zigbee.h" + +class ZigbeeInterfaceMessage +{ +public: + ZigbeeInterfaceMessage(); + ZigbeeInterfaceMessage(const Zigbee::InterfaceMessageType &messageType, const QByteArray &data = QByteArray()); + + Zigbee::InterfaceMessageType messageType() const; + void setMessageType(const Zigbee::InterfaceMessageType &messageType); + + QByteArray data() const; + void setData(const QByteArray &data); + +private: + Zigbee::InterfaceMessageType m_messageType; + QByteArray m_data; + +}; + +QDebug operator<<(QDebug dbg, const ZigbeeInterfaceMessage &message); + +#endif // ZIGBEEINTERFACEMESSAGE_H diff --git a/zigbeemanager.cpp b/zigbeemanager.cpp index 33f9822..d05f98c 100644 --- a/zigbeemanager.cpp +++ b/zigbeemanager.cpp @@ -1,4 +1,5 @@ #include "zigbeemanager.h" +#include "loggingcategory.h" ZigbeeManager::ZigbeeManager(const QString &serialPort, QObject *parent) : QObject(parent), @@ -6,9 +7,16 @@ ZigbeeManager::ZigbeeManager(const QString &serialPort, QObject *parent) : { 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(); - m_interface->enable(m_serialPort); - m_interface->sendCommand(ZigbeeInterface::DataManagerAvailableResponse, QByteArray::fromRawData("\x00\x00", 2)); } QString ZigbeeManager::serialPort() const @@ -25,3 +33,17 @@ void ZigbeeManager::setSerialPort(const QString &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; +} diff --git a/zigbeemanager.h b/zigbeemanager.h index 7039bad..1c70885 100644 --- a/zigbeemanager.h +++ b/zigbeemanager.h @@ -3,7 +3,9 @@ #include +#include "zigbee.h" #include "zigbeeinterface.h" +#include "zigbeeinterfacemessage.h" class ZigbeeManager : public QObject { @@ -18,8 +20,14 @@ private: ZigbeeInterface *m_interface; QString m_serialPort; + // Controller methods + void initController(); + signals: +private slots: + void onMessageReceived(const ZigbeeInterfaceMessage &message); + public slots: };