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)); } }