Zigbee fix cc2652 init and permitjoin

This commit is contained in:
Stephan Hadinger 2021-02-18 20:04:41 +01:00
parent 3c791ca9bb
commit 2503cb9d03
5 changed files with 128 additions and 64 deletions

View File

@ -901,7 +901,8 @@ enum Z_configuration {
CONF_NWKMGR_ADDR = 0x89,
CONF_ZDO_DIRECT_CB = 0x8F,
CONF_TCLK_TABLE_START = 0x0101,
ZNP_HAS_CONFIGURED = 0xF00
ZNP_HAS_CONFIGURED = 0xF00,
ZNP_HAS_CONFIGURED3 = 0x60, // different attribute address for ZStack 3
};
//

View File

@ -79,6 +79,7 @@ const uint8_t ZIGBEE_LABEL_START_ROUTER = 13; // Start ZNP as router
const uint8_t ZIGBEE_LABEL_INIT_DEVICE = 14; // Init ZNP as end-device
const uint8_t ZIGBEE_LABEL_START_DEVICE = 15; // Start ZNP as end-device
const uint8_t ZIGBEE_LABEL_START_ROUTER_DEVICE = 16; // Start common to router and device
const uint8_t ZIGBEE_LABEL_ZB3_INIT = 17; // check parameters for ZB3
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
@ -113,6 +114,11 @@ public:
bool recv_until = false; // ignore all messages until the received frame fully matches
bool eeprom_present = false; // is the ZBBridge EEPROM present?
bool eeprom_ready = false; // is the ZBBridge EEPROM formatted and ready?
#ifdef USE_ZIGBEE_ZNP
bool zb3 = false; // true if ZStack 3.x, false if ZStack 1.2
#else
bool zb3 = true; // always ZB3 with EZSP
#endif // USE_ZIGBEE_ZNP
// Zigbee mapping
bool mapping_in_progress = false; // is there a mapping in progress
bool mapping_ready = false; // do we have mapping information ready
@ -131,11 +137,9 @@ public:
// Energy scan
int8_t energy[USE_ZIGBEE_CHANNEL_COUNT];
uint32_t permit_end_time = 0; // timestamp when permit join ends, with ZNP 1.2, it takes only 0 (off) and -1 (on)
#ifdef USE_ZIGBEE_EZSP
uint32_t permit_end_time = 0; // timestamp when permit join ends
uint16_t ezsp_version = 0;
#elif defined(USE_ZIGBEE_ZNP)
bool permit_end_time = false; // in ZNP mode it's only a boolean
#endif
#ifdef USE_ZIGBEE_EZSP

View File

