hi,
i m working to create a zigbee network using demo example of light bulb given in sample project of nrf5340dk.
as of now i am able to connect 2-3 bulb devices(i.e. zigbee routers) with single zigbee coordinator, now i am having issues with sending command using zigbee coordinator, when i send the command, it gives zigbee fatal error. as shown in the logs below. and system reset automatically.
if i connect only one zigbee bulb device , it works fine this same code.

/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
/** @file
* @brief Simple Zigbee network coordinator implementation
*/
#include <zephyr.h>
#include <device.h>
#include <logging/log.h>
#include <dk_buttons_and_leds.h>
#include <zboss_api.h>
#include <zb_mem_config_max.h>
#include <zigbee/zigbee_error_handler.h>
#include <zigbee/zigbee_app_utils.h>
#include <zb_nrf_platform.h>
#define RUN_STATUS_LED DK_LED1
#define RUN_LED_BLINK_INTERVAL 1000
/* Device endpoint, used to receive ZCL commands. */
#define ZIGBEE_COORDINATOR_ENDPOINT 10
/* Type of power sources available for the device.
* For possible values see section 3.2.2.2.8 of ZCL specification.
*/
#define COORDINATOR_INIT_BASIC_POWER_SOURCE ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE
/* LED indicating that device successfully joined Zigbee network. */
#define ZIGBEE_NETWORK_STATE_LED DK_LED3
/* LED used for device identification. */
#define IDENTIFY_LED DK_LED4
/* Button which reopens the Zigbee Network. */
#define KEY_ZIGBEE_NETWORK_REOPEN DK_BTN1_MSK
/* Button used to enter the Identify mode. */
#define IDENTIFY_MODE_BUTTON DK_BTN4_MSK
/* If set to ZB_TRUE then device will not open the network after forming or reboot. */
#define ZIGBEE_MANUAL_STEERING ZB_FALSE
#define ZIGBEE_PERMIT_LEGACY_DEVICES ZB_FALSE
#ifndef ZB_COORDINATOR_ROLE
#error Define ZB_COORDINATOR_ROLE to compile coordinator source code.
#endif
#define MATCH_DESC_REQ_ROLE ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE
/* Delay between the light switch startup and light bulb finding procedure. */
#define MATCH_DESC_REQ_START_DELAY K_SECONDS(2)
/* Timeout for finding procedure. */
#define MATCH_DESC_REQ_TIMEOUT K_SECONDS(5)
LOG_MODULE_REGISTER(app, LOG_LEVEL_INF);
/* Main application customizable context.
* Stores all settings and static values.
*/
uint16_t buf_addr[10];
static uint8_t count = 0;
struct bulb_context {
zb_uint8_t endpoint;
zb_uint16_t short_addr;
struct k_timer find_alarm;
};
static struct bulb_context bulb_ctx;
struct zb_device_ctx {
zb_zcl_basic_attrs_t basic_attr;
zb_zcl_identify_attrs_t identify_attr;
};
/* Zigbee device application context storage. */
static struct zb_device_ctx dev_ctx;
ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(
identify_attr_list,
&dev_ctx.identify_attr.identify_time);
ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(
basic_attr_list,
&dev_ctx.basic_attr.zcl_version,
&dev_ctx.basic_attr.power_source);
ZB_HA_DECLARE_RANGE_EXTENDER_CLUSTER_LIST(
nwk_coordinator_clusters,
basic_attr_list,
identify_attr_list);
ZB_HA_DECLARE_RANGE_EXTENDER_EP(
nwk_coordinator_ep,
ZIGBEE_COORDINATOR_ENDPOINT,
nwk_coordinator_clusters);
ZBOSS_DECLARE_DEVICE_CTX_1_EP(
nwk_coordinator,
nwk_coordinator_ep);
static void find_light_bulb_alarm(struct k_timer *timer);
static void find_light_bulb(zb_bufid_t bufid);
static void light_switch_send_on_off(zb_bufid_t bufid, zb_uint16_t on_off);
/**@brief Function for initializing all clusters attributes. */
static void app_clusters_attr_init(void)
{
/* Basic cluster attributes data. */
dev_ctx.basic_attr.zcl_version = ZB_ZCL_VERSION;
dev_ctx.basic_attr.power_source = COORDINATOR_INIT_BASIC_POWER_SOURCE;
/* Identify cluster attributes data. */
dev_ctx.identify_attr.identify_time = ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;
}
/**@brief Function to toggle the identify LED.
*
* @param bufid Unused parameter, required by ZBOSS scheduler API.
*/
static void toggle_identify_led(zb_bufid_t bufid)
{
static int blink_status;
dk_set_led(IDENTIFY_LED, (++blink_status) % 2);
ZB_SCHEDULE_APP_ALARM(toggle_identify_led, bufid, ZB_MILLISECONDS_TO_BEACON_INTERVAL(100));
}
/**@brief Function to handle identify notification events on the first endpoint.
*
* @param bufid Unused parameter, required by ZBOSS scheduler API.
*/
static void identify_cb(zb_bufid_t bufid)
{
zb_ret_t zb_err_code;
if (bufid) {
/* Schedule a self-scheduling function that will toggle the LED. */
ZB_SCHEDULE_APP_CALLBACK(toggle_identify_led, bufid);
} else {
/* Cancel the toggling function alarm and turn off LED. */
zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(toggle_identify_led, ZB_ALARM_ANY_PARAM);
ZVUNUSED(zb_err_code);
dk_set_led(IDENTIFY_LED, 0);
}
}
/**@brief Starts identifying the device.
*
* @param bufid Unused parameter, required by ZBOSS scheduler API.
*/
static void start_identifying(zb_bufid_t bufid)
{
zb_ret_t zb_err_code;
zb_uint16_t cmd_id;
ZVUNUSED(bufid);
/* Check if endpoint is in identifying mode,
* if not, put desired endpoint in identifying mode.
*/
if (dev_ctx.identify_attr.identify_time == ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE) {
LOG_INF("Enter identify mode");
zb_err_code = zb_bdb_finding_binding_target(ZIGBEE_COORDINATOR_ENDPOINT);
ZB_ERROR_CHECK(zb_err_code);
cmd_id = 0x00;
zb_err_code = zb_buf_get_out_delayed_ext(light_switch_send_on_off, cmd_id, 0);
ZB_ERROR_CHECK(zb_err_code);
} else {
LOG_INF("Cancel identify mode");
zb_bdb_finding_binding_target_cancel();
cmd_id = 0x01;
zb_err_code = zb_buf_get_out_delayed_ext(light_switch_send_on_off, cmd_id, 0);
ZB_ERROR_CHECK(zb_err_code);
}
}
/**@brief Callback used in order to visualise network steering period.
*
* @param[in] param Not used. Required by callback type definition.
*/
static void steering_finished(zb_uint8_t param)
{
ARG_UNUSED(param);
LOG_INF("Network steering finished");
dk_set_led_off(ZIGBEE_NETWORK_STATE_LED);
}
/**@brief Callback for button events.
*
* @param[in] button_state Bitmask containing buttons state.
* @param[in] has_changed Bitmask containing buttons that has changed their state.
*/
static void button_changed(uint32_t button_state, uint32_t has_changed)
{
/* Calculate bitmask of buttons that are pressed and have changed their state. */
uint32_t buttons = button_state & has_changed;
zb_bool_t comm_status;
if (buttons & KEY_ZIGBEE_NETWORK_REOPEN) {
(void)(ZB_SCHEDULE_APP_ALARM_CANCEL(steering_finished, ZB_ALARM_ANY_PARAM));
comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
if (comm_status) {
LOG_INF("Top level comissioning restated");
} else {
LOG_INF("Top level comissioning hasn't finished yet!");
}
} else if (buttons & IDENTIFY_MODE_BUTTON) {
ZB_SCHEDULE_APP_CALLBACK(start_identifying, 0);
}
}
/**@brief Function for initializing LEDs and Buttons. */
static void configure_gpio(void)
{
int err;
err = dk_buttons_init(button_changed);
if (err) {
LOG_ERR("Cannot init buttons (err: %d)", err);
}
err = dk_leds_init();
if (err) {
LOG_ERR("Cannot init LEDs (err: %d)", err);
}
}
/**@brief Zigbee stack event handler.
*
* @param[in] bufid Reference to the Zigbee stack buffer used to pass signal.
*/
void zboss_signal_handler(zb_bufid_t bufid)
{
/* Read signal description out of memory buffer. */
zb_zdo_app_signal_hdr_t *sg_p = NULL;
zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, &sg_p);
zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
zb_ret_t zb_err_code;
zb_bool_t comm_status;
zb_time_t timeout_bi;
switch (sig) {
case ZB_BDB_SIGNAL_DEVICE_REBOOT:
/* BDB initialization completed after device reboot,
* use NVRAM contents during initialization.
* Device joined/rejoined and started.
*/
if (status == RET_OK) {
if (ZIGBEE_MANUAL_STEERING == ZB_FALSE) {
LOG_INF("Start network steering");
comm_status = bdb_start_top_level_commissioning(
ZB_BDB_NETWORK_STEERING);
ZB_COMM_STATUS_CHECK(comm_status);
} else {
LOG_INF("Coordinator restarted successfully");
}
} else {
LOG_ERR("Failed to initialize Zigbee stack using NVRAM data (status: %d)",
status);
}
break;
case ZB_BDB_SIGNAL_STEERING:
if (status == RET_OK) {
if (ZIGBEE_PERMIT_LEGACY_DEVICES == ZB_TRUE) {
LOG_INF("Allow pre-Zigbee 3.0 devices to join the network");
zb_bdb_set_legacy_device_support(1);
}
/* Schedule an alarm to notify about the end of steering period.
*/
LOG_INF("Network steering started");
k_timer_start(&bulb_ctx.find_alarm,
MATCH_DESC_REQ_START_DELAY,
MATCH_DESC_REQ_TIMEOUT);
zb_err_code = ZB_SCHEDULE_APP_ALARM(
steering_finished, 0,
ZB_TIME_ONE_SECOND *
ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
ZB_ERROR_CHECK(zb_err_code);
}
break;
case ZB_ZDO_SIGNAL_DEVICE_ANNCE:
{
zb_zdo_signal_device_annce_params_t *dev_annce_params = ZB_ZDO_SIGNAL_GET_PARAMS(sg_p, zb_zdo_signal_device_annce_params_t);
LOG_INF("New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr);
zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(steering_finished, ZB_ALARM_ANY_PARAM);
if (zb_err_code == RET_OK)
{
LOG_INF("Joining period extended.");
zb_err_code = ZB_SCHEDULE_APP_ALARM(steering_finished, 0,ZB_TIME_ONE_SECOND *ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
ZB_ERROR_CHECK(zb_err_code);
}
} break;
default:
/* Call default signal handler. */
ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
break;
}
/* Update network status LED. */
if (ZB_JOINED() &&
(ZB_SCHEDULE_GET_ALARM_TIME(steering_finished, ZB_ALARM_ANY_PARAM,
&timeout_bi) == RET_OK)) {
dk_set_led_on(ZIGBEE_NETWORK_STATE_LED);
} else {
dk_set_led_off(ZIGBEE_NETWORK_STATE_LED);
}
/*
* All callbacks should either reuse or free passed buffers.
* If bufid == 0, the buffer is invalid (not passed).
*/
if (bufid) {
zb_buf_free(bufid);
}
}
static void alarm_timers_init(void)
{
k_timer_init(&bulb_ctx.find_alarm, find_light_bulb_alarm, NULL);
}
static void find_light_bulb_cb(zb_bufid_t bufid)
{
/* Get the beginning of the response. */
zb_zdo_match_desc_resp_t *resp =
(zb_zdo_match_desc_resp_t *) zb_buf_begin(bufid);
/* Get the pointer to the parameters buffer, which stores APS layer
* response.
*/
zb_apsde_data_indication_t *ind = ZB_BUF_GET_PARAM(bufid,
zb_apsde_data_indication_t);
zb_uint8_t *match_ep;
if ((resp->status == ZB_ZDP_STATUS_SUCCESS) &&
(resp->match_len > 0)) {
/* Match EP list follows right after response header. */
match_ep = (zb_uint8_t *)(resp + 1);
/* We are searching for exact cluster, so only 1 EP
* may be found.
*/
bulb_ctx.endpoint = *match_ep;
bulb_ctx.short_addr = ind->src_addr;
int isElementPresent = 0;
static uint8_t size = 0;
for(int i=0;i<10;i++)
{
if(buf_addr[i]==0)
{
size = i;
break;
}
}
//uint8_t size = sizeof(buf_addr);
//LOG_INF("size %d", size);
for (int i = 0; i <=size; i++)
{
if (buf_addr[i] == bulb_ctx.short_addr)
{
isElementPresent = 1;
break;
}
}
if (isElementPresent!=1)
{
count++;
buf_addr[size] = bulb_ctx.short_addr;
LOG_INF("Found bulb addr%d: %d ep: %d", count, bulb_ctx.short_addr, bulb_ctx.endpoint);
}
//k_timer_stop(&bulb_ctx.find_alarm);
//dk_set_led_on(BULB_FOUND_LED);
}
else {
//if()
//LOG_INF("Bulb not found, try again");
}
if (bufid) {
zb_buf_free(bufid);
}
}
static void find_light_bulb(zb_bufid_t bufid)
{
zb_zdo_match_desc_param_t *req;
/* Initialize pointers inside buffer and reserve space for
* zb_zdo_match_desc_param_t request.
*/
req = zb_buf_initial_alloc(bufid,
sizeof(zb_zdo_match_desc_param_t) + (1) * sizeof(zb_uint16_t));
req->nwk_addr = MATCH_DESC_REQ_ROLE;
req->addr_of_interest = MATCH_DESC_REQ_ROLE;
req->profile_id = ZB_AF_HA_PROFILE_ID;
/* We are searching for 2 clusters: On/Off and Level Control Server. */
req->num_in_clusters = 2;
req->num_out_clusters = 0;
req->cluster_list[0] = ZB_ZCL_CLUSTER_ID_ON_OFF;
req->cluster_list[1] = ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL;
/* Set 0xFFFF to reset short address in order to parse
* only one response.
*/
//bulb_ctx.short_addr = 0xFFFF;
(void)zb_zdo_match_desc_req(bufid, find_light_bulb_cb);
}
/**@brief Find bulb allarm handler.
*
* @param[in] timer Address of timer.
*/
static void find_light_bulb_alarm(struct k_timer *timer)
{
ZB_ERROR_CHECK(zb_buf_get_out_delayed(find_light_bulb));
}
static void light_switch_send_on_off(zb_bufid_t bufid, zb_uint16_t cmd_id)
{
static uint8_t length1 = 0;
for(int i=0;i<10;i++)
{
if(buf_addr[i]==0)
{
length1 = i;
break;
}
}
uint8_t i;
for(i=0;i<length1;i++)
{
LOG_INF("Send ON/OFF command: %d and device %d", cmd_id, i);
ZB_ZCL_ON_OFF_SEND_REQ(bufid,
buf_addr[i],
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
bulb_ctx.endpoint,
ZIGBEE_COORDINATOR_ENDPOINT,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
cmd_id,
NULL);
}
}
void main(void)
{
int blink_status = 0;
LOG_INF("Starting ZBOSS Coordinator example");
alarm_timers_init();
/* Initialize */
configure_gpio();
/* Register device context (endpoints). */
ZB_AF_REGISTER_DEVICE_CTX(&nwk_coordinator);
app_clusters_attr_init();
/* Register handlers to identify notifications. */
ZB_AF_SET_IDENTIFY_NOTIFICATION_HANDLER(ZIGBEE_COORDINATOR_ENDPOINT, identify_cb);
/* Start Zigbee default thread */
zigbee_enable();
LOG_INF("ZBOSS Coordinator example started");
while (1) {
dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
}
}