Zigbee Switch results in bootloop

I am using nrf52840-DK and trying to get the Zigbee Switch working.  This is just a plain zigbee switch with no bind to light.  However, this set attribute during init results in the bootloop

SET_ATTRIBUTE

The below code in switch_clusters_attr_init() which causes the issue. Removing this the zigbee device is registered successfully but does not update state

This code is at line 282 in the main.c (also attached here)

 	ZB_ZCL_SET_ATTRIBUTE(
 		ENDPOINT_INVOKED,
 		ZB_ZCL_CLUSTER_ID_ON_OFF,
 		ZB_ZCL_CLUSTER_SERVER_ROLE,
 		ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
 		(zb_uint8_t *)&on,
 		ZB_FALSE);

main.c

#include <zephyr/types.h>
#include <zephyr.h>
#include <device.h>
#include <soc.h>
#include <drivers/pwm.h>
#include <logging/log.h>
#include <dk_buttons_and_leds.h>
#include <settings/settings.h>

#include <zboss_api.h>
#include <zboss_api_addons.h>
#include <zb_mem_config_med.h>
#include <zigbee/zigbee_app_utils.h>
#include <zigbee/zigbee_error_handler.h>
#include <zigbee/zigbee_zcl_scenes.h>
#include <zb_nrf_platform.h>

/* Switch endpoint */
#define HA_SWITCH_ENDPOINT      12

/* Version of the application software (1 byte). */
#define SWITCH_INIT_BASIC_APP_VERSION     01

/* Version of the implementation of the Zigbee stack (1 byte). */
#define SWITCH_INIT_BASIC_STACK_VERSION   10

/* Version of the hardware of the device (1 byte). */
#define SWITCH_INIT_BASIC_HW_VERSION      11

/* Manufacturer name (32 bytes). */
#define SWITCH_INIT_BASIC_MANUF_NAME      "DongleNordic"

/* Model number assigned by manufacturer (32-bytes long string). */
#define SWITCH_INIT_BASIC_MODEL_ID        "DongleSwitch"

/* First 8 bytes specify the date of manufacturer of the device
 * in ISO 8601 format (YYYYMMDD). The rest (8 bytes) are manufacturer specific.
 */
#define SWITCH_INIT_BASIC_DATE_CODE       "202201207777"

/* Type of power sources available for the device.
 * For possible values see section 3.2.2.2.8 of ZCL specification.
 */
#define SWITCH_INIT_BASIC_POWER_SOURCE    ZB_ZCL_BASIC_POWER_SOURCE_BATTERY

/* Describes the physical location of the device (16 bytes).
 * May be modified during commisioning process.
 */
#define SWITCH_INIT_BASIC_LOCATION_DESC   "Home"

/* Describes the type of physical environment.
 * For possible values see section 3.2.2.2.10 of ZCL specification.
 */
#define SWITCH_INIT_BASIC_PH_ENV          ZB_ZCL_BASIC_ENV_UNSPECIFIED

#define TOGGLE_SWITCH					DK_BTN3_MSK

/* Nordic PWM nodes don't have flags cells in their specifiers, so
 * this is just future-proofing.
 */
#define FLAGS_OR_ZERO(node) \
	COND_CODE_1(DT_PHA_HAS_CELL(node, pwms, flags), \
		    (DT_PWMS_FLAGS(node)), (0))


#ifndef ZB_ED_ROLE
#error Define ZB_END_DEVICE_ROLE to compile enddevice source code.
#endif

static void on_off_set_value(zb_bool_t on, zb_uint8_t endpoint_invoked);
static void switch_send_on_off(zb_bufid_t bufid, zb_uint16_t on_off);

LOG_MODULE_REGISTER(app);

/** 
 * Placeholder for the bulb context 
 * Stores all settings and static values.
 **/
typedef struct 
{
	zb_zcl_basic_attrs_ext_t         basic_attr;
	zb_zcl_identify_attrs_t          identify_attr;
	zb_zcl_scenes_attrs_t            scenes_attr;
	zb_zcl_groups_attrs_t            groups_attr;
	zb_zcl_on_off_attrs_t            on_off_attr;
} switch_device_ctx_t;
/* Zigbee device application context storage. */
static switch_device_ctx_t dev_ctx;