@ -94,6 +94,7 @@ enum Zigbee_StateMachine_Instruction_Set {
#define ZI_STOP(x) { .i = { ZGB_INSTR_STOP, (x), 0x0000} },
#define ZI_CALL(f, x) { .i = { ZGB_INSTR_CALL, (x), 0x0000} }, { .p = (const void*)(f) },
// #define ZI_CALL2(f, x, y) { .i = { ZGB_INSTR_CALL, (x), (y)} }, { .p = (const void*)(f) },
#define ZI_LOG(x, m) { .i = { ZGB_INSTR_LOG, (x), 0x0000 } }, { .p = ((const void*)(m)) },
#define ZI_MQTT_STATE(x, m) { .i = { ZGB_INSTR_MQTT_STATE, (x), 0x0000 } }, { .p = ((const void*)(m)) },
#define ZI_ON_RECV_UNEXPECTED(f) { .i = { ZGB_ON_RECV_UNEXPECTED, 0x00, 0x0000} }, { .p = (const void*)(f) },
@ -149,7 +150,7 @@ ZBM(ZBS_VERSION, Z_SREQ | Z_SYS, SYS_VERSION ) // 2102 Z_SYS:versio
ZBM(ZBR_VERSION, Z_SRSP | Z_SYS, SYS_VERSION ) // 6102 Z_SYS:version
// Check if ZNP_HAS_CONFIGURED is set
ZBM(ZBS_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_READ, ZNP_HAS_CONFIGURED & 0xFF, ZNP_HAS_CONFIGURED >> 8, 0x00 /* offset */ ) // 2108000F00 - 6108000155
ZBR(ZBS_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_READ, ZNP_HAS_CONFIGURED & 0xFF, ZNP_HAS_CONFIGURED >> 8, 0x00 /* offset */ ) // 2108000F00 - 6108000155
ZBM(ZBR_ZNPHC, Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_SUCCESS, 0x01 /* len */, 0x55) // 6108000155
// If not set, the response is 61-08-02-00 = Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_INVALIDPARAMETER, 0x00 /* len */
@ -169,8 +170,16 @@ ZBR(ZBR_CHANN, Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_SUCCESS,
Z_B0(USE_ZIGBEE_CHANNEL_MASK), Z_B1(USE_ZIGBEE_CHANNEL_MASK), Z_B2(USE_ZIGBEE_CHANNEL_MASK), Z_B3(USE_ZIGBEE_CHANNEL_MASK),
) // 61080004xxxxxxxx
ZBM(ZBS_PFGK, Z_SREQ | Z_SYS, SYS_OSAL_NV_READ, CONF_PRECFGKEY,0x00, 0x00 ) // 2108620000
ZBR(ZBR_PFGK, Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_SUCCESS,
ZBM(ZBS_PFGK, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_PRECFGKEY ) // 260462
ZBR(ZBR_PFGK, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PRECFGKEY,
0x10 /* len */,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_l */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_h */
/*0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0D*/ ) // 660400621001030507090B0D0F00020406080A0C0D
ZBM(ZBS_PFGK3, Z_SREQ | Z_SYS, SYS_OSAL_NV_READ, CONF_PRECFGKEY,0x00, 0x00 ) // 2108620000
ZBR(ZBR_PFGK3, Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_SUCCESS,
0x10 /* len */,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_l */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_h */
@ -238,14 +247,14 @@ ZBM(ZBS_WNV_SECMODE, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, Z_B0(CONF_TCLK_TABLE_STA
// Write Z_ZDO Direct CB
ZBM(ZBS_W_ZDODCB, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, CONF_ZDO_DIRECT_CB,0x00, 0x00, 0x01 /* len */, 0x01 ) // 21098F00000101
// NV Init ZNP Has Configured
ZBM(ZBS_WNV_INITZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_ITEM_INIT, ZNP_HAS_CONFIGURED & 0xFF, ZNP_HAS_CONFIGURED >> 8,
ZBR(ZBS_WNV_INITZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_ITEM_INIT, ZNP_HAS_CONFIGURED & 0xFF, ZNP_HAS_CONFIGURED >> 8,
0x01, 0x00 /* InitLen 16 bits */, 0x01 /* len */, 0x00 ) // 2107000F01000100 - 610709
// Init succeeded
//ZBM(ZBR_WNV_INIT_OK, Z_SRSP | Z_SYS, SYS_OSAL_NV_ITEM_INIT, Z_CREATED ) // 610709 - NV Write
ZBM(ZBR_WNV_INIT_OK, Z_SRSP | Z_SYS, SYS_OSAL_NV_ITEM_INIT ) // 6107xx, Success if 610700 or 610709 - NV Write
// Write ZNP Has Configured
ZBM(ZBS_WNV_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, Z_B0(ZNP_HAS_CONFIGURED), Z_B1(ZNP_HAS_CONFIGURED),
ZBR(ZBS_WNV_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, Z_B0(ZNP_HAS_CONFIGURED), Z_B1(ZNP_HAS_CONFIGURED),
0x00 /* offset */, 0x01 /* len */, 0x55 ) // 2109000F000155 - 610900
// Z_ZDO:startupFromApp
ZBM(ZBS_STARTUPFROMAPP, Z_SREQ | Z_ZDO, ZDO_STARTUP_FROM_APP, 100, 0 /* delay */) // 25406400
@ -333,8 +342,17 @@ void ZNP_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_pa
0x04 /* len */,
Z_B0(zb_channel_mask), Z_B1(zb_channel_mask), Z_B2(zb_channel_mask), Z_B3(zb_channel_mask),
) // 61080004xxxxxxxx
ZBW(ZBR_PFGK, Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_SUCCESS,
// Zstack 1.2
ZBW(ZBR_PFGK, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PRECFGKEY,
0x10 /* len */,
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),
/*0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0D*/ ) // 660400621001030507090B0D0F00020406080A0C0D
// ZStack 3
ZBW(ZBR_PFGK3, Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_SUCCESS,
0x10 /* len */,
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),
@ -363,6 +381,17 @@ void ZNP_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_pa
) // 21096200001001030507090B0D0F00020406080A0C0D
}
// Update configuration for ZStack 3
void ZNP_UpdateZStack3(void) {
ZBW(ZBS_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_READ, ZNP_HAS_CONFIGURED3 & 0xFF, ZNP_HAS_CONFIGURED3 >> 8, 0x00 /* offset */ ) // 2108000F00 - 6108000155
ZBW(ZBS_WNV_INITZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_ITEM_INIT, ZNP_HAS_CONFIGURED3 & 0xFF, ZNP_HAS_CONFIGURED3 >> 8,
0x01, 0x00 /* InitLen 16 bits */, 0x01 /* len */, 0x00 ) // 2107000F01000100 - 610709
ZBW(ZBS_WNV_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, Z_B0(ZNP_HAS_CONFIGURED3), Z_B1(ZNP_HAS_CONFIGURED3),
0x00 /* offset */, 0x01 /* len */, 0x55 ) // 2109000F000155 - 610900
}
static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_LABEL(0)
ZI_NOOP()
@ -402,10 +431,17 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_WAIT_RECV(1000, ZBR_EXTPAN)
ZI_SEND(ZBS_CHANN) // check CHANNEL
ZI_WAIT_RECV(1000, ZBR_CHANN)
ZI_SEND(ZBS_PFGK) // check PFGK
ZI_WAIT_RECV(1000, ZBR_PFGK)
ZI_SEND(ZBS_PFGKEN) // check PFGKEN
ZI_WAIT_RECV(1000, ZBR_PFGKEN)
ZI_CALL(&Z_GotoZB3, ZIGBEE_LABEL_ZB3_INIT)
ZI_SEND(ZBS_PFGK) // check PFGK on ZB1.2
ZI_WAIT_RECV(1000, ZBR_PFGK)
ZI_GOTO(ZIGBEE_LABEL_START_COORD)
ZI_LABEL(ZIGBEE_LABEL_ZB3_INIT)
ZI_SEND(ZBS_PFGK3) // check PFGK on ZB3
ZI_WAIT_RECV(1000, ZBR_PFGK3)
//ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "zigbee configuration ok")
// all is good, we can start
@ -416,7 +452,7 @@ 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(5000, ZBR_STARTUPFROMAPP) // wait for sync ack of command
ZI_WAIT_UNTIL_FUNC(10000, AREQ_STARTUPFROMAPP, &ZNP_ReceiveStateChange) // wait for async message that coordinator started
ZI_WAIT_UNTIL_FUNC(20000, AREQ_STARTUPFROMAPP, &ZNP_ReceiveStateChange) // wait for async message that coordinator started, max 20s
ZI_SEND(ZBS_GETDEVICEINFO) // GetDeviceInfo
ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &ZNP_ReceiveDeviceInfo)
//ZI_WAIT_RECV(2000, ZBR_GETDEVICEINFO) // memorize info
@ -1027,6 +1063,7 @@ void ZigbeeStateMachine_Run(void) {
if (cur_ptr1) {
uint32_t res;
res = (*((ZB_Func)cur_ptr1))(cur_d8);
// res = (*((ZB_Func)cur_ptr1))(cur_d8, cur_d16);
if (res > 0) {
ZigbeeGotoLabel(res);
continue; // avoid incrementing PC after goto
@ -1170,4 +1207,15 @@ int32_t ZigbeeProcessInput(SBuffer &buf) {
return 0; // Fix GCC 10.1 warning
}
//
// Condiditional GOTO depending on ZB3 or not
// Take the branch if ZB3
int32_t Z_GotoZB3(uint8_t value) {
if (zigbee.zb3) {
return value; // take the branch
} else {
return 0; // continue
}
}
#endif // USE_ZIGBEE

View File

@ -227,15 +227,6 @@ int32_t EZ_PermitJoinRsp(int32_t res, const SBuffer &buf) {
return -1;
}
//
// Special case: EZSP does not send an event for PermitJoin end, so we generate a synthetic one
//
void Z_PermitJoinDisable(void) {
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":20,\"Message\":\"Pairing mode disabled\"}}"));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
}
//
// Received MessageSentHandler
//
@ -254,6 +245,14 @@ int32_t EZ_MessageSent(int32_t res, const SBuffer &buf) {
#endif // USE_ZIGBEE_EZSP
//
// Special case: EZSP does not send an event for PermitJoin end, so we generate a synthetic one
//
void Z_PermitJoinDisable(void) {
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":20,\"Message\":\"Pairing mode disabled\"}}"));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
}
/*********************************************************************************************\
* Handle auto-mapping
\*********************************************************************************************/
@ -427,6 +426,10 @@ int32_t ZNP_Reboot(int32_t res, SBuffer &buf) {
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
if ((0x02 == major_rel) && ((0x06 == minor_rel) || (0x07 == minor_rel))) {
if (0x07 == minor_rel) {
zigbee.zb3 = true; // we run Zigbee 3
ZNP_UpdateZStack3(); // update configuration for ZStack 3
}
return 0; // version 2.6.x and 2.7.x are ok
} else {
return ZIGBEE_LABEL_UNSUPPORTED_VERSION; // abort
@ -546,18 +549,18 @@ int32_t ZNP_ReceivePermitJoinStatus(int32_t res, const SBuffer &buf) {
uint8_t status_code;
const char* message;
if (0xFF == duration) {
if (!zigbee.zb3 && (0xFF == duration)) {
status_code = ZIGBEE_STATUS_PERMITJOIN_OPEN_XX;
message = PSTR("Enable Pairing mode until next boot");
zigbee.permit_end_time = true; // In ZNP mode, declare permitjoin open
zigbee.permit_end_time = -1; // In ZNP mode, declare permitjoin open
} else if (duration > 0) {
status_code = ZIGBEE_STATUS_PERMITJOIN_OPEN_60;
message = PSTR("Enable Pairing mode for %d seconds");
zigbee.permit_end_time = true; // In ZNP mode, declare permitjoin open
zigbee.permit_end_time = -1; // In ZNP mode, declare permitjoin open
} else {
status_code = ZIGBEE_STATUS_PERMITJOIN_CLOSE;
message = PSTR("Disable Pairing mode");
zigbee.permit_end_time = false; // In ZNP mode, declare permitjoin closed
zigbee.permit_end_time = 0; // In ZNP mode, declare permitjoin closed
}
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
"\"Status\":%d,\"Message\":\""),

View File

@ -1416,13 +1416,15 @@ void CmndZbPermitJoin(void) {
if (payload <= 0) {
duration = 0;
}
// ZNP Version
#ifdef USE_ZIGBEE_ZNP
if (99 == payload) {
if (zigbee.zb3) {
ResponseCmndChar_P(PSTR("Unlimited time not supported")); return;
}
duration = 0xFF; // unlimited time
}
// ZNP Version
#ifdef USE_ZIGBEE_ZNP
SBuffer buf(34);
buf.add8(Z_SREQ | Z_ZDO); // 25
buf.add8(ZDO_MGMT_PERMIT_JOIN_REQ); // 36
@ -1437,10 +1439,6 @@ void CmndZbPermitJoin(void) {
// EZSP VERSION
#ifdef USE_ZIGBEE_EZSP
if (99 == payload) {
ResponseCmndChar_P(PSTR("Unlimited time not supported")); return;
}
SBuffer buf(3);
buf.add16(EZSP_permitJoining);
buf.add8(duration);
@ -1451,17 +1449,20 @@ void CmndZbPermitJoin(void) {
buf.add8(duration);
buf.add8(0x01); // TC_Significance - This field shall always have a value of 1, indicating a request to change the Trust Center policy. If a frame is received with a value of 0, it shall be treated as having a value of 1.
EZ_SendZDO(0xFFFC, ZDO_Mgmt_Permit_Joining_req, buf.buf(), buf.len());
#endif // USE_ZIGBEE_EZSP
// Set Timer after the end of the period, and reset a non-expired previous timer
if (duration > 0) {
// Log pairing mode enabled
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":21,\"Message\":\"Pairing mode enabled\"}}"));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
zigbee.permit_end_time = millis() + duration * 1000;
} else {
zigbee.permit_end_time = millis();
if (zigbee.zb3) {
if (duration > 0) {
// Log pairing mode enabled
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":21,\"Message\":\"Pairing mode enabled\"}}"));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
zigbee.permit_end_time = millis() + duration * 1000;
} else {
zigbee.permit_end_time = millis();
}
if (0 == zigbee.permit_end_time) { zigbee.permit_end_time = 1; } // avoid very rare case where timer collides with timestamp equals to zero
}
#endif // USE_ZIGBEE_EZSP
ResponseCmndDone();
}
@ -1498,31 +1499,40 @@ void CmndZbEZSPListen(void) {
void ZigbeeGlowPermitJoinLight(void) {
static const uint16_t cycle_time = 1000; // cycle up and down in 1000 ms
static const uint16_t half_cycle_time = cycle_time / 2; // cycle up and down in 1000 ms
uint16_t led_power = 0; // turn led off
if (zigbee.permit_end_time) {
uint16_t led_power = 0; // turn led off
uint32_t millis_to_go = millis() - zigbee.permit_end_time;
uint32_t sub_second = millis_to_go % cycle_time;
if (sub_second <= half_cycle_time) {
led_power = changeUIntScale(sub_second, 0, half_cycle_time, 0, 1023);
} else {
led_power = changeUIntScale(sub_second, half_cycle_time, cycle_time, 1023, 0);
}
led_power = ledGamma10_10(led_power);
}
// change the led state
int led_pin = Pin(GPIO_LEDLNK);
if (led_pin >= 0) {
analogWrite(led_pin, TasmotaGlobal.ledlnk_inverted ? 1023 - led_power : led_power);
}
}
#endif // USE_ZIGBEE_EZSP
// check if the permitjoin timer has expired
void ZigbeePermitJoinUpdate(void) {
if (zigbee.zb3 && zigbee.permit_end_time) {
// permit join is ongoing
if (TimeReached(zigbee.permit_end_time)) {
zigbee.permit_end_time = 0; // disable timer
Z_PermitJoinDisable();
} else {
uint32_t millis_to_go = millis() - zigbee.permit_end_time;
uint32_t sub_second = millis_to_go % cycle_time;
if (sub_second <= half_cycle_time) {
led_power = changeUIntScale(sub_second, 0, half_cycle_time, 0, 1023);
} else {
led_power = changeUIntScale(sub_second, half_cycle_time, cycle_time, 1023, 0);
}
led_power = ledGamma10_10(led_power);
}
// change the led state
int led_pin = Pin(GPIO_LEDLNK);
if (led_pin >= 0) {
analogWrite(led_pin, TasmotaGlobal.ledlnk_inverted ? 1023 - led_power : led_power);
}
#ifdef USE_ZIGBEE_EZSP
ZigbeeGlowPermitJoinLight(); // update glowing light accordingly
#endif // USE_ZIGBEE_EZSP
}
}
#endif // USE_ZIGBEE_EZSP
//
// Command `ZbStatus`
@ -2144,9 +2154,7 @@ bool Xdrv23(uint8_t function)
if (ZigbeeSerial) {
ZigbeeInputLoop();
ZigbeeOutputLoop(); // send any outstanding data
#ifdef USE_ZIGBEE_EZSP
ZigbeeGlowPermitJoinLight();
#endif // USE_ZIGBEE_EZSP
ZigbeePermitJoinUpdate(); // timer for permit join
}
if (zigbee.state_machine) {
ZigbeeStateMachine_Run();