This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

commanding 2-3 devices together using Zigbee coordinator

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

Parents
  • Hello,

    So when zb_buf_get_out_delayed_ext() returns something other than RET_OK, and you pass that return value into ZB_ERROR_CHECK() it will reset with this "fatal error" message.

    Try to rather check the return value. According to the declaration of zb_buf_get_out_delayed_ext() it can return either RET_OK or RET_OVERFLOW. Try something like this:

    ...
                zb_err_code = zb_buf_get_out_delayed_ext(light_switch_send_on_off, cmd_id, 0);
    			if (zb_err_code == RET_OVERFLOW)
    			{
    			    LOG_INF("not scheduled. Try again later...");
    			}
    			else
    			{
    			    ZB_ERROR_CHECK(zb_err_code);
    			}
    ...

    See if that helps.

    Best regards,

    Edvin

Reply
  • Hello,

    So when zb_buf_get_out_delayed_ext() returns something other than RET_OK, and you pass that return value into ZB_ERROR_CHECK() it will reset with this "fatal error" message.

    Try to rather check the return value. According to the declaration of zb_buf_get_out_delayed_ext() it can return either RET_OK or RET_OVERFLOW. Try something like this:

    ...
                zb_err_code = zb_buf_get_out_delayed_ext(light_switch_send_on_off, cmd_id, 0);
    			if (zb_err_code == RET_OVERFLOW)
    			{
    			    LOG_INF("not scheduled. Try again later...");
    			}
    			else
    			{
    			    ZB_ERROR_CHECK(zb_err_code);
    			}
    ...

    See if that helps.

    Best regards,

    Edvin

Children
No Data
Related