/////////// DECLARATION FOR FIRST ENDPOINT - START /////////////////////////////////////
ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(
	identify_attr_list,
	&dev_ctx.identify_attr.identify_time);

ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(
	basic_attr_list,
	&dev_ctx.basic_attr.zcl_version,
	&dev_ctx.basic_attr.app_version,
	&dev_ctx.basic_attr.stack_version,
	&dev_ctx.basic_attr.hw_version,
	dev_ctx.basic_attr.mf_name,
	dev_ctx.basic_attr.model_id,
	dev_ctx.basic_attr.date_code,
	&dev_ctx.basic_attr.power_source,
	dev_ctx.basic_attr.location_id,
	&dev_ctx.basic_attr.ph_env,
	dev_ctx.basic_attr.sw_ver);

/* On/Off cluster attributes additions data */
ZB_ZCL_DECLARE_ON_OFF_ATTRIB_LIST(
	on_off_attr_list,
	&dev_ctx.on_off_attr.on_off);

ZB_HA_DECLARE_ON_OFF_SWITCH_CLUSTER_LIST(
	switch_clusters,
	on_off_attr_list,
	basic_attr_list,
	identify_attr_list
);


ZB_HA_DECLARE_ON_OFF_SWITCH_EP(
	switch_ep,
	HA_SWITCH_ENDPOINT,
	switch_clusters);

/////////// DECLARATION FOR FIRST ENDPOINT - END /////////////////////////////////////

/**
 * Declares the context of single endpoint 
 * 
 **/
ZB_HA_DECLARE_ON_OFF_SWITCH_CTX(switch_ctx, switch_ep);

/**@brief Callback for button events.
 *
 * @param[in]   button_state  Bitmask containing buttons state.
 * @param[in]   has_changed   Bitmask containing buttons
 *                            that have changed their state.
 */
static void button_changed(uint32_t button_state, uint32_t has_changed)
{
	zb_ret_t zb_err_code;
	zb_uint16_t cmd_id;

    // user_input_indicate();
	/* Calculate bitmask of buttons that are pressed
	 * and have changed their state.
	 */
	uint32_t buttons = button_state & has_changed;

 	if (buttons & TOGGLE_SWITCH)
	{
		LOG_INF("Current LED setting is %d", dev_ctx.on_off_attr.on_off);

		if(dev_ctx.on_off_attr.on_off)
		{
			// on_off_set_value(ZB_FALSE, HA_BUTTON_ENDPOINT);
			cmd_id = ZB_ZCL_CMD_ON_OFF_ON_ID;
		}
		else
		{
			// on_off_set_value(ZB_TRUE, HA_BUTTON_ENDPOINT);
			cmd_id = ZB_ZCL_CMD_ON_OFF_OFF_ID;
		}

		zb_err_code = zb_buf_get_out_delayed_ext(switch_send_on_off, cmd_id, 0);
		ZB_ERROR_CHECK(zb_err_code);

		LOG_INF("Toggling Completed");
	}
}

/**@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);
	}
}

// /**
//  * Sets the respective LEDs ON or OFF depending upon the ENDPOINT INVOKED 
//  * @brief Function for turning ON/OFF the light bulb.
//  *
//  * @param[in]   on   Boolean light bulb state.
//  */
// static void on_off_set_value(zb_bool_t on, zb_uint8_t ENDPOINT_INVOKED)
// {
// 	LOG_INF("Set ON/OFF value: %i", on);

// 	ZB_ZCL_SET_ATTRIBUTE(
// 		ENDPOINT_INVOKED,
// 		ZB_ZCL_CLUSTER_ID_ON_OFF,
// 		ZB_ZCL_CLUSTER_SERVER_ROLE,
// 		ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
// 		(zb_uint8_t *)&on,
// 		ZB_FALSE);
// }

/**@brief Function for sending ON/OFF requests to the network / co-ordinator.
 *
 * @param[in]   bufid    Non-zero reference to Zigbee stack buffer that will be
 *                       used to construct on/off request.
 * @param[in]   cmd_id   ZCL command id.
 */
