Merge PR #33: Add support for TI z-Stack based adapters
commit
ea2e1cbf0a
24
README.md
24
README.md
|
|
@ -3,19 +3,37 @@
|
|||
|
||||
This repository contains the nymea-zigbee library and tools.
|
||||
|
||||
# Supported hardware
|
||||
nymea-zigbee is a general purpose ZigBee coordinator library to build ZigBee coordinators/gateways.
|
||||
The provided zigbee-cli is a minimal ZigBee coordinator implementation which allows to host a ZigBee
|
||||
network for devices to join and interact with each other but without interacting with the devices.
|
||||
|
||||
Depending on your available hardware following gateway modules are supported
|
||||
For a full fetaured ZigBee coordinator/gateway implementation based on this library, please see
|
||||
https://github.com/nymea/nymea.
|
||||
|
||||
|
||||
# Supported ZigBee adapters
|
||||
|
||||
## TI z-Stack
|
||||
|
||||
All USB and serial port adapters based on the Texas Instruments CC1352/CC2652
|
||||
chipset are supported, provided they are flashed with the z-Stack coordinator firmware.
|
||||
|
||||
Pre-built binaries of the firmware are provided by Koenkk:
|
||||
https://github.com/Koenkk/Z-Stack-firmware/tree/master/coordinator
|
||||
|
||||
## NXP
|
||||
|
||||
> Note: the firmware erquires an entire rework and implement the APS layer
|
||||
The following NXP chip based adapters are supported, provided they are flashed with
|
||||
the nymea coordinator firmware found in this repository.
|
||||
|
||||
* JN5168 (SoM)
|
||||
* JN5169 (USB Stick)
|
||||
|
||||
## deCONZ
|
||||
|
||||
All deCONZ based adapters are supported, with the standard firmware preinstalled.
|
||||
It is recommended to update to the latest firmware.
|
||||
|
||||
* ConBee
|
||||
* RaspBee
|
||||
* ConBee II
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ Build-Depends: debhelper (>= 9.0.0),
|
|||
qtbase5-dev-tools,
|
||||
libqt5sql5-sqlite,
|
||||
libqt5serialport5-dev,
|
||||
libudev-dev
|
||||
libudev-dev,
|
||||
libqca-qt5-2-dev,
|
||||
|
||||
Package: libnymea-zigbee1
|
||||
Section: libs
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,584 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef TI_H
|
||||
#define TI_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#define MT_RPC_DATA_MAX 250
|
||||
|
||||
class Ti
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
enum ZnpVersion {
|
||||
zStack12 = 0x00,
|
||||
zStack3x0 = 0x01,
|
||||
zStack30x = 0x02
|
||||
};
|
||||
Q_ENUM(ZnpVersion)
|
||||
|
||||
enum ResetType {
|
||||
ResetTypeHard = 0x00,
|
||||
ResetTypeSoft = 0x01
|
||||
};
|
||||
Q_ENUM(ResetType)
|
||||
|
||||
enum ResetReason {
|
||||
ResetReasonPowerUp = 0x00,
|
||||
ResetReasonExternal = 0x01,
|
||||
ResetReasonWatchDog = 0x02
|
||||
};
|
||||
Q_ENUM(ResetReason)
|
||||
|
||||
enum StartupMode {
|
||||
StartupModeNormal = 0x00,
|
||||
StartupModeClean = 0x03
|
||||
};
|
||||
Q_ENUM(StartupMode)
|
||||
|
||||
enum DeviceLogicalType {
|
||||
DeviceLogicalTypeCoordinator = 0x00,
|
||||
DeviceLogicalTypeRouter = 0x01,
|
||||
DeviceLogicalTypeEndDevice = 0x02,
|
||||
DeviceLogicalTypeComplexDescriptorAvailable = 0x04,
|
||||
DeviceLogicalTypeUserDescriptorAvailable = 0x08,
|
||||
DeviceLogicalTypeReserved1 = 0x10,
|
||||
DeviceLogicalTypeReserved2 = 0x20,
|
||||
DeviceLogicalTypeReserved3 = 0x40,
|
||||
DeviceLogicalTypeReserved4 = 0x80,
|
||||
};
|
||||
Q_ENUM(DeviceLogicalType)
|
||||
|
||||
enum ControllerCapability {
|
||||
ControllerCapabilityNone = 0x0000,
|
||||
ControllerCapabilitySys = 0x0001,
|
||||
ControllerCapabilityMAC = 0x0002,
|
||||
ControllerCapabilityNWK = 0x0004,
|
||||
ControllerCapabilityAF = 0x0008,
|
||||
ControllerCapabilityZDO = 0x0010,
|
||||
ControllerCapabilitySAPI = 0x0020,
|
||||
ControllerCapabilityUtil = 0x0040,
|
||||
ControllerCapabilityDebug = 0x0080,
|
||||
ControllerCapabilityApp = 0x0100,
|
||||
ControllerCapabilityZOAD = 0x1000
|
||||
};
|
||||
Q_DECLARE_FLAGS(ControllerCapabilities, ControllerCapability)
|
||||
Q_FLAG(ControllerCapabilities)
|
||||
|
||||
enum StatusCode {
|
||||
StatusCodeSuccess = 0x00,
|
||||
StatusCodeFailure = 0x01,
|
||||
StatusCodeBusy = 0x02,
|
||||
StatusCodeTimeout = 0x03,
|
||||
StatusCodeUnsupported = 0x04,
|
||||
StatusCodeError = 0x05,
|
||||
StatusCodeNoNetwork = 0x06,
|
||||
StatusCodeInvalidValue = 0x07
|
||||
};
|
||||
Q_ENUM(StatusCode)
|
||||
|
||||
enum CommandType {
|
||||
CommandTypePoll = 0x00,
|
||||
CommandTypeSReq = 0x20,
|
||||
CommandTypeAReq = 0x40,
|
||||
CommandTypeSRsp = 0x60,
|
||||
};
|
||||
Q_ENUM(CommandType)
|
||||
|
||||
enum SubSystem {
|
||||
SubSystemReserved = 0x00,
|
||||
SubSystemSys = 0x01,
|
||||
SubSystemMAC = 0x02,
|
||||
SubSystemNwk = 0x03,
|
||||
SubSystemAF = 0x04,
|
||||
SubSystemZDO = 0x05,
|
||||
SubSystemSAPI = 0x06,
|
||||
SubSystemUtil = 0x07,
|
||||
SubSystemDebug = 0x08,
|
||||
SubSystemApp = 0x09,
|
||||
SubSystemAppCnf = 0x0F,
|
||||
SubSystemGreenPower = 0x15,
|
||||
};
|
||||
Q_ENUM(SubSystem)
|
||||
|
||||
enum SYSCommand {
|
||||
SYSCommandResetReq = 0x00,
|
||||
SYSCommandPing = 0x01,
|
||||
SYSCommandVersion = 0x02,
|
||||
SYSCommandSetExtAddress = 0x03,
|
||||
SYSCommandGetExtAddress = 0x04,
|
||||
SYSCommandRamRead = 0x05,
|
||||
SYSCommandRamWrite = 0x06,
|
||||
SYSCommandOsalNvItemInit = 0x07,
|
||||
SYSCommandOsalNvRead = 0x08,
|
||||
SYSCommandOsaNvWrite = 0x09,
|
||||
SYSCommandOsalStartTimer = 0x0A,
|
||||
SYSCommandOsalStopTimer = 0x0B,
|
||||
SYSCommandOsalRandom = 0x0C,
|
||||
SYSCommandAdcRead = 0x0D,
|
||||
SYSCommandGpio = 0x0E,
|
||||
SYSCommandStackTune = 0x0F,
|
||||
SYSCommandSetTime = 0x10,
|
||||
SYSCommandGetTime = 0x11,
|
||||
SYSCommandOsalNvDelete = 0x12,
|
||||
SYSCommandOsalNvLength = 0x13,
|
||||
SYSCommandSetTxPower = 0x14,
|
||||
SYSCommandJammerParameters = 0x15,
|
||||
SYSCommandSnifferParameters = 016,
|
||||
SYSCommandZdiagsInitStats = 0x17,
|
||||
SYSCommandZdiagsClearStats = 0x18,
|
||||
SYSCommandZdiagsGetStats = 0x19,
|
||||
SYSCommandZdiagsRestoreStatsNv = 0x1A,
|
||||
SYSCommandZdiagsSaveStatsToNv = 0x1B,
|
||||
SYSCommandOsalNvReadExt = 0x1C,
|
||||
SYSCommandOsalNvWriteExt = 0x01D,
|
||||
|
||||
SYSCommandNvCreate = 0x30,
|
||||
SYSCommandNvDelete = 0x31,
|
||||
SYSCommandNvLength = 0x32,
|
||||
SYSCommandNvRead = 0x33,
|
||||
SYSCommandNvWrite = 0x34,
|
||||
SYSCommandNvUpdate = 0x35,
|
||||
SYSCommandNvCompact = 0x36,
|
||||
|
||||
SYSCommandResetInd = 0x80,
|
||||
SYSCommandOsalTimerExpired = 0x81,
|
||||
SYSCommandJammerInd = 0x82
|
||||
};
|
||||
Q_ENUM(SYSCommand)
|
||||
|
||||
enum MACCommand {
|
||||
MACCommandResetReq = 0x01,
|
||||
MACCommandInit = 0x02,
|
||||
MACCommandStartReq = 0x03,
|
||||
MACCommandSyncReq = 0x04,
|
||||
MACCommandDataReq = 0x05,
|
||||
MACCommandAssociateReq = 0x06,
|
||||
MACCommandDisassociateReq = 0x07,
|
||||
MACCommandGetReq = 0x08,
|
||||
MACCommandSetReq = 0x09,
|
||||
|
||||
MACCommandScanReq = 0x0C,
|
||||
MACCommandPollReq = 0x0D,
|
||||
MACCommandPurgeReq = 0x0E,
|
||||
MACCommandSetRxGainReq = 0x0F,
|
||||
|
||||
MACCommandSecurityGetReq = 0x30,
|
||||
MACCommandSecuritySetReq = 0x31,
|
||||
|
||||
MACCommandAssociateRsp = 0x50,
|
||||
MACCommandOrphanRsp = 0x51,
|
||||
|
||||
MACCommandSyncLossInd = 0x80,
|
||||
MACCommandAssociateInd = 0x81,
|
||||
MACCommandAssociateCnf = 0x82,
|
||||
MACCommandBeaconNotifyInd = 0x83,
|
||||
MACCommandDataCnf = 0x84,
|
||||
MACCommandDataInd = 0x85,
|
||||
MACCommandDisassociateInd = 0x86,
|
||||
MACCommandDisassociateCnf = 0x87,
|
||||
|
||||
MACCommandOrphanInd = 0x8A,
|
||||
MACCommandPollCnf = 0x8B,
|
||||
MACCommandScanCnf = 0x8C,
|
||||
MACCommandCommStatusInd = 0x8D,
|
||||
MACCommandStartCnf = 0x8E,
|
||||
MACCommandRxEnableCnf = 0x8F,
|
||||
MACCommandPurgeCnf = 0x90
|
||||
};
|
||||
Q_ENUM(MACCommand)
|
||||
|
||||
enum AFCommand {
|
||||
AFCommandRegister = 0x00,
|
||||
AFCommandDataRequest = 0x01,
|
||||
AFCommandDataRequestExt = 0x02,
|
||||
AFCommandDataRequestSrcRtg = 0x03,
|
||||
AFCommandDelete = 0x04,
|
||||
|
||||
AFCommandInterPanCtl = 0x10,
|
||||
AFCommandDataStore = 0x11,
|
||||
AFCommandDataRetrieve = 0x12,
|
||||
AFCommandApsfConfigSet = 0x13,
|
||||
AFCommandApsfConfigGet = 0x14,
|
||||
|
||||
AFCommandDataConfirm = 0x80,
|
||||
AFCommandIncomingMsg = 0x81,
|
||||
AFCommandIncomingMsgExt = 0x82,
|
||||
AFCommandReflectError = 0x83,
|
||||
};
|
||||
Q_ENUM(AFCommand)
|
||||
|
||||
enum ZDOCommand {
|
||||
ZDOCommandNwwAddrReq = 0x00,
|
||||
ZDOCommandIeeeAddrReq = 0x01,
|
||||
ZDOCommandNodeDescReq = 0x02,
|
||||
ZDOCommandPowerDescReq = 0x03,
|
||||
ZDOCommandSimpleDescReq = 0x04,
|
||||
ZDOCommandActiveEpReq = 0x05,
|
||||
ZDOCommandMatchDescReq = 0x06,
|
||||
ZDOCommandComplexDescReq = 0x07,
|
||||
ZDOCommandUserDescReq = 0x08,
|
||||
|
||||
ZDOCommandEndDeviceAnnce = 0x0A,
|
||||
ZDOCommandUserDescSet = 0x0B,
|
||||
ZDOCommandServerDiscReq = 0x0C,
|
||||
ZDOCommandEndDeviceTimeoutReq = 0x0D,
|
||||
|
||||
ZDOCommandEndDeviceBindReq = 0x20,
|
||||
ZDOCommandBindReq = 0x21,
|
||||
ZDOCommandUnbindReq = 0x22,
|
||||
ZDOCommandSetLinkKey = 0x23,
|
||||
ZDOCommandRemoveLinkKey = 0x24,
|
||||
ZDOCommandGetLinkKey = 0x25,
|
||||
ZDOCommandNwkDiscoveryReq = 0x26,
|
||||
ZDOCommandJoinReq = 0x27,
|
||||
ZDOCommandSendData = 0x28,
|
||||
ZDOCommandNwkAddrOfInterestReq = 0x26,
|
||||
|
||||
ZDOCommandMgmtNwkDiscReq = 0x30,
|
||||
ZDOCommandMgmtLqiReq = 0x31,
|
||||
ZDOCommandMgmtRtgReq = 0x32,
|
||||
ZDOCommandMgmtBindReq = 0x33,
|
||||
ZDOCommandMgmtLeaveReq = 0x34,
|
||||
ZDOCommandMgmtDirectJoinReq = 0x35,
|
||||
ZDOCommandMgmtPermitJoinReq = 0x36,
|
||||
ZDOCommandMgmtNwkUpdateReq = 0x37,
|
||||
|
||||
ZDOCommandMsgCbRegister = 0x3E,
|
||||
ZDOCommandMsgCbRemove = 0x3F,
|
||||
ZDOCommandStartupFromApp = 0x40,
|
||||
ZDOCommandAutoFindDestination = 0x41,
|
||||
ZDOCommandSecAddLinkKey = 0x42,
|
||||
ZDOCommandSecEntryLookupExt = 0x43,
|
||||
ZDOCommandSecDeviceRemove = 0x044,
|
||||
ZDOCommandExtRouteDisc = 0x45,
|
||||
ZDOCommandExtRouteCheck = 0x46,
|
||||
ZDOCommandExtRemoveGroup = 0x47,
|
||||
ZDOCommandExtRemoveAllGroup = 0x48,
|
||||
ZDOCommandExtFindAllGroupsEndpoint = 0x49,
|
||||
ZDOCommandExtFindGroup = 0x4A,
|
||||
ZDOCommandExtAddGroup = 0x4B,
|
||||
ZDOCommandExtCountAllGroups = 0xAC,
|
||||
ZDOCommandExtRxIdle = 0xAD,
|
||||
ZDOCommandExtUpdateNwkKey = 0xAE,
|
||||
ZDOCommandExtSwitchNwkKey = 0xAF,
|
||||
ZDOCommandExtNwkInfo = 0x50,
|
||||
ZDOCommandExtSecApsRemoveReq = 0x51,
|
||||
ZDOCommandForceContentratorChange = 0x52,
|
||||
ZDOCommandExtSetParams = 0x53,
|
||||
|
||||
ZDOCommandNwkAddrRsp = 0x80,
|
||||
ZDOCommandNwkIeeeAddrRsp = 0x81,
|
||||
ZDOCommandNodeDescRsp = 0x82,
|
||||
ZDOCommandPowerDescRsp = 0x83,
|
||||
ZDOCommandSimpleDescRsp = 0x84,
|
||||
ZDOCommandActiveEpRsp = 0x85,
|
||||
ZDOCommandMatchDescRsp = 0x86,
|
||||
ZDOCommandComplexDescRsp = 0x87,
|
||||
ZDOCommandUserDescRsp = 0x88,
|
||||
ZDOCommandUserDescConf = 0x89,
|
||||
ZDOCommandServerDiscRsp = 0x8A,
|
||||
|
||||
ZDOCommandEndDeviceBindRsp = 0xA0,
|
||||
ZDOCommandBindRsp = 0xA1,
|
||||
ZDOCommandUnbindRsp = 0xA2,
|
||||
|
||||
ZDOCommandMgmtNwkDiscRsp = 0xB0,
|
||||
ZDOCommandMgmtLqiRsp = 0xB1,
|
||||
ZDOCommandMgmtRtgRsp = 0xB2,
|
||||
ZDOCommandMgmtBindRsp = 0xB3,
|
||||
ZDOCommandMgmtLeaveRsp = 0xB4,
|
||||
ZDOCommandMgmtDirectJoinRsp = 0xB5,
|
||||
ZDOCommandMgmtPermitJoinRsp = 0xB6,
|
||||
|
||||
ZDOCommandMgmtNwkUpdateNotify = 0xB8,
|
||||
|
||||
ZDOCommandStateChangeInd = 0xC0,
|
||||
ZDOCommandEndDeviceAnnceInd = 0xC1,
|
||||
ZDOCommandMatchNodeDscRsp = 0xC2,
|
||||
ZDOCommandStatusErrorRsp = 0xC3,
|
||||
ZDOCommandSrcRtgInd = 0xC4,
|
||||
ZDOCommandBeaconNotifyInd = 0xC5,
|
||||
ZDOCommandJoinCnf = 0xC6,
|
||||
ZDOCommandNwkDiscoveryCnf = 0xC7,
|
||||
ZDOCommandConcentratorIndCb = 0xC8,
|
||||
ZDOCommandLeaveInd = 0xC9,
|
||||
ZDOCommandTcDeviceInd = 0xCA,
|
||||
ZDOCommandPermitJoinInd = 0xCB,
|
||||
|
||||
ZDOCommandSetRejoinParametersReq = 0xCC,
|
||||
ZDOCommandMsgCbIncoming = 0xFF
|
||||
};
|
||||
Q_ENUM(ZDOCommand)
|
||||
|
||||
enum SAPICommand {
|
||||
SAPICommandStartRequest = 0x00,
|
||||
SAPICommandSystemReset = 0x09,
|
||||
SAPICommandBindDevice = 0x01,
|
||||
SAPICommandAllowBind = 0x02,
|
||||
SAPICommandSendDataRequest = 0x03,
|
||||
SAPICommandReadConfiguration = 0x04,
|
||||
SAPICommandWriteConfiguration = 0x05,
|
||||
SAPICommandGetDeviceInfo = 0x06,
|
||||
SAPICommandFindDeviceRequest = 0x07,
|
||||
SAPICommandPermitJoiningRequest = 0x08,
|
||||
|
||||
SAPICommandStartConfirm = 0x80,
|
||||
SAPICommandBindConfirm = 0x81,
|
||||
SAPICommandAllowBindConfirm = 0x82,
|
||||
SAPICommandSendDataConfirm = 0x83,
|
||||
SAPICommandFindDeviceConfirm = 0x84,
|
||||
|
||||
SAPICommandReceiveDataIndication = 0x87,
|
||||
};
|
||||
Q_ENUM(SAPICommand)
|
||||
|
||||
enum UtilCommand {
|
||||
UtilCommandGetDeviceInfo = 0x00,
|
||||
UtilCommandGetNvInfo = 0x01,
|
||||
UtilCommandSetPanId = 0x02,
|
||||
UtilCommandSetChannels = 0x03,
|
||||
UtilCommandSetSecLevel = 0x04,
|
||||
UtilCommandSetPreCfgKey = 0x05,
|
||||
UtilCommandCallbackSubCmd = 0x06,
|
||||
UtilCommandKeyEvent = 0x07,
|
||||
UtilCommandTimeAlive = 0x09,
|
||||
UtilCommandLedControl = 0x0A,
|
||||
|
||||
UtilCommandTestLoopback = 0x10,
|
||||
UtilCommandDataReq = 0x11,
|
||||
|
||||
UtilCommandGpioSetDirection = 0x14,
|
||||
UtilCommandGpioRead = 0x15,
|
||||
UtilCommandGpioWrite = 0x16,
|
||||
|
||||
UtilCommandSrcMatchEnable = 0x20,
|
||||
UtilCommandSrcMatchAddEntry = 0x21,
|
||||
UtilCommandSrcMatchDelEntry = 0x22,
|
||||
UtilCommandSrcMatchCheckSrcAddr = 0x23,
|
||||
UtilCommandSrcMatchAckAllPending = 0x24,
|
||||
UtilCommandSrcMatchCheckAllPending = 0x25,
|
||||
|
||||
UtilCommandAddrMgrExtAddrLookup = 0x40,
|
||||
UtilCommandAddrMgrNwkAddrLookup = 0x41,
|
||||
|
||||
UtilCommandApsmeLinkKeyDataGet = 0x44,
|
||||
UtilCommandApsmeLinkKeyNvIdGet = 0x45,
|
||||
|
||||
UtilCommandAssocCount = 0x48,
|
||||
UtilCommandAssocFindDevice = 0x49,
|
||||
UtilCommandAssocGetWithAddress = 0x4A,
|
||||
UtilCommandApsmeRequestKeyCmd = 0x4B,
|
||||
UtilCommandSrngGen = 0x4C,
|
||||
UtilCommandBindAddKey = 0x4D,
|
||||
|
||||
UtilCommandAssocRemove = 0x63,
|
||||
UtilCommandAssocAdd = 0x64,
|
||||
|
||||
UtilCommandZclKeyEstInitEst = 0x80,
|
||||
UtilCommandZclKeyEstSign = 0x81,
|
||||
|
||||
UtilCommandSyncReq = 0xE0,
|
||||
UtilCommandZclKeyEstablishInd = 0xE1,
|
||||
};
|
||||
Q_ENUM(UtilCommand)
|
||||
|
||||
enum DebugCommand {
|
||||
DebugCommandSetThreshold = 0x00,
|
||||
DebugCommandMsg = 0x80,
|
||||
};
|
||||
Q_ENUM(DebugCommand)
|
||||
|
||||
enum AppCommand {
|
||||
AppCommandMsg = 0x00,
|
||||
AppCommandUserTest = 0x01,
|
||||
|
||||
AppCommandTllTlInd = 0x81,
|
||||
};
|
||||
Q_ENUM(AppCommand)
|
||||
|
||||
enum AppCnfCommand {
|
||||
AppCnfCommandBdbStartCommissioning = 0x05,
|
||||
AppCnfCommandBdbSetChannel = 0x08,
|
||||
AppCnfCommandBdbSetTcRequireKeyExchange = 0x09,
|
||||
|
||||
AppCnfCommandBdbCommissioningNotification = 0x80,
|
||||
|
||||
AppCnfCommandSetNwkFrameCounter = 0xFF
|
||||
};
|
||||
Q_ENUM(AppCnfCommand)
|
||||
|
||||
enum GreenPowerCommand {
|
||||
GreenPowerCommandSecReq = 0x03,
|
||||
};
|
||||
Q_ENUM(GreenPowerCommand)
|
||||
|
||||
enum NvItemId {
|
||||
NvItemIdExtAddr = 0x01,
|
||||
NvItemIdBootCounter = 0x02,
|
||||
NvItemIdStartupOption = 0x03,
|
||||
NvItemIdStartDelay = 0x04,
|
||||
NvItemIdNIB = 0x21,
|
||||
NvItemIdDeviceList = 0x22,
|
||||
NvItemIdAddrMgr = 0x23,
|
||||
NvItemIdPollRate = 0x24,
|
||||
NvItemIdQueuedPollRate = 0x25,
|
||||
NvItemIdResponsePollRate = 0x26,
|
||||
NvItemIdRejoinPollRate = 0x27,
|
||||
NvItemIdDataRetries = 0x28,
|
||||
NvItemIdPollFailureRetries = 0x29,
|
||||
NvItemIdStackProfile = 0x2A,
|
||||
NvItemIdIndirectMsgTimeout = 0x2B,
|
||||
NvItemIdRouteExpiryTime = 0x2C,
|
||||
NvItemIdExtendedPanId = 0x2D,
|
||||
NvItemIdBcastRetries = 0x2E,
|
||||
NvItemIdPassiveAckTimeout = 0x2F,
|
||||
NvItemIdBcastDeliveryTime = 0x30,
|
||||
NvItemIdNwkMode = 0x31,
|
||||
NvItemIdConcentratorEnable = 0x32,
|
||||
NvItemIdConcentratorDiscovery = 0x33,
|
||||
NvItemIdConcentratorRadius = 0x34,
|
||||
|
||||
NvItemIdConcentratorRC = 0x36,
|
||||
NvItemIdMwkMgrMode = 0x37,
|
||||
NvItemIdSrcRtgExpiryTime = 0x38,
|
||||
NvItemIdRouteDiscoveryTime = 0x39,
|
||||
NvItemIdNwkActiveKeyInfo = 0x3A,
|
||||
NvItemIdNwkAlternKeyInfo = 0x3B,
|
||||
NvItemIdRouterOffAssocCleanup = 0x3C,
|
||||
NvItemIdNwkLeaveReqAllowed = 0x3D,
|
||||
NvItemIdNwkChildAgeEnable = 0x3E,
|
||||
NvItemIdDeviceListKaTimeout = 0x3F,
|
||||
|
||||
NvItemIdBindingTable = 0x41,
|
||||
NvItemIdGroupTable = 0x42,
|
||||
NvItemIdApsFrameRetries = 0x43,
|
||||
NvItemIdApsAckWaitDuration = 0x44,
|
||||
NvItemIdApsAckWaitMultiplier = 0x45,
|
||||
NvItemIdBindingTime = 0x46,
|
||||
NvItemIdApsUseExtPanId = 0x47,
|
||||
NvItemIdApsUseInsecureJoin = 0x48,
|
||||
NvItemIdCommisionedNwkAddr = 0x49,
|
||||
NvItemIdApsNonMemberRadious = 0x4B,
|
||||
NvItemIdApsLinkKeyTable = 0x4C,
|
||||
NvItemIdApsDuprejTimeoutInc = 0x4D,
|
||||
NvItemIdApsDuprejTimeoutCount = 0x4E,
|
||||
NvItemIdApsDuprejTableSize = 0x4F,
|
||||
NvItemIdDiagnosticStats = 0x50,
|
||||
NvItemIdBdbNodeIsOnANetwork = 0x55,
|
||||
NvItemIdSecurityLevel = 0x61,
|
||||
NvItemIdPreCfgKey = 0x62,
|
||||
NvItemIdPreCfgKeysEnable = 0x63,
|
||||
NvItemIdSecurityMode = 0x64,
|
||||
NvItemIdSecurePermitJoin = 0x65,
|
||||
NvItemIdApsLinkKeyType = 0x66,
|
||||
NvItemIdApsAllowR19Security = 0x67,
|
||||
NvItemIdImplicitCertificate = 0x69,
|
||||
NvItemIdDevicePrivateKey = 0x6A,
|
||||
NvItemIdCaPublicKey = 0x6B,
|
||||
NvItemIdKeMaxDevices = 0x6C,
|
||||
NvItemIdUseDefaultTclk = 0x6D,
|
||||
NvItemIdRngCounter = 0x6F,
|
||||
NvItemIdRandomSeed = 0x70,
|
||||
NvItemIdTrustcenterAddr = 0x71,
|
||||
NvItemIdLegacyNwkSecMaterialTableStart = 0x74, // Valid for <= Z-Stack 3.0.x
|
||||
NvItemIdExNwkSecMaterialTable = 0x07, // Valid for >= Z-Stack 3.x.0
|
||||
NvItemIdUserDesc = 0x81,
|
||||
NvItemIdNwkKey = 0x82,
|
||||
NvItemIdPanId = 0x83,
|
||||
NvItemIdChanList = 0x84,
|
||||
NvItemIdLeaveCtrl = 0x85,
|
||||
NvItemIdScanDuration = 0x86,
|
||||
NvItemIdLogicalType = 0x87,
|
||||
NvItemIdNwkMgrMinTx = 0x88,
|
||||
NvItemIdNwkMgrAddr = 0x89,
|
||||
|
||||
NvItemIdZdoDirectCb = 0x8F,
|
||||
NvItemIdSceneTable = 0x91,
|
||||
NvItemIdMinFreeNwkAddr = 0x92,
|
||||
NvItemIdMaxFreeNwkAddr = 0x93,
|
||||
NvItemIdMinFreeGrpId = 0x94,
|
||||
NvItemIdMaxFreeGrpId = 0x95,
|
||||
NvItemIdMinGrpIds = 0x96,
|
||||
NvItemIdMaxGrpIds = 0x97,
|
||||
NvItemIdOtaBlockReqDelay = 0x98,
|
||||
NvItemIdSAPIEndpoint = 0xA1,
|
||||
NvItemIdSASShortAddr = 0xB1,
|
||||
NvItemIdSASExtPanId = 0xB2,
|
||||
NvItemIdSASPanId = 0xB3,
|
||||
NvItemIdSASChannelMask = 0xB4,
|
||||
NvItemIdSASProtocolVer = 0xB5,
|
||||
NvItemIdSASStackProfile = 0xB6,
|
||||
NvItemIdSASStartupCtrl = 0xB7,
|
||||
NvItemIdSASTcAddr = 0xC1,
|
||||
NvItemIdSASTcMasterKey = 0xC2,
|
||||
NvItemIdSASNwkKey = 0xC3,
|
||||
NvItemIdSASUseInsecJoin = 0xC4,
|
||||
NvItemIdSASPreCfgLinkKey = 0xC5,
|
||||
NvItemIdSASNwkKeySeqNum = 0xC6,
|
||||
NvItemIdSASNwkKeyType = 0xC7,
|
||||
NvItemIdSASNwkMgrAddr = 0xC8,
|
||||
NvItemIdSASCurrTcMasterKey = 0xD1,
|
||||
NvItemIdSASCurrNwkKey = 0xD2,
|
||||
NvItemIdSASCurrPreCfgLinkKey = 0xD3,
|
||||
|
||||
NvItemIdTclkSeed = 0x101,
|
||||
NvItemIdLegacyTclkTableStart_12 = 0x101, // Keep it for Legacy 1.2 stack
|
||||
NvItemIdLegacyTclkTableStart = 0x111, // Valid for <= Z-Stack 3.0.x
|
||||
NvItemIdExTclkTable = 0x04, // Valid for >= Z-Stack 3.0.x
|
||||
NvItemIdApsLinkKeyDataStart = 0x201,
|
||||
NvItemIdApsLinkKeyDataEnd = 0x2FF,
|
||||
NvItemIdDuplicateBindingTable = 0x300,
|
||||
NvItemIdDuplicateDeviceList = 0x301,
|
||||
NvItemIdDuplicateDeviceListKaTimeout = 0x302,
|
||||
NvItemIdZnpHasConfiguredStack1 = 0xF00,
|
||||
NvItemIdZnpHasConfiguredStack3 = 0x60,
|
||||
NvItemIdZcdNvExApsKeyDataTable = 0x06,
|
||||
NvItemIdZcdNvExAddrMgr = 0x01
|
||||
};
|
||||
Q_ENUM(NvItemId)
|
||||
|
||||
enum TxOption {
|
||||
TxOptionNone = 0x00,
|
||||
TxOptionsWildcardProfileId = 0x02,
|
||||
TxOptionPreprocess = 0x04,
|
||||
TxOptionLimitConcentrator = 0x08,
|
||||
TxOptionApsAck = 0x10,
|
||||
TxOptionSuppressRouteDiscovery = 0x20,
|
||||
TxOptionApsSecurity = 0x40,
|
||||
TxOptionSkipRouting = 0x80,
|
||||
TxOptionBroadCastEndpoint = 0xFF
|
||||
};
|
||||
Q_DECLARE_FLAGS(TxOptions, TxOption)
|
||||
Q_FLAG(TxOption)
|
||||
};
|
||||
|
||||
|
||||
#endif // TI_H
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "zigbeeinterfaceti.h"
|
||||
#include "zigbee.h"
|
||||
#include "zigbeeutils.h"
|
||||
#include "loggingcategory.h"
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
ZigbeeInterfaceTi::ZigbeeInterfaceTi(QObject *parent) : QObject(parent)
|
||||
{
|
||||
m_reconnectTimer = new QTimer(this);
|
||||
m_reconnectTimer->setSingleShot(true);
|
||||
m_reconnectTimer->setInterval(5000);
|
||||
|
||||
connect(m_reconnectTimer, &QTimer::timeout, this, &ZigbeeInterfaceTi::onReconnectTimeout);
|
||||
}
|
||||
|
||||
ZigbeeInterfaceTi::~ZigbeeInterfaceTi()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ZigbeeInterfaceTi::available() const
|
||||
{
|
||||
return m_available;
|
||||
}
|
||||
|
||||
QString ZigbeeInterfaceTi::serialPort() const
|
||||
{
|
||||
return m_serialPort->portName();
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::sendMagicByte()
|
||||
{
|
||||
QByteArray message;
|
||||
QDataStream stream(&message, QIODevice::WriteOnly);
|
||||
stream << static_cast<quint8>(0xef);
|
||||
m_serialPort->write(message);
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::setDTR(bool dtr)
|
||||
{
|
||||
m_serialPort->setDataTerminalReady(dtr);
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::setRTS(bool rts)
|
||||
{
|
||||
m_serialPort->setRequestToSend(rts);
|
||||
}
|
||||
|
||||
quint8 ZigbeeInterfaceTi::calculateChecksum(const QByteArray &data)
|
||||
{
|
||||
quint8 checksum = 0;
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
checksum ^= static_cast<quint8>(data.at(i));
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::setAvailable(bool available)
|
||||
{
|
||||
if (m_available == available)
|
||||
return;
|
||||
|
||||
// Clear the data buffer in any case
|
||||
if (m_available) {
|
||||
m_dataBuffer.clear();
|
||||
}
|
||||
|
||||
m_available = available;
|
||||
emit availableChanged(m_available);
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::onReconnectTimeout()
|
||||
{
|
||||
if (m_serialPort && !m_serialPort->isOpen()) {
|
||||
if (!m_serialPort->open(QSerialPort::ReadWrite)) {
|
||||
setAvailable(false);
|
||||
qCDebug(dcZigbeeInterface()) << "Interface reconnected failed" << m_serialPort->portName() << m_serialPort->baudRate();
|
||||
m_reconnectTimer->start();
|
||||
} else {
|
||||
qCDebug(dcZigbeeInterface()) << "Interface reconnected successfully on" << m_serialPort->portName() << m_serialPort->baudRate();
|
||||
m_serialPort->clear();
|
||||
setAvailable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::onReadyRead()
|
||||
{
|
||||
m_dataBuffer.append(m_serialPort->readAll());
|
||||
processBuffer();
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::processBuffer()
|
||||
{
|
||||
if (m_dataBuffer.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeInterfaceTraffic()) << "<--" << m_dataBuffer.toHex();
|
||||
// StartOfFrame
|
||||
if (static_cast<quint8>(m_dataBuffer.at(0)) != SOF) {
|
||||
qCWarning(dcZigbeeInterface()) << "Data doesn't start with StartOfFrame byte 0xfe. Discarding data...";
|
||||
m_dataBuffer.remove(0, 1);
|
||||
processBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
// payload length
|
||||
quint8 payloadLength = static_cast<quint8>(m_dataBuffer[1]);
|
||||
// Packet must be SOF + payload length field + CMD0 + CMD1 + payload length + Checksum
|
||||
if (m_dataBuffer.length() < payloadLength + 5) {
|
||||
qCDebug(dcZigbeeInterface()) << "Not enough data in buffer....";
|
||||
return;
|
||||
}
|
||||
QByteArray packet = m_dataBuffer.left(5 + payloadLength);
|
||||
m_dataBuffer.remove(0, 5 + payloadLength);
|
||||
|
||||
quint8 cmd0 = static_cast<quint8>(packet[2]);
|
||||
quint8 cmd1 = static_cast<quint8>(packet[3]);
|
||||
QByteArray payload = packet.mid(4, payloadLength);
|
||||
quint8 checksum = packet.at(4 + payloadLength);
|
||||
|
||||
if (calculateChecksum(packet.mid(1, 3 + payloadLength)) != checksum) {
|
||||
qCWarning(dcZigbeeInterface()) << "Checksum mismatch!";
|
||||
processBuffer();
|
||||
return;
|
||||
}
|
||||
// qCDebug(dcZigbeeInterface()) << "packet received:" << payloadLength << cmd0 << command << payload.toHex(' ') << checksum;
|
||||
|
||||
Ti::SubSystem subSystem = static_cast<Ti::SubSystem>(cmd0 & 0x1F);
|
||||
Ti::CommandType type = static_cast<Ti::CommandType>(cmd0 & 0xE0);
|
||||
|
||||
emit packetReceived(subSystem, type, cmd1, payload);
|
||||
|
||||
// In case there's more...
|
||||
processBuffer();
|
||||
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::onError(const QSerialPort::SerialPortError &error)
|
||||
{
|
||||
if (error != QSerialPort::NoError && m_serialPort->isOpen()) {
|
||||
qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString();
|
||||
m_reconnectTimer->start();
|
||||
m_serialPort->close();
|
||||
setAvailable(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::sendPacket(Ti::CommandType type, Ti::SubSystem subSystem, quint8 command, const QByteArray &payload)
|
||||
{
|
||||
if (!m_available) {
|
||||
qCWarning(dcZigbeeInterface()) << "Can not send data. The interface is not available";
|
||||
return;
|
||||
}
|
||||
|
||||
quint8 cmd0 = type | subSystem;
|
||||
|
||||
// Build transport data
|
||||
QByteArray data;
|
||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
stream << static_cast<quint8>(SOF);
|
||||
stream << static_cast<quint8>(payload.length());
|
||||
stream << cmd0;
|
||||
stream << static_cast<quint8>(command);
|
||||
for (int i = 0; i < payload.length(); i++) {
|
||||
stream << static_cast<quint8>(payload.at(i));
|
||||
}
|
||||
stream << calculateChecksum(data.right(data.length() - 1));
|
||||
|
||||
// Send the data
|
||||
qCDebug(dcZigbeeInterfaceTraffic()) << "-->" << data.toHex();
|
||||
if (m_serialPort->write(data) < 0) {
|
||||
qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteArrayToHexString(data);
|
||||
}
|
||||
|
||||
//m_serialPort->flush();
|
||||
}
|
||||
|
||||
bool ZigbeeInterfaceTi::enable(const QString &serialPort, qint32 baudrate)
|
||||
{
|
||||
qCDebug(dcZigbeeInterface()) << "Start UART interface " << serialPort << baudrate;
|
||||
|
||||
if (m_serialPort) {
|
||||
delete m_serialPort;
|
||||
m_serialPort = nullptr;
|
||||
}
|
||||
|
||||
m_serialPort = new QSerialPort(serialPort, this);
|
||||
m_serialPort->setBaudRate(baudrate);
|
||||
m_serialPort->setDataBits(QSerialPort::Data8);
|
||||
m_serialPort->setStopBits(QSerialPort::OneStop);
|
||||
m_serialPort->setParity(QSerialPort::NoParity);
|
||||
m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
|
||||
|
||||
connect(m_serialPort, &QSerialPort::readyRead, this, &ZigbeeInterfaceTi::onReadyRead);
|
||||
typedef void (QSerialPort::* errorSignal)(QSerialPort::SerialPortError);
|
||||
connect(m_serialPort, static_cast<errorSignal>(&QSerialPort::error), this, &ZigbeeInterfaceTi::onError);
|
||||
|
||||
if (!m_serialPort->open(QSerialPort::ReadWrite)) {
|
||||
qCWarning(dcZigbeeInterface()) << "Could not open serial port" << serialPort << baudrate << m_serialPort->errorString();
|
||||
m_reconnectTimer->start();
|
||||
return false;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeInterface()) << "Interface enabled successfully on" << serialPort << baudrate;
|
||||
m_serialPort->clear();
|
||||
|
||||
setAvailable(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::reconnectController()
|
||||
{
|
||||
if (!m_serialPort)
|
||||
return;
|
||||
|
||||
if (m_serialPort->isOpen())
|
||||
m_serialPort->close();
|
||||
|
||||
delete m_serialPort;
|
||||
m_serialPort = nullptr;
|
||||
setAvailable(false);
|
||||
m_reconnectTimer->start();
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTi::disable()
|
||||
{
|
||||
if (!m_serialPort)
|
||||
return;
|
||||
|
||||
if (m_serialPort->isOpen())
|
||||
m_serialPort->close();
|
||||
|
||||
delete m_serialPort;
|
||||
m_serialPort = nullptr;
|
||||
setAvailable(false);
|
||||
qCDebug(dcZigbeeInterface()) << "Interface disabled";
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ZIGBEEINTERFACETI_H
|
||||
#define ZIGBEEINTERFACETI_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QSerialPort>
|
||||
#include "zigbeeinterfacetireply.h"
|
||||
|
||||
#define SOF 0xFE
|
||||
|
||||
class ZigbeeInterfaceTi : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ZigbeeInterfaceTi(QObject *parent = nullptr);
|
||||
~ZigbeeInterfaceTi();
|
||||
|
||||
bool available() const;
|
||||
QString serialPort() const;
|
||||
|
||||
void sendMagicByte();
|
||||
void setDTR(bool dtr);
|
||||
void setRTS(bool rts);
|
||||
|
||||
void sendPacket(Ti::CommandType type, Ti::SubSystem subSystem, quint8 command, const QByteArray &payload);
|
||||
|
||||
public slots:
|
||||
bool enable(const QString &serialPort = "/dev/ttyS0", qint32 baudrate = 38400);
|
||||
void reconnectController();
|
||||
void disable();
|
||||
|
||||
signals:
|
||||
void availableChanged(bool available);
|
||||
void packetReceived(Ti::SubSystem subSystem, Ti::CommandType type, quint8 command, const QByteArray &payload);
|
||||
|
||||
private slots:
|
||||
void onReconnectTimeout();
|
||||
void onReadyRead();
|
||||
void onError(const QSerialPort::SerialPortError &error);
|
||||
void processBuffer();
|
||||
|
||||
private:
|
||||
QTimer *m_reconnectTimer = nullptr;
|
||||
QSerialPort *m_serialPort = nullptr;
|
||||
bool m_available = false;
|
||||
QByteArray m_dataBuffer;
|
||||
|
||||
quint8 calculateChecksum(const QByteArray &data);
|
||||
|
||||
void setAvailable(bool available);
|
||||
};
|
||||
|
||||
#endif // ZIGBEEINTERFACETI_H
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "zigbeeinterfacetireply.h"
|
||||
|
||||
quint8 ZigbeeInterfaceTiReply::command() const
|
||||
{
|
||||
return m_command;
|
||||
}
|
||||
|
||||
Ti::SubSystem ZigbeeInterfaceTiReply::subSystem() const
|
||||
{
|
||||
return m_subSystem;
|
||||
}
|
||||
|
||||
QByteArray ZigbeeInterfaceTiReply::requestPayload() const
|
||||
{
|
||||
return m_requestPayload;
|
||||
}
|
||||
|
||||
QByteArray ZigbeeInterfaceTiReply::responsePayload() const
|
||||
{
|
||||
return m_responsePayload;
|
||||
}
|
||||
|
||||
Ti::StatusCode ZigbeeInterfaceTiReply::statusCode() const
|
||||
{
|
||||
return m_statusCode;
|
||||
}
|
||||
|
||||
bool ZigbeeInterfaceTiReply::timendOut() const
|
||||
{
|
||||
return m_timeout;
|
||||
}
|
||||
|
||||
bool ZigbeeInterfaceTiReply::aborted() const
|
||||
{
|
||||
return m_aborted;
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTiReply::abort()
|
||||
{
|
||||
m_timer->stop();
|
||||
m_aborted = true;
|
||||
emit finished();
|
||||
}
|
||||
|
||||
ZigbeeInterfaceTiReply::ZigbeeInterfaceTiReply(QObject *parent, int timeout):
|
||||
QObject(parent),
|
||||
m_timer(new QTimer(this))
|
||||
{
|
||||
m_timer->setInterval(timeout);
|
||||
m_timer->setSingleShot(true);
|
||||
connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceTiReply::onTimeout);
|
||||
|
||||
// We'll auto-delete ourselves.
|
||||
connect(this, &ZigbeeInterfaceTiReply::finished, this, &QObject::deleteLater, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
ZigbeeInterfaceTiReply::ZigbeeInterfaceTiReply(Ti::SubSystem subSystem, quint8 command, QObject *parent, const QByteArray &requestPayload, int timeout) :
|
||||
ZigbeeInterfaceTiReply(parent, timeout)
|
||||
{
|
||||
m_subSystem = subSystem;
|
||||
m_command = command;
|
||||
m_requestPayload = requestPayload;
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTiReply::finish(Ti::StatusCode statusCode)
|
||||
{
|
||||
m_statusCode = statusCode;
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceTiReply::onTimeout()
|
||||
{
|
||||
m_timeout = true;
|
||||
emit timeout();
|
||||
emit finished();
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ZIGBEEINTERFACETIREPLY_H
|
||||
#define ZIGBEEINTERFACETIREPLY_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#include "ti.h"
|
||||
#include "zigbeenetworkrequest.h"
|
||||
|
||||
class ZigbeeInterfaceTiReply: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ZigbeeBridgeControllerTi;
|
||||
|
||||
public:
|
||||
explicit ZigbeeInterfaceTiReply(QObject *parent = nullptr, int timeout = 5000);
|
||||
explicit ZigbeeInterfaceTiReply(Ti::SubSystem subSystem, quint8 command, QObject *parent = nullptr, const QByteArray &requestPayload = QByteArray(), int timeout = 5000);
|
||||
|
||||
// Request content
|
||||
Ti::SubSystem subSystem() const;
|
||||
quint8 command() const;
|
||||
QByteArray requestPayload() const;
|
||||
|
||||
QByteArray responsePayload() const;
|
||||
|
||||
// Response content
|
||||
Ti::StatusCode statusCode() const;
|
||||
|
||||
bool timendOut() const;
|
||||
bool aborted() const;
|
||||
void abort();
|
||||
|
||||
signals:
|
||||
void timeout();
|
||||
void finished();
|
||||
|
||||
private slots:
|
||||
void onTimeout();
|
||||
void finish(Ti::StatusCode statusCode = Ti::StatusCodeSuccess);
|
||||
|
||||
private:
|
||||
QTimer *m_timer = nullptr;
|
||||
bool m_timeout = false;
|
||||
bool m_aborted = false;
|
||||
|
||||
void setSequenceNumber(quint8 sequenceNumber);
|
||||
|
||||
// Request content
|
||||
Ti::SubSystem m_subSystem = Ti::SubSystemSys;
|
||||
quint8 m_command = 0;
|
||||
QByteArray m_requestPayload;
|
||||
|
||||
// Response content
|
||||
Ti::StatusCode m_statusCode = Ti::StatusCodeError;
|
||||
QByteArray m_responsePayload;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // ZIGBEEINTERFACETIREPLY_H
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,154 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ZIGBEEBRIDGECONTROLLERTI_H
|
||||
#define ZIGBEEBRIDGECONTROLLERTI_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QTimer>
|
||||
#include <QQueue>
|
||||
#include <QObject>
|
||||
|
||||
#include "zigbee.h"
|
||||
#include "zigbeenetwork.h"
|
||||
#include "zigbeeaddress.h"
|
||||
#include "zigbeenetworkkey.h"
|
||||
#include "zigbeenetworkrequest.h"
|
||||
#include "zigbeebridgecontroller.h"
|
||||
|
||||
#include "interface/ti.h"
|
||||
#include "interface/zigbeeinterfaceti.h"
|
||||
#include "interface/zigbeeinterfacetireply.h"
|
||||
|
||||
typedef struct TiNetworkConfiguration {
|
||||
ZigbeeAddress ieeeAddress; // R
|
||||
quint16 panId = 0; // R
|
||||
quint16 shortAddress = 0; // R
|
||||
quint64 extendedPanId = 0; // R
|
||||
ZigbeeChannelMask channelMask = 0; // RW
|
||||
ZigbeeNetworkKey networkKey; // RW
|
||||
quint8 currentChannel = 0; // R
|
||||
Ti::ZnpVersion znpVersion = Ti::zStack12;
|
||||
} TiNetworkConfiguration;
|
||||
|
||||
class ZigbeeBridgeControllerTi : public ZigbeeBridgeController
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ZigbeeNetworkTi;
|
||||
|
||||
public:
|
||||
enum ControllerState {
|
||||
ControllerStateDown,
|
||||
ControllerStateInitialized,
|
||||
ControllerStateRunning,
|
||||
};
|
||||
Q_ENUM(ControllerState)
|
||||
|
||||
explicit ZigbeeBridgeControllerTi(QObject *parent = nullptr);
|
||||
~ZigbeeBridgeControllerTi() override;
|
||||
|
||||
ControllerState state() const;
|
||||
|
||||
ZigbeeInterfaceTiReply *init();
|
||||
ZigbeeInterfaceTiReply *commission(Ti::DeviceLogicalType deviceType, quint16 panId, const ZigbeeChannelMask &channelMask);
|
||||
ZigbeeInterfaceTiReply *start();
|
||||
ZigbeeInterfaceTiReply *reset();
|
||||
ZigbeeInterfaceTiReply *factoryReset();
|
||||
|
||||
// Network config will be available after initialisation.
|
||||
TiNetworkConfiguration networkConfiguration() const;
|
||||
|
||||
// Anything else is available once running
|
||||
ZigbeeInterfaceTiReply *setLed(bool on);
|
||||
|
||||
ZigbeeInterfaceTiReply *requestPermitJoin(quint8 seconds, const quint16 &networkAddress);
|
||||
ZigbeeInterfaceTiReply *registerEndpoint(quint8 endpointId, Zigbee::ZigbeeProfile profile, quint16 deviceId, quint8 deviceVersion);
|
||||
ZigbeeInterfaceTiReply *addEndpointToGroup(quint8 endpointId, quint16 groupId);
|
||||
|
||||
// Send APS request data
|
||||
ZigbeeInterfaceTiReply *requestSendRequest(const ZigbeeNetworkRequest &request);
|
||||
|
||||
public slots:
|
||||
bool enable(const QString &serialPort, qint32 baudrate);
|
||||
void disable();
|
||||
|
||||
signals:
|
||||
void controllerStateChanged(ControllerState state);
|
||||
|
||||
void permitJoinStateChanged(qint8 duration);
|
||||
void deviceIndication(quint16 shortAddress, const ZigbeeAddress &ieeeAddress, quint8 macCapabilities);
|
||||
void nodeLeft(const ZigbeeAddress &ieeeAddress, bool request, bool remove, bool rejoin);
|
||||
|
||||
void deviceProfileIndicationReceived(const Zigbee::ApsdeDataIndication &indication);
|
||||
void clusterLibraryIndicationReceived(const Zigbee::ApsdeDataIndication &indication);
|
||||
|
||||
private slots:
|
||||
void onInterfaceAvailableChanged(bool available);
|
||||
void onInterfacePacketReceived(Ti::SubSystem subSystem, Ti::CommandType commandType, quint8 command, const QByteArray &payload);
|
||||
void sendNextRequest();
|
||||
|
||||
void initPhase2(ZigbeeInterfaceTiReply* initReply, int attempt);
|
||||
void postStartup();
|
||||
|
||||
private:
|
||||
ZigbeeInterfaceTiReply *sendCommand(Ti::SubSystem subSystem, quint8 command, const QByteArray &payload = QByteArray(), int timeout = 5000);
|
||||
ZigbeeInterfaceTiReply *readNvItem(Ti::NvItemId itemId, quint16 offset = 0);
|
||||
ZigbeeInterfaceTiReply *writeNvItem(Ti::NvItemId itemId, const QByteArray &data, quint16 offset = 0);
|
||||
ZigbeeInterfaceTiReply *deleteNvItem(Ti::NvItemId itemId);
|
||||
void retrieveHugeMessage(const Zigbee::ApsdeDataIndication &pendingIndication, quint32 timestamp, quint16 dataLength);
|
||||
|
||||
void waitFor(ZigbeeInterfaceTiReply *reply, Ti::SubSystem subSystem, quint8 command);
|
||||
void waitFor(ZigbeeInterfaceTiReply *reply, Ti::SubSystem subSystem, quint8 command, const QByteArray &payload);
|
||||
struct WaitData {
|
||||
Ti::SubSystem subSystem;
|
||||
quint8 command;
|
||||
QByteArray payload;
|
||||
bool comparePayload = false;
|
||||
};
|
||||
QHash<ZigbeeInterfaceTiReply*, WaitData> m_waitFors;
|
||||
|
||||
ZigbeeInterfaceTi *m_interface = nullptr;
|
||||
|
||||
TiNetworkConfiguration m_networkConfiguration;
|
||||
ControllerState m_controllerState = ControllerStateDown;
|
||||
|
||||
ZigbeeInterfaceTiReply *m_currentReply = nullptr;
|
||||
|
||||
QQueue<ZigbeeInterfaceTiReply *> m_replyQueue;
|
||||
|
||||
QTimer m_permitJoinTimer;
|
||||
|
||||
QList<int> m_registeredEndpointIds;
|
||||
|
||||
void finishRequest(Ti::StatusCode statusCode = Ti::StatusCodeSuccess);
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, const TiNetworkConfiguration &configuration);
|
||||
|
||||
|
||||
#endif // ZIGBEEBRIDGECONTROLLERTI_H
|
||||
|
|
@ -0,0 +1,541 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "zdo/zigbeedeviceprofile.h"
|
||||
#include "zigbeenetworkti.h"
|
||||
#include "loggingcategory.h"
|
||||
#include "zigbeeutils.h"
|
||||
#include "zigbeenetworkdatabase.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QtCrypto>
|
||||
|
||||
ZigbeeNetworkTi::ZigbeeNetworkTi(const QUuid &networkUuid, QObject *parent) :
|
||||
ZigbeeNetwork(networkUuid, parent)
|
||||
{
|
||||
m_controller = new ZigbeeBridgeControllerTi(this);
|
||||
connect(m_controller, &ZigbeeBridgeControllerTi::availableChanged, this, &ZigbeeNetworkTi::onControllerAvailableChanged);
|
||||
connect(m_controller, &ZigbeeBridgeControllerTi::controllerStateChanged, this, &ZigbeeNetworkTi::onControllerStateChanged);
|
||||
connect(m_controller, &ZigbeeBridgeControllerTi::firmwareVersionChanged, this, &ZigbeeNetworkTi::firmwareVersionChanged);
|
||||
connect(m_controller, &ZigbeeBridgeControllerTi::permitJoinStateChanged, this, &ZigbeeNetworkTi::onPermitJoinStateChanged);
|
||||
connect(m_controller, &ZigbeeBridgeControllerTi::deviceIndication, this, &ZigbeeNetworkTi::onDeviceIndication);
|
||||
connect(m_controller, &ZigbeeBridgeControllerTi::apsDataIndicationReceived, this, &ZigbeeNetworkTi::onApsDataIndicationReceived);
|
||||
connect(m_controller, &ZigbeeBridgeControllerTi::apsDataConfirmReceived, this, &ZigbeeNetworkTi::onApsDataConfirmReceived);
|
||||
connect(m_controller, &ZigbeeBridgeControllerTi::nodeLeft, this, &ZigbeeNetworkTi::onNodeLeaveIndication);
|
||||
}
|
||||
|
||||
ZigbeeBridgeController *ZigbeeNetworkTi::bridgeController() const
|
||||
{
|
||||
if (!m_controller)
|
||||
return nullptr;
|
||||
|
||||
return m_controller;
|
||||
}
|
||||
|
||||
Zigbee::ZigbeeBackendType ZigbeeNetworkTi::backendType() const
|
||||
{
|
||||
return Zigbee::ZigbeeBackendTypeTi;
|
||||
}
|
||||
|
||||
ZigbeeNetworkReply *ZigbeeNetworkTi::sendRequest(const ZigbeeNetworkRequest &request)
|
||||
{
|
||||
ZigbeeNetworkReply *reply = createNetworkReply(request);
|
||||
|
||||
// Finish the reply right away if the network is offline
|
||||
if (!m_controller->available() || state() == ZigbeeNetwork::StateOffline || state() == ZigbeeNetwork::StateStopping) {
|
||||
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorNetworkOffline);
|
||||
return reply;
|
||||
}
|
||||
|
||||
if (state() == ZigbeeNetwork::StateStarting) {
|
||||
m_requestQueue.append(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
ZigbeeInterfaceTiReply *interfaceReply = m_controller->requestSendRequest(request);
|
||||
connect(interfaceReply, &ZigbeeInterfaceTiReply::finished, reply, [this, reply, interfaceReply](){
|
||||
if (interfaceReply->statusCode() != Ti::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Could send request to controller." << interfaceReply->statusCode();
|
||||
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorInterfaceError);
|
||||
return;
|
||||
}
|
||||
|
||||
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorNoError);
|
||||
});
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::setPermitJoining(quint8 duration, quint16 address)
|
||||
{
|
||||
if (duration > 0) {
|
||||
qCDebug(dcZigbeeNetwork()) << "Set permit join for" << duration << "s on" << ZigbeeUtils::convertUint16ToHexString(address);
|
||||
} else {
|
||||
qCDebug(dcZigbeeNetwork()) << "Disable permit join on"<< ZigbeeUtils::convertUint16ToHexString(address);
|
||||
}
|
||||
|
||||
setPermitJoiningDuration(duration);
|
||||
|
||||
ZigbeeInterfaceTiReply *requestPermitJoinReply = m_controller->requestPermitJoin(duration, address);
|
||||
connect(requestPermitJoinReply, &ZigbeeInterfaceTiReply::finished, this, [=](){
|
||||
if (requestPermitJoinReply->statusCode() != Ti::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Could not set permit join to" << duration << ZigbeeUtils::convertUint16ToHexString(address) << requestPermitJoinReply->statusCode();
|
||||
return;
|
||||
}
|
||||
qCDebug(dcZigbeeNetwork()) << "Permit join request finished successfully";
|
||||
|
||||
// Opening the green power network too
|
||||
// Todo: This should probably be somewhere else, but not yet sure how other backeds deal with this
|
||||
QByteArray payload;
|
||||
QDataStream stream(&payload, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
stream << static_cast<quint8>(0x0b); // options
|
||||
stream << static_cast<quint16>(duration);
|
||||
|
||||
|
||||
// Build ZCL frame control
|
||||
ZigbeeClusterLibrary::FrameControl frameControl;
|
||||
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
|
||||
frameControl.manufacturerSpecific = false;
|
||||
frameControl.direction = ZigbeeClusterLibrary::DirectionServerToClient;
|
||||
frameControl.disableDefaultResponse = true;
|
||||
|
||||
// Build ZCL header
|
||||
ZigbeeClusterLibrary::Header header;
|
||||
header.frameControl = frameControl;
|
||||
header.command = 0x02;// TODO: ZigbeeClusterGreenPower::ClusterCommandCommissioningMode;
|
||||
header.transactionSequenceNumber = generateSequenceNumber();
|
||||
|
||||
// Build ZCL frame
|
||||
ZigbeeClusterLibrary::Frame frame;
|
||||
frame.header = header;
|
||||
frame.payload = payload;
|
||||
|
||||
ZigbeeNetworkRequest request;
|
||||
request.setRequestId(generateSequenceNumber());
|
||||
request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress);
|
||||
request.setDestinationShortAddress(0xFFFD);
|
||||
request.setDestinationEndpoint(242); // Green Power Endpoint
|
||||
request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP
|
||||
request.setClusterId(0x21);
|
||||
request.setTxOptions(static_cast<Zigbee::ZigbeeTxOption>(0x00)); // FIXME: There should be TxOptionsNone I guess...
|
||||
request.setSourceEndpoint(242); // Green Power Endpoint
|
||||
request.setRadius(30); // FIXME: There should be a more clever way to figure out the radius
|
||||
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
|
||||
|
||||
m_controller->requestSendRequest(request);
|
||||
});
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::initController()
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Initializing controller";
|
||||
setState(StateStarting);
|
||||
setError(ErrorNoError);
|
||||
|
||||
ZigbeeInterfaceTiReply *initReply = m_controller->init();
|
||||
connect(initReply, &ZigbeeInterfaceTiReply::finished, this, [=](){
|
||||
if (initReply->statusCode() != Ti::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Error initializing controller";
|
||||
setState(StateUninitialized);
|
||||
setError(ErrorZigbeeError);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::commissionController()
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Commissioning controller";
|
||||
|
||||
quint16 panId = ZigbeeUtils::generateRandomPanId();
|
||||
|
||||
ZigbeeInterfaceTiReply *commissionReply = m_controller->commission(Ti::DeviceLogicalTypeCoordinator, panId, channelMask());
|
||||
connect(commissionReply, &ZigbeeInterfaceTiReply::finished, this, [=](){
|
||||
if (commissionReply->statusCode() != Ti::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Error commissioning controller.";
|
||||
setState(StateUninitialized);
|
||||
setError(ErrorZigbeeError);
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << "Controller commissioned";
|
||||
|
||||
startControllerNetwork();
|
||||
setMacAddress(m_controller->networkConfiguration().ieeeAddress);
|
||||
});
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::startControllerNetwork()
|
||||
{
|
||||
setState(StateStarting);
|
||||
qCDebug(dcZigbeeNetwork()) << "Starting network on controller...";
|
||||
ZigbeeInterfaceTiReply *startReply = m_controller->start();
|
||||
connect(startReply, &ZigbeeInterfaceTiReply::finished, this, [=]() {
|
||||
if (startReply->statusCode() != Ti::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Error starting network.";
|
||||
setState(StateOffline);
|
||||
setError(ErrorZigbeeError);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::processGreenPowerFrame(const Zigbee::ApsdeDataIndication &indication)
|
||||
{
|
||||
ZigbeeClusterLibrary::Frame inputFrame = ZigbeeClusterLibrary::parseFrameData(indication.asdu);
|
||||
QDataStream inputStream(inputFrame.payload);
|
||||
inputStream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint8 commandId, payloadSize;
|
||||
quint16 options;
|
||||
quint32 srcId, frameCounter;
|
||||
inputStream >> options >> srcId >> frameCounter >> commandId >> payloadSize;
|
||||
QByteArray commandFrame = inputFrame.payload.right(payloadSize);
|
||||
qCWarning(dcZigbeeNetwork()) << "Green Power frame:" << options << srcId << frameCounter << commandId << payloadSize << commandFrame.toHex();
|
||||
|
||||
if (commandId == 0xE0) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Green power commissioning";
|
||||
QDataStream commandStream(commandFrame);
|
||||
commandStream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint8 deviceId, inputOptions, extendedOptions;
|
||||
QByteArray securityKey;
|
||||
quint32 keyMic;
|
||||
quint32 outgoingCounter;
|
||||
commandStream >> deviceId >> inputOptions >> extendedOptions;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
quint8 byte;
|
||||
commandStream >> byte;
|
||||
securityKey.append(byte);
|
||||
}
|
||||
commandStream >> keyMic >> outgoingCounter;
|
||||
|
||||
// Send commissioning reply
|
||||
QByteArray payload;
|
||||
QDataStream stream(&payload, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
ZigbeeDataType options = ZigbeeDataType(static_cast<quint32>(0x00e548), Zigbee::Uint24); // options
|
||||
for (int i = 0; i < options.data().length(); i++) {
|
||||
stream << static_cast<quint8>(options.data().at(i));
|
||||
}
|
||||
stream << srcId;
|
||||
stream << static_cast<quint16>(0x0b84); // Green Power group as configured during startup
|
||||
stream << deviceId;
|
||||
stream << outgoingCounter;
|
||||
payload.append(encryptSecurityKey(srcId, securityKey));
|
||||
|
||||
// Build ZCL frame control
|
||||
ZigbeeClusterLibrary::FrameControl frameControl;
|
||||
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
|
||||
frameControl.manufacturerSpecific = false;
|
||||
frameControl.direction = ZigbeeClusterLibrary::DirectionServerToClient;
|
||||
frameControl.disableDefaultResponse = true;
|
||||
|
||||
// Build ZCL header
|
||||
ZigbeeClusterLibrary::Header header;
|
||||
header.frameControl = frameControl;
|
||||
header.command = 0x01; // TODO: ZigbeeClusterGreenPower::ClusterCommandPairing;
|
||||
header.transactionSequenceNumber = generateSequenceNumber() - 1;
|
||||
|
||||
// Build ZCL frame
|
||||
ZigbeeClusterLibrary::Frame frame;
|
||||
frame.header = header;
|
||||
frame.payload = payload;
|
||||
|
||||
ZigbeeNetworkRequest request;
|
||||
request.setRequestId(generateSequenceNumber() + 1);
|
||||
request.setDestinationAddressMode(Zigbee::DestinationAddressModeShortAddress);
|
||||
request.setDestinationShortAddress(0xFFFD);
|
||||
request.setDestinationEndpoint(242); // Green Power Endpoint
|
||||
request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP
|
||||
request.setClusterId(0x21);
|
||||
request.setTxOptions(static_cast<Zigbee::ZigbeeTxOption>(0x00)); // FIXME: There should be TxOptionsNone I guess...
|
||||
request.setSourceEndpoint(242); // Green Power Endpoint
|
||||
request.setRadius(30); // FIXME: There should be a more clever way to figure out the radius
|
||||
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
|
||||
|
||||
m_controller->requestSendRequest(request);
|
||||
|
||||
QStringList l;
|
||||
for (int i = 0; i < request.asdu().length(); i++) {
|
||||
l.append(QString::number(static_cast<quint8>(request.asdu().at(i))));
|
||||
}
|
||||
|
||||
// TODO: create the GreenPower Node here once GreenPower support is added properly
|
||||
// emit greenPowerDeviceJoined(srcId, deviceId, indication.sourceIeeeAddress())
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray ZigbeeNetworkTi::encryptSecurityKey(quint32 sourceId, const QByteArray &securityKey)
|
||||
{
|
||||
#if (QCA_VERSION >= QCA_VERSION_CHECK(2, 2, 0))
|
||||
QByteArray sourceIdArray;
|
||||
sourceIdArray.append(static_cast<quint8>(sourceId & 0x000000ff));
|
||||
sourceIdArray.append(static_cast<quint8>((sourceId & 0x0000ff00) >> 8));
|
||||
sourceIdArray.append(static_cast<quint8>((sourceId & 0x00ff0000) >> 16));
|
||||
sourceIdArray.append(static_cast<quint8>((sourceId & 0xff000000) >> 24));
|
||||
|
||||
QByteArray nonce(13, Qt::Uninitialized);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
nonce[4 * i + j] = sourceIdArray.at(j);
|
||||
}
|
||||
}
|
||||
nonce[12] = 0x05;
|
||||
|
||||
QByteArray zigbeeLinkKey = securityConfiguration().globalTrustCenterLinkKey().toByteArray();
|
||||
|
||||
QCA::Initializer init;
|
||||
QCA::Cipher cipher("aes128", QCA::Cipher::CCM, QCA::Cipher::DefaultPadding, QCA::Encode, zigbeeLinkKey, nonce);
|
||||
QByteArray encrypted = cipher.update(securityKey).toByteArray();
|
||||
encrypted.append(cipher.final().toByteArray());
|
||||
return encrypted;
|
||||
#else
|
||||
Q_UNUSED(sourceId)
|
||||
qCWarning(dcZigbeeNetwork()) << "Greenpower encryption requires AES-128-CCM (requires qca-qt5-2 >= 2.2.0)";
|
||||
return securityKey;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::onControllerAvailableChanged(bool available)
|
||||
{
|
||||
if (!available) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Hardware controller is not available any more.";
|
||||
setError(ErrorHardwareUnavailable);
|
||||
setPermitJoiningEnabled(false);
|
||||
setState(StateOffline);
|
||||
setError(ErrorHardwareUnavailable);
|
||||
} else {
|
||||
setPermitJoiningEnabled(false);
|
||||
setState(StateOffline);
|
||||
setError(ErrorNoError);
|
||||
qCDebug(dcZigbeeNetwork()) << "Hardware controller is now available.";
|
||||
initController();
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::onControllerStateChanged(ZigbeeBridgeControllerTi::ControllerState state)
|
||||
{
|
||||
switch (state) {
|
||||
case ZigbeeBridgeControllerTi::ControllerStateDown:
|
||||
setState(StateOffline);
|
||||
break;
|
||||
case ZigbeeBridgeControllerTi::ControllerStateInitialized:
|
||||
|
||||
// The mac address of the controller will be stored locally when the coordinator node replies
|
||||
// to the node descriptor request which includes the IEEE address.
|
||||
// If we don't know the mac address yet, it means that we've never had the zigbee network up and running
|
||||
// => start the commissioning procedure, else, directly start the network
|
||||
// Note: if the user messes around with the stick by provisioning stuff with another instance/software, it
|
||||
// will not be detected currently and the "wrong" network starts up.
|
||||
qCDebug(dcZigbeeNetwork()) << "Controller initialized";
|
||||
qCDebug(dcZigbeeNetwork()) << "Stored MAC address:" << macAddress() << "Controller MAC address:" << m_controller->networkConfiguration().ieeeAddress;
|
||||
|
||||
if (macAddress() != ZigbeeAddress("00:00:00:00:00:00:00:00") && m_controller->networkConfiguration().ieeeAddress != macAddress()) {
|
||||
qCWarning(dcZigbeeNetwork()) << "The controller MAC address changed. Please connect the original controller or create a new network.";
|
||||
setState(StateUninitialized);
|
||||
setError(ErrorHardwareModuleChanged);
|
||||
stopNetwork();
|
||||
return;
|
||||
}
|
||||
if (macAddress() == ZigbeeAddress("00:00:00:00:00:00:00")) {
|
||||
// Controller network is not commissioned yet
|
||||
qCDebug(dcZigbeeNetwork()) << "Controller is not comissioned yet. Comissioning now...";
|
||||
commissionController();
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << "Controller is ready and commissioned.";
|
||||
startControllerNetwork();
|
||||
|
||||
break;
|
||||
case ZigbeeBridgeControllerTi::ControllerStateRunning: {
|
||||
qCDebug(dcZigbeeNetwork()) << "Controller network running. Registering endpoints on controller..";
|
||||
|
||||
setPanId(m_controller->networkConfiguration().panId);
|
||||
setExtendedPanId(m_controller->networkConfiguration().extendedPanId);
|
||||
setChannel(m_controller->networkConfiguration().currentChannel);
|
||||
|
||||
// TODO: This should be public API of libnymea-zigbee so that the application layer (e.g. nymea-plugins)
|
||||
// can register the endpoints it needs for the particular application/device.
|
||||
// Fow now we're registering HomeAutomation, LightLink and GreenPower endpoints.
|
||||
m_controller->registerEndpoint(1, Zigbee::ZigbeeProfileHomeAutomation, 5, 0);
|
||||
m_controller->registerEndpoint(12, Zigbee::ZigbeeProfileLightLink, 5, 0);
|
||||
|
||||
// The Green Power endpoing is a bit special, it also needs to be added to a group
|
||||
ZigbeeInterfaceTiReply *registerLLEndpointReply = m_controller->registerEndpoint(242, Zigbee::ZigbeeProfileGreenPower, 5, 0);
|
||||
connect(registerLLEndpointReply, &ZigbeeInterfaceTiReply::finished, this, [=]() {
|
||||
if (registerLLEndpointReply->statusCode() != Ti::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Error registering GreenPower endpoint.";
|
||||
setState(StateOffline);
|
||||
return;
|
||||
}
|
||||
qCDebug(dcZigbeeNetwork()) << "Registered GreenPower endpoint on coordinator node.";
|
||||
|
||||
ZigbeeInterfaceTiReply *addGEndpointGroupReply = m_controller->addEndpointToGroup(242, 0x0b84);
|
||||
connect(addGEndpointGroupReply, &ZigbeeInterfaceTiReply::finished, this, [=]() {
|
||||
if (addGEndpointGroupReply->statusCode() != Ti::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeNetwork()) << "Error adding GreenPower endpoint to group.";
|
||||
setState(StateOffline);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now we're done. If this is a first start (no coordinator node loaded from configs) we'll add
|
||||
// ourselves now and start the inspection.
|
||||
if (!m_coordinatorNode) {
|
||||
qCDebug(dcZigbeeNetwork()) << "Initializing coordinator node:" << m_controller->networkConfiguration();
|
||||
ZigbeeNode *coordinatorNode = createNode(m_controller->networkConfiguration().shortAddress, m_controller->networkConfiguration().ieeeAddress, this);
|
||||
m_coordinatorNode = coordinatorNode;
|
||||
addUnitializedNode(coordinatorNode);
|
||||
}
|
||||
// Introspecing ourselves on every start. Most of the times this wouldn't be needed, but if the above
|
||||
// endpoints are changed (e.g. on a future upgrade), we'll want to refresh.
|
||||
m_coordinatorNode->startInitialization();
|
||||
|
||||
ZigbeeInterfaceTiReply *ledReply = m_controller->setLed(false);
|
||||
connect(ledReply, &ZigbeeInterfaceTiReply::finished, this, [=]() {
|
||||
setState(StateRunning);
|
||||
|
||||
while (!m_requestQueue.isEmpty()) {
|
||||
ZigbeeNetworkReply *reply = m_requestQueue.takeFirst();
|
||||
ZigbeeInterfaceTiReply *interfaceReply = m_controller->requestSendRequest(reply->request());
|
||||
connect(interfaceReply, &ZigbeeInterfaceTiReply::finished, reply, [this, reply, interfaceReply](){
|
||||
if (interfaceReply->statusCode() != Ti::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Could send request to controller." << interfaceReply->statusCode();
|
||||
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorInterfaceError);
|
||||
return;
|
||||
}
|
||||
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorNoError);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::onPermitJoinStateChanged(quint8 duration)
|
||||
{
|
||||
setPermitJoiningRemaining(duration);
|
||||
setPermitJoiningEnabled(duration > 0);
|
||||
m_controller->setLed(duration > 0);
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::onDeviceIndication(quint16 shortAddress, const ZigbeeAddress &ieeeAddress, quint8 macCapabilities)
|
||||
{
|
||||
onDeviceAnnounced(shortAddress, ieeeAddress, macCapabilities);
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::onNodeLeaveIndication(const ZigbeeAddress &ieeeAddress, bool request, bool remove, bool rejoin)
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Received node leave indication" << ieeeAddress.toString() << "request:" << request << "remove:" << remove << "rejoining:" << rejoin;
|
||||
if (!hasNode(ieeeAddress)) {
|
||||
qCDebug(dcZigbeeNetwork()) << "Node left the network" << ieeeAddress.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
ZigbeeNode *node = getZigbeeNode(ieeeAddress);
|
||||
qCDebug(dcZigbeeNetwork()) << node << "left the network";
|
||||
removeNode(node);
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::onApsDataConfirmReceived(const Zigbee::ApsdeDataConfirm &confirm)
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Data confirm received:" << confirm;
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::onApsDataIndicationReceived(const Zigbee::ApsdeDataIndication &indication)
|
||||
{
|
||||
// If it's for the green power endpoint, we'll have to do a commissioning.
|
||||
// TODO: This should probably be in ZigbeeNode or ZigbeeDeviceObject, but not yet sure how other backends deal with it
|
||||
if (indication.destinationEndpoint == 242) {
|
||||
processGreenPowerFrame(indication);
|
||||
}
|
||||
|
||||
// Check if this indocation is related to any pending reply
|
||||
if (indication.profileId == Zigbee::ZigbeeProfileDevice) {
|
||||
handleZigbeeDeviceProfileIndication(indication);
|
||||
return;
|
||||
}
|
||||
|
||||
// Else let the node handle this indication
|
||||
handleZigbeeClusterLibraryIndication(indication);
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::startNetwork()
|
||||
{
|
||||
loadNetwork();
|
||||
|
||||
if (!m_controller->enable(serialPortName(), serialBaudrate())) {
|
||||
setPermitJoiningEnabled(false);
|
||||
setState(StateOffline);
|
||||
setError(ErrorHardwareUnavailable);
|
||||
return;
|
||||
}
|
||||
|
||||
setPermitJoiningEnabled(false);
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::stopNetwork()
|
||||
{
|
||||
setState(StateStopping);
|
||||
m_controller->disable();
|
||||
setState(StateOffline);
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::reset()
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Resetting controller.";
|
||||
m_controller->reset();
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::factoryResetNetwork()
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Factory resetting network and forget all information. This cannot be undone.";
|
||||
|
||||
ZigbeeInterfaceTiReply *reply = m_controller->factoryReset();
|
||||
connect(reply, &ZigbeeInterfaceTiReply::finished, this, [=](){
|
||||
qCDebug(dcZigbeeNetwork()) << "Factory reset reply finished" << reply->statusCode();
|
||||
|
||||
m_controller->disable();
|
||||
clearSettings();
|
||||
setMacAddress(ZigbeeAddress("00:00:00:00:00:00"));
|
||||
setState(StateOffline);
|
||||
setError(ErrorNoError);
|
||||
qCDebug(dcZigbeeNetwork()) << "The factory reset is finished. Restarting with a fresh network.";
|
||||
startNetwork();
|
||||
});
|
||||
}
|
||||
|
||||
void ZigbeeNetworkTi::destroyNetwork()
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Destroy network and delete the database";
|
||||
m_controller->disable();
|
||||
clearSettings();
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ZIGBEENETWORKTI_H
|
||||
#define ZIGBEENETWORKTI_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "zigbeenetwork.h"
|
||||
#include "zigbeechannelmask.h"
|
||||
#include "zcl/zigbeeclusterlibrary.h"
|
||||
#include "zigbeebridgecontrollerti.h"
|
||||
|
||||
class ZigbeeNetworkTi : public ZigbeeNetwork
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
explicit ZigbeeNetworkTi(const QUuid &networkUuid, QObject *parent = nullptr);
|
||||
|
||||
ZigbeeBridgeController *bridgeController() const override;
|
||||
Zigbee::ZigbeeBackendType backendType() const override;
|
||||
|
||||
// Sending an APSDE-DATA.request, will be finished on APSDE-DATA.confirm
|
||||
ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) override;
|
||||
|
||||
void setPermitJoining(quint8 duration, quint16 address = Zigbee::BroadcastAddressAllRouters) override;
|
||||
|
||||
public slots:
|
||||
void startNetwork() override;
|
||||
void stopNetwork() override;
|
||||
void reset() override;
|
||||
void factoryResetNetwork() override;
|
||||
void destroyNetwork() override;
|
||||
|
||||
|
||||
private slots:
|
||||
void onControllerAvailableChanged(bool available);
|
||||
void onControllerStateChanged(ZigbeeBridgeControllerTi::ControllerState state);
|
||||
void onPermitJoinStateChanged(quint8 duration);
|
||||
void onDeviceIndication(quint16 shortAddress, const ZigbeeAddress &ieeeAddress, quint8 macCapabilities);
|
||||
void onNodeLeaveIndication(const ZigbeeAddress &ieeeAddress, bool request, bool remove, bool rejoin);
|
||||
|
||||
void onApsDataConfirmReceived(const Zigbee::ApsdeDataConfirm &confirm);
|
||||
void onApsDataIndicationReceived(const Zigbee::ApsdeDataIndication &indication);
|
||||
|
||||
private:
|
||||
void initController();
|
||||
void commissionController();
|
||||
void startControllerNetwork();
|
||||
|
||||
void processGreenPowerFrame(const Zigbee::ApsdeDataIndication &indication);
|
||||
QByteArray encryptSecurityKey(quint32 sourceId, const QByteArray &securityKey);
|
||||
|
||||
private:
|
||||
ZigbeeBridgeControllerTi *m_controller = nullptr;
|
||||
|
||||
QList<ZigbeeNetworkReply*> m_requestQueue;
|
||||
};
|
||||
|
||||
#endif // ZIGBEENETWORKDECONZ_H
|
||||
|
|
@ -12,6 +12,8 @@ packagesExist(libudev) {
|
|||
DEFINES += DISABLE_UDEV
|
||||
}
|
||||
|
||||
PKGCONFIG += qca2-qt5
|
||||
|
||||
SOURCES += \
|
||||
backends/deconz/interface/zigbeeinterfacedeconz.cpp \
|
||||
backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \
|
||||
|
|
@ -22,6 +24,10 @@ SOURCES += \
|
|||
backends/nxp/interface/zigbeeinterfacenxpreply.cpp \
|
||||
backends/nxp/zigbeebridgecontrollernxp.cpp \
|
||||
backends/nxp/zigbeenetworknxp.cpp \
|
||||
backends/ti/interface/zigbeeinterfaceti.cpp \
|
||||
backends/ti/interface/zigbeeinterfacetireply.cpp \
|
||||
backends/ti/zigbeebridgecontrollerti.cpp \
|
||||
backends/ti/zigbeenetworkti.cpp \
|
||||
zcl/closures/zigbeeclusterdoorlock.cpp \
|
||||
zcl/general/zigbeeclusteranaloginput.cpp \
|
||||
zcl/general/zigbeeclusteranalogoutput.cpp \
|
||||
|
|
@ -90,6 +96,11 @@ HEADERS += \
|
|||
backends/nxp/interface/zigbeeinterfacenxpreply.h \
|
||||
backends/nxp/zigbeebridgecontrollernxp.h \
|
||||
backends/nxp/zigbeenetworknxp.h \
|
||||
backends/ti/interface/ti.h \
|
||||
backends/ti/interface/zigbeeinterfaceti.h \
|
||||
backends/ti/interface/zigbeeinterfacetireply.h \
|
||||
backends/ti/zigbeebridgecontrollerti.h \
|
||||
backends/ti/zigbeenetworkti.h \
|
||||
zcl/closures/zigbeeclusterdoorlock.h \
|
||||
zcl/general/zigbeeclusteranaloginput.h \
|
||||
zcl/general/zigbeeclusteranalogoutput.h \
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ class Zigbee
|
|||
public:
|
||||
enum ZigbeeBackendType {
|
||||
ZigbeeBackendTypeDeconz,
|
||||
ZigbeeBackendTypeNxp
|
||||
ZigbeeBackendTypeNxp,
|
||||
ZigbeeBackendTypeTi
|
||||
};
|
||||
Q_ENUM(ZigbeeBackendType)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "backends/nxp/zigbeenetworknxp.h"
|
||||
#include "backends/deconz/zigbeenetworkdeconz.h"
|
||||
#include "backends/ti/zigbeenetworkti.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
|
|
@ -48,6 +49,8 @@ ZigbeeNetwork *ZigbeeNetworkManager::createZigbeeNetwork(const QUuid &networkUui
|
|||
return qobject_cast<ZigbeeNetwork *>(new ZigbeeNetworkNxp(networkUuid, parent));
|
||||
case Zigbee::ZigbeeBackendTypeDeconz:
|
||||
return qobject_cast<ZigbeeNetwork *>(new ZigbeeNetworkDeconz(networkUuid, parent));
|
||||
case Zigbee::ZigbeeBackendTypeTi:
|
||||
return qobject_cast<ZigbeeNetwork *>(new ZigbeeNetworkTi(networkUuid, parent));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea-zigbee.
|
||||
|
|
@ -237,6 +237,12 @@ void ZigbeeUartAdapterMonitor::addAdapterInternally(const QString &serialPort)
|
|||
adapter.setBackendType(Zigbee::ZigbeeBackendTypeNxp);
|
||||
adapter.setBaudRate(115200);
|
||||
}
|
||||
QStringList zStackModels = {"cc2530", "cc2531", "cc2538", "cc1352p", "cc2652p", "cc2652r", "cc2652rb", "sonoff zigbee 3.0 usb"};
|
||||
if (QRegExp(".*(" + zStackModels.join("|") + ").*").exactMatch(serialPortInfo.description().toLower())) {
|
||||
adapter.setHardwareRecognized(true);
|
||||
adapter.setBackendType(Zigbee::ZigbeeBackendTypeTi);
|
||||
adapter.setBaudRate(115200);
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeAdapterMonitor()) << "Added" << adapter;
|
||||
m_availableAdapters.insert(adapter.serialPort(), adapter);
|
||||
|
|
|
|||
Loading…
Reference in New Issue