The nRF5 SDK for Thread and Zigbee provides several helper functions that are intended to facilitate the end user application implementation. They implement the default behavior of a Zigbee device and are used in the Zigbee examples in this SDK.
Zigbee default signal handler
The Zigbee default signal handler is a function called from the zboss_signal_handler() function that is mandatory for each application.
Because most of Zigbee devices behave in a similar way, zigbee_default_signal_handler() was introduced to provide a default logic to handle stack signals.
As a result, the minimal implementation of zboss_signal_handler includes only a call to the default signal handler:
{
zigbee_default_signal_handler(param);
}
With this call, the device will be able to join the Zigbee network.
In general, using the default signal handler is worth considering, because of the following reasons:
- It simplifies the application.
- It provides a default behavior for each signal, which reduces the risk that an application will break due to an unimplemented signal handler.
- It makes the application less sensitive to changes in the Zigbee stack commissioning API.
Apart from that, the default signal handler serves as a good starting point for a custom signal handler implementation.
Complete zboss_signal_handler implementation
In its complete implementation, the zboss_signal_handler
allows the application to control a broader set of basic functionalities, including joining, commissioning, and network formation.
There are in fact cases in which the default handler will not be sufficient and needs to be extended. For example, when the application wants to use the procedure of the initiator of finding & binding or use the production configuration feature.
If the application wants to change or extend the default behavior, use a switch-case statement and then the default signal handler inside the default case:
{
switch (sig)
{
if (status == RET_OK)
{
NRF_LOG_INFO("Joined network successfully");
}
else
{
NRF_LOG_INFO("Unable to join the network. Restart network steering.");
ZB_COMM_STATUS_CHECK(comm_status);
}
break;
default:
zigbee_default_signal_handler(param);
break;
}
if (param)
{
}
}
Zigbee stack startup without autostart
Whenever zigbee_default_signal_handler() is used, the stack should be started using a call to zboss_start_no_autostart():
The reason for this is that although the Zigbee stack provides some automatic initialization procedure with zboss_start(), the default signal handler requires the application to start the stack without those mechanisms.
Starting the stack with zboss_start_no_autostart() has the following advantages:
- It allows you to ensure better granularity in customizing the default procedure.
- You gain a better understanding of procedures executed by the stack, because all procedures specified by the Zigbee Base Device Behavior specification are explicitly started inside the default signal handler and generate a separate signal once finished.
Zigbee stack startup without autostart
When the stack is started through zboss_start_no_autostart(), the stack generates the following signals:
The reception of these signals determines the behavior of the default signal handler:
ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY signal handler
- Upon reception of ZB_ZDO_SIGNAL_SKIP_STARTUP signal, the default signal handler will perform the BDB initialization procedure, and then exit.
ZB_ZDO_SIGNAL_SKIP_STARTUP signal handler
- Note
- If you want to perform some actions before the stack attempts to join or rejoin the Zigbee network, you can overwrite this behavior by providing a custom ZB_ZDO_SIGNAL_SKIP_STARTUP signal handler implementation.
Zigbee Base Device Behavior initialization
Once the BDB initialization procedure is finished, depending on the data stored inside the Zigbee persistent storage, the stack will complete one of the following scenarios:
Both scenarios will cause different behavior of the the default signal handler.
New device scenario
For factory new devices, the default signal handler will:
Commissioned device scenario
For devices that have been already commissioned, the default handler will:
- Not perform additional actions if the device implements a coordinator role.
- This will keep the network closed for new Zigbee devices even if the coordinator is reset.
- Not perform additional actions if the device successfully rejoins Zigbee network.
- This will not open the network for new devices if one of existing devices is reset.
- Start the BDB network steering on routers and end devices, if they were not able to rejoin the Zigbee network on the first attempt. Once finished, the stack will generate the ZB_BDB_SIGNAL_STEERING signal, and continue to Zigbee network formation and commissioning.
Scenario for already commissioned devices (ZB_BDB_SIGNAL_DEVICE_REBOOT)
Zigbee network formation and commissioning
According to the logic implemented inside the default signal handler, the devices can either form a network or join an existing network:
- Coordinators will first form a network. Attempts to form the network will continue infinitely, with a one-second delay between each attempt.
Forming a network following the generation of ZB_BDB_SIGNAL_FORMATION
By default, after the successful network formation on the coordinator node, a single-permit join period of 180 seconds will be started, which will allow new Zigbee devices to join the network.
- Other devices will then join an existing network during this join period.
Forming a network following the generation of ZB_BDB_SIGNAL_STEERING
Zigbee stack sleep routines
The Zigbee stack provides the following mechanisms to reduce power consumption:
- On Zigbee end devices, routers and coordinators:
- The stack calls the nrf_pwr_mgmt_run API (through zb_osif_wait_for_event) if the Zigbee scheduler queue is empty.
- On Zigbee sleepy end devices:
- If there are no immediate callbacks scheduled through the Zigbee scheduler, the stack calls the nrf_pwr_mgmt_run API (through zb_osif_wait_for_event).
- If there are no delayed callbacks (alarms) scheduled for the next sleep_threshold period, the stack switches off all peripheral devices related to the Zigbee stack before calling the nrf_pwr_mgmt_run API.
On Zigbee sleepy end devices, the sleep_threshold period lasts approximately 15 ms by default and can be modified by using the zb_sleep_set_threshold API.
If the device implements a Zigbee sleepy end device, the ZB_COMMON_SIGNAL_CAN_SLEEP signal is generated whenever the device can be put into the deep sleep mode. This signal can also be handled using the Zigbee default signal handler. If so, it will allow the Zigbee stack to enter the deep sleep state.
If the default behavior is not applicable for the application, you can customize the sleep functionality by using the following options:
- Overwriting the zb_osif_go_idle weak function and implementing a custom logic for handling the stack idle state.
Implementing a custom logic for handling the stack idle state
- Overwriting the zb_nrf52840_sleep weak function and implementing a custom logic for putting the stack into the deep sleep mode.
- As part of this option, overwriting zb_nrf52840_periph_disable and zb_nrf52840_periph_enable weak functions to change the set of peripheral devices, whose power is managed by the Zigbee stack.
- The stack informs the application about the possibility to enter the deep sleep mode by generating ZB_COMMON_SIGNAL_CAN_SLEEP signal.
Implementing a custom logic for putting the stack into the deep sleep mode