static void switch_send_on_off(zb_bufid_t bufid, zb_uint16_t cmd_id)
{
	LOG_INF("Send ON/OFF command: %d", cmd_id);
	zb_uint16_t coordinator_address = 0x0000;
	// switch_ctx.on_off_attr.on_off = (zb_bool_t)ZB_ZCL_ON_OFF_IS_ON;				

	// LOG_INF("Testpoint1:");
	// ZB_ZCL_SET_ATTRIBUTE(HA_BUTTON_ENDPOINT, 
	// 				ZB_ZCL_CLUSTER_ID_ON_OFF,    
	// 				ZB_ZCL_CLUSTER_SERVER_ROLE,  
	// 				ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
	// 				(zb_uint8_t *)&switch_ctx.on_off_attr.on_off,                     
	// 				ZB_FALSE);		
	LOG_INF("Testpoint2:");
	ZB_ZCL_ON_OFF_SEND_REQ(bufid,
				coordinator_address,
				ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
				HA_SWITCH_ENDPOINT,
				HA_SWITCH_ENDPOINT,
				ZB_AF_HA_PROFILE_ID,
				ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
				cmd_id,
				NULL);
	LOG_INF("Send ON/OFF command Completed: %d", cmd_id);
}

/**@brief Function for initializing all clusters attributes.
 */
static void switch_clusters_attr_init(void)
{
	/* Basic cluster attributes data */
	dev_ctx.basic_attr.zcl_version   = ZB_ZCL_VERSION;
	dev_ctx.basic_attr.app_version   = SWITCH_INIT_BASIC_APP_VERSION;
	dev_ctx.basic_attr.stack_version = SWITCH_INIT_BASIC_STACK_VERSION;
	dev_ctx.basic_attr.hw_version    = SWITCH_INIT_BASIC_HW_VERSION;

	/* Use ZB_ZCL_SET_STRING_VAL to set strings, because the first byte
	 * should contain string length without trailing zero.
	 *
	 * For example "test" string wil be encoded as:
	 *   [(0x4), 't', 'e', 's', 't']
	 */
	ZB_ZCL_SET_STRING_VAL(
		dev_ctx.basic_attr.mf_name,
		SWITCH_INIT_BASIC_MANUF_NAME,
		ZB_ZCL_STRING_CONST_SIZE(SWITCH_INIT_BASIC_MANUF_NAME));

	ZB_ZCL_SET_STRING_VAL(
		dev_ctx.basic_attr.model_id,
		SWITCH_INIT_BASIC_MODEL_ID,
		ZB_ZCL_STRING_CONST_SIZE(SWITCH_INIT_BASIC_MODEL_ID));

	ZB_ZCL_SET_STRING_VAL(
		dev_ctx.basic_attr.date_code,
		SWITCH_INIT_BASIC_DATE_CODE,
		ZB_ZCL_STRING_CONST_SIZE(SWITCH_INIT_BASIC_DATE_CODE));

	dev_ctx.basic_attr.power_source = SWITCH_INIT_BASIC_POWER_SOURCE;

	ZB_ZCL_SET_STRING_VAL(
		dev_ctx.basic_attr.location_id,
		SWITCH_INIT_BASIC_LOCATION_DESC,
		ZB_ZCL_STRING_CONST_SIZE(SWITCH_INIT_BASIC_LOCATION_DESC));

	dev_ctx.basic_attr.ph_env = SWITCH_INIT_BASIC_PH_ENV;

	/* Identify cluster attributes data. */
	dev_ctx.identify_attr.identify_time =
		ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;

	/* On/Off cluster attributes data. */
	dev_ctx.on_off_attr.on_off = ZB_FALSE;
	ZB_ZCL_SET_ATTRIBUTE(
		HA_SWITCH_ENDPOINT,
		ZB_ZCL_CLUSTER_ID_ON_OFF,
		ZB_ZCL_CLUSTER_SERVER_ROLE,
		ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
		(zb_uint8_t *)&dev_ctx.on_off_attr.on_off,
		ZB_FALSE);
}

/**@brief Callback function for handling ZCL commands.
 *
 * @param[in]   bufid   Reference to Zigbee stack buffer
 *                      used to pass received data.
 */
