From 8bfd7533340ff18fee40de068b4be8ed4c6c18c9 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Thu, 2 Jul 2020 22:56:37 +0200 Subject: [PATCH] Zigbee EZSP milestone 4 --- tasmota/my_user_config.h | 1 + tasmota/settings.h | 2 +- tasmota/xdrv_23_zigbee_7_statemachine.ino | 167 +++++++++++--- tasmota/xdrv_23_zigbee_8_parsers.ino | 258 ++++++++++++++++------ tasmota/xdrv_23_zigbee_9_serial.ino | 36 ++- tasmota/xdrv_23_zigbee_A_impl.ino | 22 +- 6 files changed, 382 insertions(+), 104 deletions(-) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index c073447fe..a097b6154 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -679,6 +679,7 @@ // if PANID == 0xFFFE, then the device will act as a Zigbee end-device (non-router), the parameters below are ignored #define USE_ZIGBEE_EXTPANID 0xCCCCCCCCCCCCCCCCL // arbitrary extended PAN ID #define USE_ZIGBEE_CHANNEL 11 // Zigbee Channel (11-26) + #define USE_ZIGBEE_TXRADIO_DBM 20 // Tx Radio power in dBm (only for EZSP, EFR32 can go up to 20 dBm) #define USE_ZIGBEE_PRECFGKEY_L 0x0F0D0B0907050301L // note: changing requires to re-pair all devices #define USE_ZIGBEE_PRECFGKEY_H 0x0D0C0A0806040200L // note: changing requires to re-pair all devices diff --git a/tasmota/settings.h b/tasmota/settings.h index 7fd279ab6..d5baaed93 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -559,7 +559,7 @@ struct { uint64_t zb_precfgkey_h; // F28 uint16_t zb_pan_id; // F30 uint8_t zb_channel; // F32 - uint8_t zb_free_byte; // F33 + uint8_t zb_txradio_dbm; // F33 uint16_t pms_wake_interval; // F34 uint8_t config_version; // F36 uint8_t windmeter_pulses_x_rot; // F37 diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index dd09cd18b..bfc07793e 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -106,6 +106,7 @@ enum Zigbee_StateMachine_Instruction_Set { #define ZI_WAIT_RECV_FUNC(x, m, f) { .i = { ZGB_INSTR_WAIT_RECV_CALL, sizeof(m), (x)} }, { .p = (const void*)(m) }, { .p = (const void*)(f) }, // Labels used in the State Machine -- internal only +const uint8_t ZIGBEE_LABEL_RESTART = 1; // Restart the state_machine in a different mode const uint8_t ZIGBEE_LABEL_INIT_COORD = 10; // Start ZNP as coordinator const uint8_t ZIGBEE_LABEL_START_COORD = 11; // Start ZNP as coordinator const uint8_t ZIGBEE_LABEL_INIT_ROUTER = 12; // Init ZNP as router @@ -118,13 +119,16 @@ const uint8_t ZIGBEE_LABEL_BOOT_TIME_OUT = 18; // MCU has not rebooted const uint8_t ZIGBEE_LABEL_FACT_RESET_ROUTER_DEVICE_POST = 19; // common post configuration for router and device const uint8_t ZIGBEE_LABEL_READY = 20; // goto label 20 for main loop const uint8_t ZIGBEE_LABEL_MAIN_LOOP = 21; // main loop +const uint8_t ZIGBEE_LABEL_NETWORK_CONFIGURED = 22; // main loop +const uint8_t ZIGBEE_LABEL_BAD_CONFIG = 23; // EZSP configuration is not the right one const uint8_t ZIGBEE_LABEL_PERMIT_JOIN_CLOSE = 30; // disable permit join const uint8_t ZIGBEE_LABEL_PERMIT_JOIN_OPEN_60 = 31; // enable permit join for 60 seconds const uint8_t ZIGBEE_LABEL_PERMIT_JOIN_OPEN_XX = 32; // enable permit join for 60 seconds -// factory reset +// factory reset or reconfiguration const uint8_t ZIGBEE_LABEL_FACT_RESET_COORD = 50; // main loop const uint8_t ZIGBEE_LABEL_FACT_RESET_ROUTER = 51; // main loop const uint8_t ZIGBEE_LABEL_FACT_RESET_DEVICE = 52; // main loop +const uint8_t ZIGBEE_LABEL_CONFIGURE_EZSP = 53; // main loop // errors const uint8_t ZIGBEE_LABEL_ABORT = 99; // goto label 99 in case of fatal error const uint8_t ZIGBEE_LABEL_UNSUPPORTED_VERSION = 98; // Unsupported ZNP version @@ -371,7 +375,7 @@ ZBM(ZBR_PERMITJOINREQ, Z_SRSP | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_REQ, Z_SUCCESS) / ZBM(ZBR_PERMITJOIN_AREQ_RSP, Z_AREQ | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_RSP, 0x00, 0x00 /* srcAddr*/, Z_SUCCESS ) // 45B6000000 // Update the relevant commands with Settings -void Z_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_panid, uint64_t zb_precfgkey_l, uint64_t zb_precfgkey_h) { +void ZNP_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_panid, uint64_t zb_precfgkey_l, uint64_t zb_precfgkey_h) { uint32_t zb_channel_mask = (1 << zb_channel); ZBW(ZBR_PAN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PANID, 0x02 /* len */, @@ -422,26 +426,26 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_NOOP() ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) - ZI_ON_RECV_UNEXPECTED(&Z_Recv_Default) + ZI_ON_RECV_UNEXPECTED(&ZNP_Recv_Default) ZI_WAIT(10500) // wait for 10 seconds for Tasmota to stabilize //ZI_MQTT_STATE(ZIGBEE_STATUS_BOOT, "Booting") //ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "rebooting device") ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_BOOT_TIME_OUT) // give a second chance ZI_SEND(ZBS_RESET) // reboot cc2530 just in case we rebooted ESP8266 but not cc2530 - ZI_WAIT_RECV_FUNC(5000, ZBR_RESET, &Z_Reboot) // timeout 5s + ZI_WAIT_RECV_FUNC(5000, ZBR_RESET, &ZNP_Reboot) // timeout 5s ZI_GOTO(ZIGBEE_LABEL_BOOT_OK) ZI_LABEL(ZIGBEE_LABEL_BOOT_TIME_OUT) ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) ZI_SEND(ZBS_RESET) // reboot cc2530 just in case we rebooted ESP8266 but not cc2530 - ZI_WAIT_RECV_FUNC(5000, ZBR_RESET, &Z_Reboot) // timeout 5s + ZI_WAIT_RECV_FUNC(5000, ZBR_RESET, &ZNP_Reboot) // timeout 5s ZI_LABEL(ZIGBEE_LABEL_BOOT_OK) ZI_WAIT(100) ZI_LOG(LOG_LEVEL_DEBUG, kCheckingDeviceConfiguration) // Log Debug: checking device configuration ZI_SEND(ZBS_VERSION) // check ZNP software version - ZI_WAIT_RECV_FUNC(2000, ZBR_VERSION, &Z_ReceiveCheckVersion) // Check if version is valid + ZI_WAIT_RECV_FUNC(2000, ZBR_VERSION, &ZNP_ReceiveCheckVersion) // Check if version is valid // Dispatching whether coordinator, router or end-device ZI_CALL(&Z_SwitchDeviceType, 0) // goto ZIGBEE_LABEL_INIT_ROUTER, ZIGBEE_LABEL_INIT_DEVICE or continue if coordinator @@ -476,9 +480,9 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { //ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "starting zigbee coordinator") ZI_SEND(ZBS_STARTUPFROMAPP) // start coordinator ZI_WAIT_RECV(2000, ZBR_STARTUPFROMAPP) // wait for sync ack of command - ZI_WAIT_UNTIL_FUNC(10000, AREQ_STARTUPFROMAPP, &Z_ReceiveStateChange) // wait for async message that coordinator started + ZI_WAIT_UNTIL_FUNC(10000, AREQ_STARTUPFROMAPP, &ZNP_ReceiveStateChange) // wait for async message that coordinator started ZI_SEND(ZBS_GETDEVICEINFO) // GetDeviceInfo - ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &Z_ReceiveDeviceInfo) + ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &ZNP_ReceiveDeviceInfo) //ZI_WAIT_RECV(2000, ZBR_GETDEVICEINFO) // memorize info ZI_SEND(ZBS_ZDO_NODEDESCREQ) // Z_ZDO:nodeDescReq ZI_WAIT_RECV(1000, ZBR_ZDO_NODEDESCREQ) @@ -537,7 +541,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_WAIT_RECV(1000, ZBR_W_OK) // Now mark the device as ready, writing 0x55 in memory slot 0x0F00 ZI_SEND(ZBS_WNV_INITZNPHC) // Init NV ZNP Has Configured - ZI_WAIT_RECV_FUNC(1000, ZBR_WNV_INIT_OK, &Z_CheckNVWrite) + ZI_WAIT_RECV_FUNC(1000, ZBR_WNV_INIT_OK, &ZNP_CheckNVWrite) ZI_SEND(ZBS_WNV_ZNPHC) // Write NV ZNP Has Configured ZI_WAIT_RECV(1000, ZBR_WNV_OK) @@ -563,9 +567,9 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_WAIT_RECV(1000, ZBR_AF_REGISTER) ZI_SEND(ZBS_STARTUPFROMAPP) // start router ZI_WAIT_RECV(2000, ZBR_STARTUPFROMAPP) // wait for sync ack of command - ZI_WAIT_UNTIL_FUNC(0xFFFF, AREQ_STARTUPFROMAPP, &Z_ReceiveStateChange) // wait for async message that coordinator started + ZI_WAIT_UNTIL_FUNC(0xFFFF, AREQ_STARTUPFROMAPP, &ZNP_ReceiveStateChange) // wait for async message that coordinator started ZI_SEND(ZBS_GETDEVICEINFO) // GetDeviceInfo - ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &Z_ReceiveDeviceInfo) + ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &ZNP_ReceiveDeviceInfo) ZI_GOTO(ZIGBEE_LABEL_READY) ZI_LABEL(ZIGBEE_LABEL_FACT_RESET_ROUTER) // Factory reset for router @@ -585,7 +589,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { // Now mark the device as ready, writing 0x55 in memory slot 0x0F00 ZI_SEND(ZBS_WNV_INITZNPHC) // Init NV ZNP Has Configured - ZI_WAIT_RECV_FUNC(1000, ZBR_WNV_INIT_OK, &Z_CheckNVWrite) + ZI_WAIT_RECV_FUNC(1000, ZBR_WNV_INIT_OK, &ZNP_CheckNVWrite) ZI_SEND(ZBS_WNV_ZNPHC) // Write NV ZNP Has Configured ZI_WAIT_RECV(1000, ZBR_WNV_OK) @@ -632,11 +636,6 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { #ifdef USE_ZIGBEE_EZSP -// Update the relevant commands with Settings -void Z_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_panid, uint64_t zb_precfgkey_l, uint64_t zb_precfgkey_h) { -} - - // patterns for EZSP // wait for RSTACK, meaning the device booted @@ -666,8 +665,8 @@ ZBM(ZBR_SET_OK, EZSP_setConfigurationValue, 0x00 /*high*/, 0x00 /*ok*/) // 53 ZBM(ZBR_SET_OK2, 0x00, 0x00 /*high*/, 0x00 /*ok*/) // 000000 - TODO why does setting EZSP_CONFIG_PACKET_BUFFER_COUNT has a different response? // Read some configuration values -ZBM(ZBS_GET_APS_UNI, EZSP_getConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_APS_UNICAST_MESSAGE_COUNT) // 520003 -ZBM(ZBR_GET_OK, EZSP_getConfigurationValue, 0x00 /*high*/, 0x00 /*ok*/) // 5200 - followed by the value +// ZBM(ZBS_GET_APS_UNI, EZSP_getConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_APS_UNICAST_MESSAGE_COUNT) // 520003 +// ZBM(ZBR_GET_OK, EZSP_getConfigurationValue, 0x00 /*high*/, 0x00 /*ok*/) // 5200 - followed by the value // Add Endpoints ZBM(ZBS_ADD_ENDPOINT1, EZSP_addEndpoint, 0x00 /*high*/, 0x01 /*ep*/, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), @@ -697,7 +696,7 @@ ZBM(ZBR_SET_CONCENTRATOR, EZSP_setConcentrator, 0x00 /*high*/, 0x00 /*ok*/) // setInitialSecurityState #define EZ_SECURITY_MODE EMBER_TRUST_CENTER_GLOBAL_LINK_KEY | EMBER_PRECONFIGURED_NETWORK_KEY_MODE | EMBER_HAVE_NETWORK_KEY | EMBER_HAVE_PRECONFIGURED_KEY -ZBM(ZBS_SET_SECURITY, EZSP_setInitialSecurityState, 0x00 /*high*/, +ZBR(ZBS_SET_SECURITY, EZSP_setInitialSecurityState, 0x00 /*high*/, Z_B0(EZ_SECURITY_MODE), Z_B1(EZ_SECURITY_MODE), // preConfiguredKey 0x5A, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6C, 0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0x30, 0x39, // well known key "ZigBeeAlliance09" @@ -715,7 +714,7 @@ ZBM(ZBR_SET_SECURITY, EZSP_setInitialSecurityState, 0x00 /*high*/, 0x00 /*st ZBM(ZBS_SET_POLICY_00, EZSP_setPolicy, 0x00 /*high*/, EZSP_TRUST_CENTER_POLICY, EZSP_DECISION_ALLOW_JOINS | EZSP_DECISION_ALLOW_UNSECURED_REJOINS) // 55000003 ZBM(ZBS_SET_POLICY_02, EZSP_setPolicy, 0x00 /*high*/, EZSP_UNICAST_REPLIES_POLICY, - EZSP_HOST_WILL_NOT_SUPPLY_REPLY) // 550002210 + EZSP_HOST_WILL_NOT_SUPPLY_REPLY) // 55000220 ZBM(ZBS_SET_POLICY_03, EZSP_setPolicy, 0x00 /*high*/, EZSP_POLL_HANDLER_POLICY, EZSP_POLL_HANDLER_IGNORE) // 55000330 ZBM(ZBS_SET_POLICY_05, EZSP_setPolicy, 0x00 /*high*/, EZSP_TC_KEY_REQUEST_POLICY, @@ -724,12 +723,16 @@ ZBM(ZBS_SET_POLICY_06, EZSP_setPolicy, 0x00 /*high*/, EZSP_APP_KEY_REQUEST_PO EZSP_DENY_APP_KEY_REQUESTS) // 55000660 ZBM(ZBR_SET_POLICY_XX, EZSP_setPolicy, 0x00 /*high*/, 0x00 /*status*/) +// networkInit - restart the network from previous settings +ZBM(ZBS_NETWORK_INIT, EZSP_networkInit, 0x00 /*high*/, 0x00, 0x00) // 17000000 +ZBM(ZBR_NETWORK_INIT, EZSP_networkInit, 0x00 /*high*/, 0x00 /*status*/) // 170000 + // formNetwork - i.e. start zigbee network as coordinator -ZBM(ZBS_FORM_NETWORK, EZSP_formNetwork, 0x00 /*high*/, +ZBR(ZBS_FORM_NETWORK, EZSP_formNetwork, 0x00 /*high*/, Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID), Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID), Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID), - 20 /*radioTxPower*/, + USE_ZIGBEE_TXRADIO_DBM /*radioTxPower*/, USE_ZIGBEE_CHANNEL /*channel*/, EMBER_USE_MAC_ASSOCIATION, 0xFF,0xFF, /*nwkManagerId, unused*/ @@ -739,34 +742,103 @@ ZBM(ZBS_FORM_NETWORK, EZSP_formNetwork, 0x00 /*high*/, ZBM(ZBR_FORM_NETWORK, EZSP_formNetwork, 0x00 /*high*/, 0x00 /*status*/) // 1E0000 ZBM(ZBR_NETWORK_UP, EZSP_stackStatusHandler, 0x00 /*high*/, EMBER_NETWORK_UP) // 190090 +// leaveNetwork +ZBR(ZBS_LEAVE_NETWORK, EZSP_leaveNetwork, 0x00 /*high*/) // 2000 +ZBM(ZBR_LEAVE_NETWORK, EZSP_leaveNetwork, 0x00 /*high*/) // 2000, we don't care whether it succeeeded or the network was not up + // read configuration details ZBM(ZBS_GET_NETW_PARM, EZSP_getNetworkParameters, 0x00 /*high*/) // 2800 ZBM(ZBR_GET_NETW_PARM, EZSP_getNetworkParameters, 0x00 /*high*/, 0x00 /*ok*/) // 2800 +ZBR(ZBR_CHECK_NETW_PARM, EZSP_getNetworkParameters, 0x00 /*high*/, + 0x00 /*status*/, + EMBER_COORDINATOR /*0x01*/, + Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID), + Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID), + Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID), + USE_ZIGBEE_TXRADIO_DBM /*radioTxPower*/, + USE_ZIGBEE_CHANNEL /*channel*/, + ) // 2800... + ZBM(ZBS_GET_EUI64, EZSP_getEui64, 0x00 /*high*/) // 2600 ZBM(ZBR_GET_EUI64, EZSP_getEui64, 0x00 /*high*/) // 2600 ZBM(ZBS_GET_NODEID, EZSP_getNodeId, 0x00 /*high*/) // 2700 ZBM(ZBR_GET_NODEID, EZSP_getNodeId, 0x00 /*high*/) // 2700 +// getCurrentSecurityState +// TODO double check the security bitmask +ZBM(ZBS_GET_CURR_SEC, EZSP_getCurrentSecurityState, 0x00 /*high*/) // 6900 +ZBR(ZBR_GET_CURR_SEC, EZSP_getCurrentSecurityState, 0x00 /*high*/, + 0x00 /*status*/, + 0x7C, 0x00 /*Current Security Bitmask*/, + ) // 6900... + +/*********************************************************************************************\ + * Update the relevant commands with Settings +\*********************************************************************************************/ +// +void EZ_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_panid, uint64_t zb_precfgkey_l, uint64_t zb_precfgkey_h, uint8_t zb_txradio_dbm) { + uint8_t txradio = zb_txradio_dbm; + // restrict txradio to acceptable range, and use default otherwise + if (txradio == 0) { txradio = USE_ZIGBEE_TXRADIO_DBM; } + if (txradio > 20) { txradio = USE_ZIGBEE_TXRADIO_DBM; } + + ZBW(ZBS_SET_SECURITY, EZSP_setInitialSecurityState, 0x00 /*high*/, + Z_B0(EZ_SECURITY_MODE), Z_B1(EZ_SECURITY_MODE), + // preConfiguredKey + 0x5A, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6C, 0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0x30, 0x39, // well known key "ZigBeeAlliance09" + // networkKey + Z_B0(zb_precfgkey_l), Z_B1(zb_precfgkey_l), Z_B2(zb_precfgkey_l), Z_B3(zb_precfgkey_l), + Z_B4(zb_precfgkey_l), Z_B5(zb_precfgkey_l), Z_B6(zb_precfgkey_l), Z_B7(zb_precfgkey_l), + Z_B0(zb_precfgkey_h), Z_B1(zb_precfgkey_h), Z_B2(zb_precfgkey_h), Z_B3(zb_precfgkey_h), + Z_B4(zb_precfgkey_h), Z_B5(zb_precfgkey_h), Z_B6(zb_precfgkey_h), Z_B7(zb_precfgkey_h), + 0x00 /*sequence*/, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*trustcenter*/ + ) + + ZBW(ZBS_FORM_NETWORK, EZSP_formNetwork, 0x00 /*high*/, + Z_B0(zb_ext_panid), Z_B1(zb_ext_panid), Z_B2(zb_ext_panid), Z_B3(zb_ext_panid), + Z_B4(zb_ext_panid), Z_B5(zb_ext_panid), Z_B6(zb_ext_panid), Z_B7(zb_ext_panid), + Z_B0(zb_pan_id), Z_B1(zb_pan_id), + txradio /*radioTxPower*/, + zb_channel /*channel*/, + EMBER_USE_MAC_ASSOCIATION, + 0xFF,0xFF, /*nwkManagerId, unused*/ + 0x00, /*nwkUpdateId, unused*/ + 0x00,0x00,0x00,0x00, /*NWK channel mask, unused*/ + ) // 1E00... + +ZBW(ZBR_CHECK_NETW_PARM, EZSP_getNetworkParameters, 0x00 /*high*/, + 0x00 /*status*/, + EMBER_COORDINATOR /*0x01*/, + Z_B0(zb_ext_panid), Z_B1(zb_ext_panid), Z_B2(zb_ext_panid), Z_B3(zb_ext_panid), + Z_B4(zb_ext_panid), Z_B5(zb_ext_panid), Z_B6(zb_ext_panid), Z_B7(zb_ext_panid), + Z_B0(zb_pan_id), Z_B1(zb_pan_id), + txradio /*radioTxPower*/, + zb_channel /*channel*/, + ) // 2800... +} static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_LABEL(0) ZI_NOOP() + ZI_CALL(EZ_Set_ResetConfig, 0) // for the firt pass, don't do a reset_config + ZI_LABEL(ZIGBEE_LABEL_RESTART) ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) - ZI_ON_RECV_UNEXPECTED(&Z_Recv_Default) + ZI_ON_RECV_UNEXPECTED(&EZ_Recv_Default) ZI_WAIT(10500) // wait for 10 seconds for Tasmota to stabilize // Hardware reset ZI_LOG(LOG_LEVEL_INFO, kResettingDevice) // Log Debug: resetting EZSP device - ZI_CALL(&Z_Reset_Device, 0) // LOW = reset + ZI_CALL(&EZ_Reset_Device, 0) // LOW = reset ZI_WAIT(100) // wait for .1 second - ZI_CALL(&Z_Reset_Device, 1) // HIGH = release reset + ZI_CALL(&EZ_Reset_Device, 1) // HIGH = release reset // wait for device to start ZI_WAIT_UNTIL(5000, ZBR_RSTACK) // wait for RSTACK message // Init device and probe version - ZI_SEND(ZBS_VERSION) ZI_WAIT_RECV_FUNC(1000, ZBR_VERSION, &Z_ReceiveCheckVersion) // check EXT PAN ID + ZI_SEND(ZBS_VERSION) ZI_WAIT_RECV_FUNC(1000, ZBR_VERSION, &EZ_ReceiveCheckVersion) // check EXT PAN ID // configure EFR32 ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredCoord) @@ -786,7 +858,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { // read configuration // TODO - not sure it's useful - //ZI_SEND(ZBS_GET_APS_UNI) ZI_WAIT_RECV_FUNC(500, ZBR_GET_OK, &Z_ReadAPSUnicastMessage) + //ZI_SEND(ZBS_GET_APS_UNI) ZI_WAIT_RECV_FUNC(500, ZBR_GET_OK, &EZ_ReadAPSUnicastMessage) // add endpoint 0x01 and 0x0B ZI_SEND(ZBS_ADD_ENDPOINT1) ZI_WAIT_RECV(500, ZBR_ADD_ENDPOINT) @@ -796,21 +868,52 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_SEND(ZBS_SET_CONCENTRATOR) ZI_WAIT_RECV(500, ZBR_SET_CONCENTRATOR) // setInitialSecurityState - ZI_SEND(ZBS_SET_SECURITY) ZI_WAIT_RECV(500, ZBR_SET_SECURITY) ZI_SEND(ZBS_SET_POLICY_00) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX) ZI_SEND(ZBS_SET_POLICY_02) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX) ZI_SEND(ZBS_SET_POLICY_03) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX) ZI_SEND(ZBS_SET_POLICY_05) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX) ZI_SEND(ZBS_SET_POLICY_06) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX) + // set encryption keys + ZI_SEND(ZBS_SET_SECURITY) ZI_WAIT_RECV(500, ZBR_SET_SECURITY) + + // Decide whether we try 'networkInit()' to restore configuration, or create a new network + ZI_CALL(&EZ_GotoIfResetConfig, ZIGBEE_LABEL_CONFIGURE_EZSP) // goto ZIGBEE_LABEL_CONFIGURE_EZSP if reset_config is set + + // ZI_GOTO(ZIGBEE_LABEL_CONFIGURE_EZSP) + + // // Try networkInit to restore settings, and check if network comes up + ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_BAD_CONFIG) // + ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_BAD_CONFIG) + ZI_SEND(ZBS_NETWORK_INIT) ZI_WAIT_RECV(500, ZBR_NETWORK_INIT) + ZI_WAIT_RECV(1500, ZBR_NETWORK_UP) // wait for network to start + // check if configuration is ok + ZI_SEND(ZBS_GET_CURR_SEC) ZI_WAIT_RECV(500, ZBR_GET_CURR_SEC) + ZI_SEND(ZBS_GET_NETW_PARM) ZI_WAIT_RECV(500, ZBR_CHECK_NETW_PARM) + // all ok, proceed to next step + ZI_GOTO(ZIGBEE_LABEL_NETWORK_CONFIGURED) + + ZI_LABEL(ZIGBEE_LABEL_BAD_CONFIG) + ZI_MQTT_STATE(ZIGBEE_STATUS_RESET_CONF, kResetting) + ZI_CALL(EZ_Set_ResetConfig, 1) // change mode to reset_config + ZI_GOTO(ZIGBEE_LABEL_RESTART) // restart state_machine + + ZI_LABEL(ZIGBEE_LABEL_CONFIGURE_EZSP) + // Set back normal error handlers + ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) + ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) // formNetwork ZI_SEND(ZBS_FORM_NETWORK) ZI_WAIT_RECV(500, ZBR_FORM_NETWORK) ZI_WAIT_RECV(5000, ZBR_NETWORK_UP) // wait for network to start + ZI_LABEL(ZIGBEE_LABEL_NETWORK_CONFIGURED) + // Set back normal error handlers + ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) + ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) // Query device information - ZI_SEND(ZBS_GET_EUI64) ZI_WAIT_RECV_FUNC(500, ZBR_GET_EUI64, &Z_EZSPGetEUI64) - ZI_SEND(ZBS_GET_NODEID) ZI_WAIT_RECV_FUNC(500, ZBR_GET_NODEID, &Z_EZSPGetNodeId) - ZI_SEND(ZBS_GET_NETW_PARM) ZI_WAIT_RECV_FUNC(500, ZBR_GET_NETW_PARM, &Z_EZSPNetworkParameters) + ZI_SEND(ZBS_GET_EUI64) ZI_WAIT_RECV_FUNC(500, ZBR_GET_EUI64, &EZ_GetEUI64) + ZI_SEND(ZBS_GET_NODEID) ZI_WAIT_RECV_FUNC(500, ZBR_GET_NODEID, &EZ_GetNodeId) + ZI_SEND(ZBS_GET_NETW_PARM) ZI_WAIT_RECV_FUNC(500, ZBR_GET_NETW_PARM, &EZ_NetworkParameters) ZI_LABEL(ZIGBEE_LABEL_READY) ZI_MQTT_STATE(ZIGBEE_STATUS_OK, kStarted) diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 870caaa7d..57313f687 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -24,8 +24,8 @@ * Parsers for incoming EZSP messages \*********************************************************************************************/ -// EZSP: received ASH RSTACK frame, indicating that the MCU finished boot -int32_t Z_EZSP_RSTACK(uint8_t reset_code) { +// EZSP: received ASH "RSTACK" frame, indicating that the MCU finished boot +int32_t EZ_RSTACK(uint8_t reset_code) { const char *reason_str; switch (reset_code) { @@ -47,8 +47,8 @@ int32_t Z_EZSP_RSTACK(uint8_t reset_code) { XdrvRulesProcess(); } -// EZSP: received ASH ERROR frame, indicating that the MCU finished boot -int32_t Z_EZSP_ERROR(uint8_t error_code) { +// EZSP: received ASH "ERROR" frame, indicating that the MCU finished boot +int32_t EZ_ERROR(uint8_t error_code) { const char *reason_str; switch (error_code) { @@ -64,13 +64,59 @@ int32_t Z_EZSP_ERROR(uint8_t error_code) { XdrvRulesProcess(); } -int32_t Z_ReadAPSUnicastMessage(int32_t res, class SBuffer &buf) { +int32_t EZ_ReadAPSUnicastMessage(int32_t res, class SBuffer &buf) { // Called when receiving a response from getConfigurationValue // Value is in bytes 2+3 uint16_t value = buf.get16(2); return res; } +/*********************************************************************************************\ + * Parsers for incoming EZSP messages +\*********************************************************************************************/ + +// +// Handle a "getEui64" incoming message +// +int32_t EZ_GetEUI64(int32_t res, class SBuffer &buf) { + localIEEEAddr = buf.get64(2); + return res; +} + +// +// Handle a "getEui64" incoming message +// +int32_t EZ_GetNodeId(int32_t res, class SBuffer &buf) { + localShortAddr = buf.get8(2); + return res; +} + +// +// Handle a "getNetworkParameters" incoming message +// +int32_t EZ_NetworkParameters(int32_t res, class SBuffer &buf) { + uint8_t node_type = buf.get8(3); + // ext panid: 4->11 + // panid: 12->13 + // radioTxPower: 14 + // radioChannel: 15 + + // Local short and long addresses are supposed to be already retrieved + // localIEEEAddr = long_adr; + // localShortAddr = short_adr; + + char hex[20]; + Uint64toHex(localIEEEAddr, hex, 64); + Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" + "\"Status\":%d,\"IEEEAddr\":\"0x%s\",\"ShortAddr\":\"0x%04X\"" + ",\"DeviceType\":%d}}"), + ZIGBEE_STATUS_EZ_INFO, hex, localShortAddr, node_type); + + MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); + XdrvRulesProcess(); + + return res; +} #endif // USE_ZIGBEE_EZSP @@ -128,7 +174,7 @@ int32_t Z_EZSPNetworkParameters(int32_t res, class SBuffer &buf) { // // Handle a "Receive Device Info" incoming message // -int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) { +int32_t ZNP_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) { // Ex= 6700.00.6263151D004B1200.0000.07.09.02.83869991 // IEEE Adr (8 bytes) = 0x00124B001D156362 // Short Addr (2 bytes) = 0x0000 @@ -174,7 +220,7 @@ int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) { return res; } -int32_t Z_CheckNVWrite(int32_t res, class SBuffer &buf) { +int32_t ZNP_CheckNVWrite(int32_t res, class SBuffer &buf) { // Check the status after NV Init "ZNP Has Configured" // Good response should be 610700 or 610709 (Success or Created) // We only filter the response on 6107 and check the code in this function @@ -186,7 +232,7 @@ int32_t Z_CheckNVWrite(int32_t res, class SBuffer &buf) { } } -int32_t Z_Reboot(int32_t res, class SBuffer &buf) { +int32_t ZNP_Reboot(int32_t res, class SBuffer &buf) { // print information about the reboot of device // 4180.02.02.00.02.06.03 // @@ -221,8 +267,8 @@ int32_t Z_Reboot(int32_t res, class SBuffer &buf) { } } -int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { #ifdef USE_ZIGBEE_ZNP +int32_t ZNP_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { // check that the version is supported // typical version for ZNP 1.2 // 61020200-02.06.03.D9143401.0200000000 @@ -251,9 +297,11 @@ int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { } else { return ZIGBEE_LABEL_UNSUPPORTED_VERSION; // abort } +} #endif // USE_ZIGBEE_ZNP #ifdef USE_ZIGBEE_EZSP +int32_t EZ_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { uint8_t protocol_version = buf.get8(2); uint8_t stack_type = buf.get8(3); uint16_t stack_version = buf.get16(4); @@ -278,9 +326,25 @@ int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { } else { return ZIGBEE_LABEL_UNSUPPORTED_VERSION; // abort } -#endif // USE_ZIGBEE_EZSP } +static bool EZ_reset_config = false; + +// Set or clear reset_config +int32_t EZ_Set_ResetConfig(uint8_t value) { + EZ_reset_config = value ? true : false; + return 0; +} +// checks if we need to reset the configuration of the device +// if reset_config == 0, continue +// if reset_config == 1, goto ZIGBEE_LABEL_CONFIGURE_EZSP +int32_t EZ_GotoIfResetConfig(uint8_t value) { + if (EZ_reset_config) { return ZIGBEE_LABEL_CONFIGURE_EZSP; } + else { return 0; } +} + +#endif // USE_ZIGBEE_EZSP + // checks the device type (coordinator, router, end-device) // If coordinator continue // If router goto ZIGBEE_LABEL_START_ROUTER @@ -308,7 +372,7 @@ bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match) { // // Handle Permit Join response // -int32_t Z_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) { +int32_t ZNP_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) { // we received a PermitJoin status change uint8_t duration = buf.get8(2); uint8_t status_code; @@ -335,7 +399,10 @@ int32_t Z_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) { return -1; } -int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) { +// +// ZNP only +// +int32_t ZNP_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) { // Received ZDO_NODE_DESC_RSP Z_ShortAddress srcAddr = buf.get16(2); uint8_t status = buf.get8(4); @@ -380,11 +447,19 @@ int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) { // int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) { // Received ZDO_ACTIVE_EP_RSP - Z_ShortAddress srcAddr = buf.get16(2); +#ifdef USE_ZIGBEE_ZNP + // Z_ShortAddress srcAddr = buf.get16(2); uint8_t status = buf.get8(4); Z_ShortAddress nwkAddr = buf.get16(5); uint8_t activeEpCount = buf.get8(7); uint8_t* activeEpList = (uint8_t*) buf.charptr(8); +#endif +#ifdef USE_ZIGBEE_EZSP + uint8_t status = buf.get8(0); + Z_ShortAddress nwkAddr = buf.get16(1); + uint8_t activeEpCount = buf.get8(3); + uint8_t* activeEpList = (uint8_t*) buf.charptr(4); +#endif for (uint32_t i = 0; i < activeEpCount; i++) { zigbee_devices.addEndpoint(nwkAddr, activeEpList[i]); @@ -409,12 +484,22 @@ int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) { // // Handle IEEEAddr incoming message // +// Same works for both ZNP and EZSP int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) { +#ifdef USE_ZIGBEE_ZNP uint8_t status = buf.get8(2); Z_IEEEAddress ieeeAddr = buf.get64(3); Z_ShortAddress nwkAddr = buf.get16(11); // uint8_t startIndex = buf.get8(13); // not used // uint8_t numAssocDev = buf.get8(14); +#endif // USE_ZIGBEE_ZNP +#ifdef USE_ZIGBEE_EZSP + uint8_t status = buf.get8(0); + Z_IEEEAddress ieeeAddr = buf.get64(1); + Z_ShortAddress nwkAddr = buf.get16(9); + // uint8_t numAssocDev = buf.get8(11); + // uint8_t startIndex = buf.get8(12); // not used +#endif // USE_ZIGBEE_EZSP if (0 == status) { // SUCCESS zigbee_devices.updateDevice(nwkAddr, ieeeAddr); @@ -439,7 +524,7 @@ int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) { // Report any AF_DATA_CONFIRM message // Ex: {"ZbConfirm":{"Endpoint":1,"Status":0,"StatusMessage":"SUCCESS"}} // -int32_t Z_DataConfirm(int32_t res, const class SBuffer &buf) { +int32_t ZNP_DataConfirm(int32_t res, const class SBuffer &buf) { uint8_t status = buf.get8(2); uint8_t endpoint = buf.get8(3); //uint8_t transId = buf.get8(4); // unused @@ -471,7 +556,7 @@ int32_t Z_DataConfirm(int32_t res, const class SBuffer &buf) { // 0x08: Starting as ZigBee Coordinator // 0x09: Started as ZigBee Coordinator // 0x0A: Device has lost information about its parent -int32_t Z_ReceiveStateChange(int32_t res, const class SBuffer &buf) { +int32_t ZNP_ReceiveStateChange(int32_t res, const class SBuffer &buf) { uint8_t state = buf.get8(2); const char * msg = nullptr; @@ -531,9 +616,9 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) { #endif #ifdef USE_ZIGBEE_EZSP // uint8_t seq = buf.get8(0); - Z_ShortAddress nwkAddr = buf.get16(1); - Z_IEEEAddress ieeeAddr = buf.get64(3); - uint8_t capabilities = buf.get8(11); + Z_ShortAddress nwkAddr = buf.get16(0); + Z_IEEEAddress ieeeAddr = buf.get64(2); + uint8_t capabilities = buf.get8(10); #endif zigbee_devices.updateDevice(nwkAddr, ieeeAddr); @@ -562,7 +647,7 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) { // Handle Receive TC Dev Ind incoming message // 45CA // -int32_t Z_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) { +int32_t ZNP_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) { Z_ShortAddress srcAddr = buf.get16(2); Z_IEEEAddress ieeeAddr = buf.get64(4); Z_ShortAddress parentNw = buf.get16(12); @@ -585,7 +670,7 @@ int32_t Z_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) { // // Handle Bind Rsp incoming message // -int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) { +int32_t ZNP_BindRsp(int32_t res, const class SBuffer &buf) { Z_ShortAddress nwkAddr = buf.get16(2); uint8_t status = buf.get8(4); @@ -608,7 +693,7 @@ int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) { // // Handle Unbind Rsp incoming message // -int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) { +int32_t ZNP_UnbindRsp(int32_t res, const class SBuffer &buf) { Z_ShortAddress nwkAddr = buf.get16(2); uint8_t status = buf.get8(4); @@ -629,7 +714,7 @@ int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) { // // Handle MgMt Bind Rsp incoming message // -int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) { +int32_t ZNP_MgmtBindRsp(int32_t res, const class SBuffer &buf) { uint16_t shortaddr = buf.get16(2); uint8_t status = buf.get8(4); uint8_t bind_total = buf.get8(5); @@ -667,7 +752,7 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) { dstep = buf.get8(idx + 20); idx += 21; } else { - //AddLog_P2(LOG_LEVEL_INFO, PSTR("Z_MgmtBindRsp unknwon address mode %d"), addrmode); + //AddLog_P2(LOG_LEVEL_INFO, PSTR("ZNP_MgmtBindRsp unknwon address mode %d"), addrmode); break; // abort for any other value since we don't know the length of the field } @@ -705,6 +790,9 @@ void Z_SendIEEEAddrReq(uint16_t shortaddr) { ZigbeeZNPSend(IEEEAddrReq, sizeof(IEEEAddrReq)); #endif +#ifdef USE_ZIGBEE_EZSP + // TODO +#endif } // @@ -725,17 +813,15 @@ void Z_SendActiveEpReq(uint16_t shortaddr) { // Send AF Info Request // void Z_SendAFInfoRequest(uint16_t shortaddr) { -#ifdef USE_ZIGBEE_ZNP uint8_t endpoint = zigbee_devices.findFirstEndpoint(shortaddr); if (0x00 == endpoint) { endpoint = 0x01; } // if we don't know the endpoint, try 0x01 uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr); - uint8_t AFInfoReq[] = { Z_SREQ | Z_AF, AF_DATA_REQUEST, Z_B0(shortaddr), Z_B1(shortaddr), endpoint, - 0x01, 0x00, 0x00, transacid, 0x30, 0x1E, 3 + 2*sizeof(uint16_t), - 0x00, transacid, ZCL_READ_ATTRIBUTES, 0x04, 0x00, 0x05, 0x00 - }; - ZigbeeZNPSend(AFInfoReq, sizeof(AFInfoReq)); -#endif + uint8_t InfoReq[] = { 0x04, 0x00, 0x05, 0x00 }; + + ZigbeeZCLSend_Raw(shortaddr, 0x0000 /*group*/, 0x0000 /*cluster*/, endpoint, ZCL_READ_ATTRIBUTES, + false /*clusterSpecific*/, 0x0000 /*manuf*/, + InfoReq, sizeof(InfoReq), true /*needResponse*/, transacid); } @@ -773,8 +859,9 @@ int32_t EZ_ReceiveTCJoinHandler(int32_t res, const class SBuffer &buf) { #endif // USE_ZIGBEE_EZSP // -// Parse incoming ZCL message. This code is common to ZNP and EZSP +// Parse incoming ZCL message. // +// This code is common to ZNP and EZSP void Z_IncomingMessage(ZCLFrame &zcl_received) { uint16_t srcaddr = zcl_received.getSrcAddr(); uint16_t groupid = zcl_received.getGroupAddr(); @@ -862,9 +949,11 @@ void Z_IncomingMessage(ZCLFrame &zcl_received) { \*********************************************************************************************/ void EZ_SendZDO(uint16_t shortaddr, uint16_t cmd, const unsigned char *payload, size_t payload_len) { - SBuffer buf(payload_len + 20); + SBuffer buf(payload_len + 22); uint8_t seq = zigbee_devices.getNextSeqNumber(0x0000); + buf.add16(EZSP_sendUnicast); + buf.add8(EMBER_OUTGOING_DIRECT); // 00 buf.add16(shortaddr); // dest addr // ApsFrame @@ -880,6 +969,8 @@ void EZ_SendZDO(uint16_t shortaddr, uint16_t cmd, const unsigned char *payload, buf.add8(payload_len + 1); // insert seq number buf.add8(seq); buf.addBuffer(payload, payload_len); + + ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true); } /*********************************************************************************************\ @@ -907,10 +998,17 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) { if ((0x0000 == profileid) && (0x00 == srcendpoint)) { // ZDO request - SBuffer zdo_buf = buf.subBuffer(21, buf.get8(20)); + // Since ZDO messages start with a sequence number, we skip it + SBuffer zdo_buf = buf.subBuffer(22, buf.get8(20) - 1); switch (clusterid) { case ZDO_Device_annce: - Z_ReceiveEndDeviceAnnonce(res, zdo_buf); + return Z_ReceiveEndDeviceAnnonce(res, zdo_buf); + break; + case ZDO_Active_EP_rsp: + return Z_ReceiveActiveEp(res, zdo_buf); + break; + case ZDO_IEEE_addr_rsp: + return Z_ReceiveIEEEAddr(res, zdo_buf); break; } } else { @@ -928,7 +1026,7 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) { // // Callback for loading Zigbee configuration from Flash, called by the state machine // -int32_t Z_Reset_Device(uint8_t value) { +int32_t EZ_Reset_Device(uint8_t value) { // TODO - GPIO is hardwired to GPIO4 digitalWrite(4, value ? HIGH : LOW); return 0; // continue @@ -938,13 +1036,15 @@ int32_t Z_Reset_Device(uint8_t value) { * Default resolver \*********************************************************************************************/ -int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) { +int32_t EZ_Recv_Default(int32_t res, const class SBuffer &buf) { // Default message handler for new messages if (zigbee.init_phase) { // if still during initialization phase, ignore any unexpected message return -1; // ignore message } else { - switch (buf.get8(0)) { + uint16_t ezsp_command_index = buf.get16(0); + + switch (ezsp_command_index) { case EZSP_incomingMessageHandler: return EZ_IncomingMessage(res, buf); break; @@ -990,6 +1090,48 @@ int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t clu return 1; } +/*********************************************************************************************\ + * Global dispatcher for incoming messages +\*********************************************************************************************/ + +#ifdef USE_ZIGBEE_ZNP + +int32_t ZNP_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { + uint16_t groupid = buf.get16(2); + uint16_t clusterid = buf.get16(4); + uint16_t srcaddr = buf.get16(6); + uint8_t srcendpoint = buf.get8(8); + uint8_t dstendpoint = buf.get8(9); + uint8_t wasbroadcast = buf.get8(10); + uint8_t linkquality = buf.get8(11); + uint8_t securityuse = buf.get8(12); + // uint32_t timestamp = buf.get32(13); + uint8_t seqnumber = buf.get8(17); + + bool defer_attributes = false; // do we defer attributes reporting to coalesce + + ZCLFrame zcl_received = ZCLFrame::parseRawFrame(buf, 19, buf.get8(18), clusterid, groupid, + srcaddr, + srcendpoint, dstendpoint, wasbroadcast, + linkquality, securityuse, seqnumber); + // + Z_IncomingMessage(zcl_received); + + return -1; +} + +// +// Callback for loading Zigbee configuration from Flash, called by the state machine +// +int32_t Z_Reset_Device(uint8_t value) { + // TODO - GPIO is hardwired to GPIO4 + digitalWrite(4, value ? HIGH : LOW); + return 0; // continue +} + +#endif // USE_ZIGBEE_ZNP + + /*********************************************************************************************\ * Global dispatcher for incoming messages \*********************************************************************************************/ @@ -1022,45 +1164,31 @@ int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { // Structure for the Dispatcher callbacks table typedef struct Z_Dispatcher { - const uint8_t* match; + uint8_t match[2]; ZB_RecvMsgFunc func; } Z_Dispatcher; -// Ffilters based on ZNP frames -ZBM(AREQ_AF_DATA_CONFIRM, Z_AREQ | Z_AF, AF_DATA_CONFIRM) // 4480 -ZBM(AREQ_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481 -// ZBM(AREQ_STATE_CHANGE_IND, Z_AREQ | Z_ZDO, ZDO_STATE_CHANGE_IND) // 45C0 -ZBM(AREQ_END_DEVICE_ANNCE_IND, Z_AREQ | Z_ZDO, ZDO_END_DEVICE_ANNCE_IND) // 45C1 -ZBM(AREQ_END_DEVICE_TC_DEV_IND, Z_AREQ | Z_ZDO, ZDO_TC_DEV_IND) // 45CA -ZBM(AREQ_PERMITJOIN_OPEN_XX, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND ) // 45CB -ZBM(AREQ_ZDO_ACTIVEEPRSP, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP) // 4585 -ZBM(AREQ_ZDO_SIMPLEDESCRSP, Z_AREQ | Z_ZDO, ZDO_SIMPLE_DESC_RSP) // 4584 -ZBM(AREQ_ZDO_IEEE_ADDR_RSP, Z_AREQ | Z_ZDO, ZDO_IEEE_ADDR_RSP) // 4581 -ZBM(AREQ_ZDO_BIND_RSP, Z_AREQ | Z_ZDO, ZDO_BIND_RSP) // 45A1 -ZBM(AREQ_ZDO_UNBIND_RSP, Z_AREQ | Z_ZDO, ZDO_UNBIND_RSP) // 45A2 -ZBM(AREQ_ZDO_MGMT_BIND_RSP, Z_AREQ | Z_ZDO, ZDO_MGMT_BIND_RSP) // 45B3 - // Dispatcher callbacks table const Z_Dispatcher Z_DispatchTable[] PROGMEM = { - { AREQ_AF_DATA_CONFIRM, &Z_DataConfirm }, - { AREQ_AF_INCOMING_MESSAGE, &Z_ReceiveAfIncomingMessage }, - // { AREQ_STATE_CHANGE_IND, &Z_ReceiveStateChange }, - { AREQ_END_DEVICE_ANNCE_IND, &Z_ReceiveEndDeviceAnnonce }, - { AREQ_END_DEVICE_TC_DEV_IND, &Z_ReceiveTCDevInd }, - { AREQ_PERMITJOIN_OPEN_XX, &Z_ReceivePermitJoinStatus }, - { AREQ_ZDO_NODEDESCRSP, &Z_ReceiveNodeDesc }, - { AREQ_ZDO_ACTIVEEPRSP, &Z_ReceiveActiveEp }, - { AREQ_ZDO_IEEE_ADDR_RSP, &Z_ReceiveIEEEAddr }, - { AREQ_ZDO_BIND_RSP, &Z_BindRsp }, - { AREQ_ZDO_UNBIND_RSP, &Z_UnbindRsp }, - { AREQ_ZDO_MGMT_BIND_RSP, &Z_MgmtBindRsp }, + { { Z_AREQ | Z_AF, AF_DATA_CONFIRM }, &ZNP_DataConfirm }, // 4480 + { { Z_AREQ | Z_AF, AF_INCOMING_MSG }, &ZNP_ReceiveAfIncomingMessage }, // 4481 + // { { Z_AREQ | Z_ZDO, ZDO_STATE_CHANGE_IND }, &ZNP_ReceiveStateChange }, // 45C0 + { { Z_AREQ | Z_ZDO, ZDO_END_DEVICE_ANNCE_IND }, &Z_ReceiveEndDeviceAnnonce }, // 45C1 + { { Z_AREQ | Z_ZDO, ZDO_TC_DEV_IND }, &ZNP_ReceiveTCDevInd }, // 45CA + { { Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND }, &ZNP_ReceivePermitJoinStatus }, // 45CB + { { Z_AREQ | Z_ZDO, ZDO_NODE_DESC_RSP }, &ZNP_ReceiveNodeDesc }, // 4582 + { { Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP }, &Z_ReceiveActiveEp }, // 4585 + { { Z_AREQ | Z_ZDO, ZDO_IEEE_ADDR_RSP }, &Z_ReceiveIEEEAddr }, // 4581 + { { Z_AREQ | Z_ZDO, ZDO_BIND_RSP }, &ZNP_BindRsp }, // 45A1 + { { Z_AREQ | Z_ZDO, ZDO_UNBIND_RSP }, &ZNP_UnbindRsp }, // 45A2 + { { Z_AREQ | Z_ZDO, ZDO_MGMT_BIND_RSP }, &ZNP_MgmtBindRsp }, // 45B3 }; /*********************************************************************************************\ * Default resolver \*********************************************************************************************/ -int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) { +int32_t ZNP_Recv_Default(int32_t res, const class SBuffer &buf) { // Default message handler for new messages if (zigbee.init_phase) { // if still during initialization phase, ignore any unexpected message diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index 5fb60de56..75c33e387 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -542,7 +542,7 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) { // RSTACK // received just after boot, either because of Power up, hardware reset or RST - Z_EZSP_RSTACK(buf.get8(2)); + EZ_RSTACK(buf.get8(2)); EZSP_Serial.from_ack = 0; EZSP_Serial.to_ack = 0; @@ -555,7 +555,7 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) { } else if (control_byte == 0xC2) { // ERROR - Z_EZSP_ERROR(buf.get8(2)); + EZ_ERROR(buf.get8(2)); zigbee.active = false; // stop all zigbee activities } else { @@ -691,6 +691,38 @@ void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterI ZigbeeZNPSend(buf.getBuffer(), buf.len()); #endif // USE_ZIGBEE_ZNP + +#ifdef USE_ZIGBEE_EZSP + SBuffer buf(32+len); + + buf.add16(EZSP_sendUnicast); // 3400 + buf.add8(EMBER_OUTGOING_DIRECT); // 00 + buf.add16(shortaddr); // dest addr + // ApsFrame + buf.add16(Z_PROF_HA); // Home Automation profile + buf.add16(clusterId); // cluster + buf.add8(0x01); // srcEp + buf.add8(endpoint); // dstEp + buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame + buf.add16(groupaddr); // groupId + buf.add8(transacId); + // end of ApsFrame + buf.add8(0x01); // tag TODO + + buf.add8(3 + len + (manuf ? 2 : 0)); + buf.add8((needResponse ? 0x00 : 0x10) | (clusterSpecific ? 0x01 : 0x00) | (manuf ? 0x04 : 0x00)); // Frame Control Field + if (manuf) { + buf.add16(manuf); // add Manuf Id if not null + } + buf.add8(transacId); // Transaction Sequance Number + buf.add8(cmdId); + if (len > 0) { + buf.addBuffer(msg, len); // add the payload + } + + ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true); + +#endif // USE_ZIGBEE_EZSP } #endif // USE_ZIGBEE diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 1370db3cc..569f522fe 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -64,10 +64,16 @@ void ZigbeeInit(void) Settings.zb_precfgkey_h = USE_ZIGBEE_PRECFGKEY_H; Settings.zb_pan_id = USE_ZIGBEE_PANID; Settings.zb_channel = USE_ZIGBEE_CHANNEL; - Settings.zb_free_byte = 0; + Settings.zb_txradio_dbm = USE_ZIGBEE_TXRADIO_DBM; } + // update commands with the current settings - Z_UpdateConfig(Settings.zb_channel, Settings.zb_pan_id, Settings.zb_ext_panid, Settings.zb_precfgkey_l, Settings.zb_precfgkey_h); +#ifdef USE_ZIGBEE_ZNP + ZNP_UpdateConfig(Settings.zb_channel, Settings.zb_pan_id, Settings.zb_ext_panid, Settings.zb_precfgkey_l, Settings.zb_precfgkey_h); +#endif +#ifdef USE_ZIGBEE_EZSP + EZ_UpdateConfig(Settings.zb_channel, Settings.zb_pan_id, Settings.zb_ext_panid, Settings.zb_precfgkey_l, Settings.zb_precfgkey_h, Settings.zb_txradio_dbm); +#endif ZigbeeInitSerial(); } @@ -1018,6 +1024,7 @@ void CmndZbConfig(void) { uint64_t zb_ext_panid = Settings.zb_ext_panid; uint64_t zb_precfgkey_l = Settings.zb_precfgkey_l; uint64_t zb_precfgkey_h = Settings.zb_precfgkey_h; + uint8_t zb_txradio_dbm = Settings.zb_txradio_dbm; // if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } RemoveAllSpaces(XdrvMailbox.data); @@ -1043,18 +1050,23 @@ void CmndZbConfig(void) { // KeyH const JsonVariant &val_key_h = GetCaseInsensitive(json, PSTR("KeyH")); if (nullptr != &val_key_h) { zb_precfgkey_h = strtoull(val_key_h.as(), nullptr, 0); } + // TxRadio dBm + const JsonVariant &val_txradio = GetCaseInsensitive(json, PSTR("TxRadio")); + if (nullptr != &val_txradio) { zb_txradio_dbm = strToUInt(val_txradio); } // Check if a parameter was changed after all if ( (zb_channel != Settings.zb_channel) || (zb_pan_id != Settings.zb_pan_id) || (zb_ext_panid != Settings.zb_ext_panid) || (zb_precfgkey_l != Settings.zb_precfgkey_l) || - (zb_precfgkey_h != Settings.zb_precfgkey_h) ) { + (zb_precfgkey_h != Settings.zb_precfgkey_h) || + (zb_txradio_dbm != Settings.zb_txradio_dbm) ) { Settings.zb_channel = zb_channel; Settings.zb_pan_id = zb_pan_id; Settings.zb_ext_panid = zb_ext_panid; Settings.zb_precfgkey_l = zb_precfgkey_l; Settings.zb_precfgkey_h = zb_precfgkey_h; + Settings.zb_txradio_dbm = zb_txradio_dbm; restart_flag = 2; // save and reboot } } @@ -1074,10 +1086,12 @@ void CmndZbConfig(void) { ",\"ExtPanID\":\"%s\"" ",\"KeyL\":\"%s\"" ",\"KeyH\":\"%s\"" + ",\"TxRadio\":%d" "}}"), zb_channel, zb_pan_id, hex_ext_panid, - hex_precfgkey_l, hex_precfgkey_h); + hex_precfgkey_l, hex_precfgkey_h, + zb_txradio_dbm); } /*********************************************************************************************\