static void zcl_device_cb(zb_bufid_t bufid)
{
	zb_uint8_t cluster_id;
	zb_uint8_t attr_id;
	zb_uint8_t endpoint_invoked;	
	zb_zcl_device_callback_param_t  *device_cb_param =
		ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
	
	endpoint_invoked = device_cb_param->endpoint;

	LOG_INF("%s id %hd", __func__, device_cb_param->device_cb_id);

	LOG_INF("EndPoint Called is %d ", endpoint_invoked);

	/* Set default response value. */
	device_cb_param->status = RET_OK;
	LOG_INF("ZB Callback started %c", bufid);	

	switch (device_cb_param->device_cb_id) 
	{
		case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
			LOG_INF("Inside the ZB_ZCL_SET_ATTR_VALUE_CB_ID");
			cluster_id = device_cb_param->cb_param.set_attr_value_param.cluster_id;
			attr_id = device_cb_param->cb_param.set_attr_value_param.attr_id;

			if (cluster_id == ZB_ZCL_CLUSTER_ID_ON_OFF)
			{
				uint8_t value = device_cb_param->cb_param.set_attr_value_param.values.data8;

				LOG_INF("on/off attribute setting to %hd", value);
				if (attr_id == ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID) 
				{
					// on_off_set_value((zb_bool_t)value);
					//on_off_set_value((zb_bool_t)value, endpoint_invoked);
					LOG_INF("ON INVOKED:");
				}
			} 
			else 
			{
				/* Other clusters can be processed here */
				LOG_INF("Unhandled cluster attribute id: %d",
					cluster_id);
			}
			break;

		default:
			device_cb_param->status = RET_ERROR;
			break;
	}

	LOG_INF("%s status: %hd", __func__, device_cb_param->status);
}

/**@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)
{
	/* No application-specific behavior is required.
	 * Call default signal handler.
	 */
	ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));

	/* All callbacks should either reuse or free passed buffers.
	 * If bufid == 0, the buffer is invalid (not passed).
	 */
	if (bufid) {
		zb_buf_free(bufid);
	}
}

void error(void)
{
	while (true) {
		/* Spin forever */
		k_sleep(K_MSEC(1000));
	}
}

void main(void)
{
	int err;

	LOG_INF("Starting Zigbee Switch example");

	/* Initialize */
	configure_gpio();
	err = settings_subsys_init();
	if (err) {
		LOG_ERR("settings initialization failed");
	}

	LOG_INF("Registering Device");
	/* Register callback for handling ZCL commands. */
	ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);

	LOG_INF("Setting Switch Context");
	/* Register dimmer switch device context (all the endpoints). */
	ZB_AF_REGISTER_DEVICE_CTX(&switch_ctx);

	switch_clusters_attr_init();

	/* Initialize ZCL scene table */
	// zcl_scenes_init();

	LOG_INF("ZCL scenes initiated");

	/* Settings should be loaded after zcl_scenes_init */
	err = settings_load();
	if (err) {
		LOG_ERR("settings loading failed");
	}

	/* Start Zigbee default thread */
	zigbee_enable();

	LOG_INF("Zigbee Switch example started");

	while (1) {
		// k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
	}
}

Debug Terminal

Parents
  • Hi,

    From your main.c code, it looks like you started out with the light_bulb sample and modified it to work as a light switch. Is there any specific reasons you did not start out with the ready-made light_switch sample instead?

    The configuration of the light_bulb sample may not support the light_switch APIs you have added. Did you change any other configs in the sample?

    Best regards,
    Jørgen

  • Well, it is a combination of the both. I didn't start off with the light switch example because the code is written as a binding to a bulb, so the button click actually sends the command for the light bulb rather than the switch itself light_switch_send_on_off.

    However, if you can take a look at the main.c  can tell why this ZB_ZCL_SET_ATTRIBUTE might fail. I believe it is due to this pointer (zb_uint8_t *)&on  but during the debug it does have a value and in not null. but somehow the kernel still gets panicked and bootloops

Reply
  • Well, it is a combination of the both. I didn't start off with the light switch example because the code is written as a binding to a bulb, so the button click actually sends the command for the light bulb rather than the switch itself light_switch_send_on_off.

    However, if you can take a look at the main.c  can tell why this ZB_ZCL_SET_ATTRIBUTE might fail. I believe it is due to this pointer (zb_uint8_t *)&on  but during the debug it does have a value and in not null. but somehow the kernel still gets panicked and bootloops

Children
No Data
Related