This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Zigbee abort function called after some time

I implement basic Thermostat Zigbee device on top of FreeRTOS v10.0.0 with nRF Thread and Zigbee SDK in version v3.0.0

When there is no network to connect then after some time the ZBOSS stack crashes.

See the GDB backtrace:

#1  0x00004388 in zb_nrf52840_abort () at external_dependencies/nrf_thread_zigbee_sdk/external/zboss/osif/zb_nrf52840_common.c:154
#2  0x0000d544 in zb_address_get_pan_id ()
#3  0x0001652c in zb_nlme_network_discovery_confirm ()
#4  0x0001188e in zb_sched_loop_iteration ()
#5  0x00000b5e in drv_zigbee_task (params=<optimized out>) at ./drivers/src/drv_zigbee.c:645
#6  0x00002b38 in ?? ()

I can't figure out where the problem is. There is no stack overflow. I can't find any race condition which may cause this problem.

Could you help me? Slight smile

Parents Reply Children
  • Hi again.

    Our developers have look at your log file, but it does not contain any trace-related information.

    Can you please create a new log file with these settings for your project:

    • Change library to the one inside the <InstallFolder>\external\zboss\lib\debug folder
    • configure the NRF logger module sdk_config.h
    • Set the trace mask to 0xC48 and trace level to 3.

    Best regards,

    Andreas

  • /**
     * @file	drv_zigbee.c
     * @brief	This file implements ZigBee layer of the firmware
     * @author	Kacper Kowalski - [email protected]
     * @todo        Add macro to enable/disable debug mode for this driver.
     */
    #include "zb_error_handler.h"
    #include "zb_mem_config_min.h"
    #include "zb_zcl_thermostat.h"
    
    #include "config/user_config.h"
    #include "config/user_error_codes.h"
    #include "drivers/drv_device_controller.h"
    #include "drivers/drv_log.h"
    #include "drivers/drv_zigbee.h"
    #include "drivers/logic/zigbee_thermostat_converters.h"
    #include "drivers/src/drv_zigbee_defs.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_queue.h"
    
    #include "jungles_os_structs/os.h"
    
    // --------------------------------------------------------------------------------------------------------------------
    // DEFINITIIONS OF PRIVATE DATA TYPES
    // --------------------------------------------------------------------------------------------------------------------
    struct drv_zigbee_write_attr_resp_struct
    {
        zb_uint8_t status;
        zb_uint16_t attr_id;
    };
    
    struct drv_zigbee_cmd_info
    {
        zb_uint16_t addr;
        zb_uint8_t ep;
        zb_uint8_t seq_num;
    };
    
    // --------------------------------------------------------------------------------------------------------------------
    // GLOBAL CONFIGURATIONS
    // --------------------------------------------------------------------------------------------------------------------
    #define ERASE_PERSISTENT_CONFIG ZB_TRUE
    
    // --------------------------------------------------------------------------------------------------------------------
    // DECLARATIONS OF ZIGBEE LEVEL VARIABLES AND CONSTANTS
    // --------------------------------------------------------------------------------------------------------------------
    #define BEEBLINKER_INIT_BASIC_APP_VERSION DRV_ZIGBEE_BASIC_APP_VERSION
    
    //! Version of the implementation of the ZigBee stack (1 byte).
    #define BEEBLINKER_INIT_BASIC_STACK_VERSION 10
    
    #define BEEBLINKER_INIT_BASIC_HW_VERSION 01
    #define BEEBLINKER_INIT_BASIC_MANUF_NAME "Lerta"
    #define BEEBLINKER_INIT_BASIC_MODEL_ID "BeeBlinker"
    #define BEEBLINKER_INIT_BASIC_DATE_CODE "20190411"
    
    //! Type of power sources available for the device. For possible values see section 3.2.2.2.8 of ZCL specification.
    #define BEEBLINKER_INIT_BASIC_POWER_SOURCE ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE
    
    #define BEEBLINKER_INIT_BASIC_SW_BUILD_ID 1
    #define BEEBLINKER_ZB_ENDPOINT 1
    
    static lerta_device_basic_attrs_1_t basic_attrs;
    static lerta_device_thermostat_attrs_1_t thermostat_attrs;
    LERTA_ZB_ZCL_DECLARE_BASIC_ATTR_LIST_1(basic_attr_list, basic_attrs);
    LERTA_ZB_ZCL_DECLARE_THERMOSTAT_ATTR_LIST_1(thermostat_attr_list, thermostat_attrs);
    LERTA_ZB_HA_DECLARE_BEEBLINKER_CLUSTER_LIST_1(beeblinker_clusters, basic_attr_list, thermostat_attr_list);
    LERTA_ZB_HA_DECLARE_BEEBLINKER_EP_1(beeblinker_ep, BEEBLINKER_ZB_ENDPOINT, beeblinker_clusters);
    LERTA_ZB_HA_DECLARE_BEEBLINKER_CTX_1(beeblinker_ctx, beeblinker_ep);
    
    // --------------------------------------------------------------------------------------------------------------------
    // DECLARATIONS OF PRIVATE VARIABLES AND MACROS
    // --------------------------------------------------------------------------------------------------------------------
    #define DRV_ZIGBEE_LOG_INFO(...) USER_APP_LOG_INFO_FROM_TASK("DRV_ZIGBEE: " __VA_ARGS__)
    #define DRV_ZIGBEE_LOG_WARNING(...) USER_APP_LOG_WARNING_FROM_TASK("DRV_ZIGBEE: " __VA_ARGS__)
    #define DRV_ZIGBEE_LOG_ERROR(...) USER_APP_LOG_ERROR_FROM_TASK("DRV_ZIGBEE: " __VA_ARGS__)
    
    NRF_QUEUE_DEF(struct drv_zigbee_write_attr_resp_struct, m_write_attr_resp_queue, 8, NRF_QUEUE_MODE_NO_OVERFLOW);
    
    static os_recursive_mutex_t m_zigbee_mux;
    static enum drv_zigbee_device_err (*m_occupied_cooling_setpoint_update_clbk)(float temperature, unsigned timeout_ms);
    static enum drv_zigbee_device_err (*m_system_mode_update_clbk)(bool state, unsigned timeout_ms);
    
    static const char unknown_str[] = "unknown";
    
    static enum drv_zigbee_state m_state = DRV_ZIGBEE_STATE_UNKNOWN;
    static volatile bool m_factory_reset_performed;
    
    static void (*m_zigbee_state_changed_clbk)(enum drv_zigbee_state);
    
    // --------------------------------------------------------------------------------------------------------------------
    // DECLARATIONS OF PRIVATE FUNCTIONS AND PUBLIC OVERRIDES
    // --------------------------------------------------------------------------------------------------------------------
    static void drv_zigbee_leave_nwk(zb_uint8_t param);
    static zb_void_t drv_zigbee_retry_join(zb_uint8_t leave_type);
    static zb_void_t drv_zigbee_leave_and_join(zb_uint8_t param);
    static zb_void_t drv_zigbee_sleepy_device_setup(void);
    static void drv_zigbee_attr_init(void);
    static zb_uint8_t drv_zigbee_ep_handler(zb_uint8_t param);
    static bool drv_zigbee_is_thermostat_setpoint_raise_lower_command(const zb_zcl_parsed_hdr_t *cmd_info);
    static bool drv_zigbee_is_thermostat_write_attribute_command(const zb_zcl_parsed_hdr_t *cmd_info);
    static void drv_zigbee_thermostat_cmd_handle_setpoint_raise_lower(zb_buf_t *buf, const zb_zcl_parsed_hdr_t *cmd_info);
    static void drv_zigbee_thermostat_cmd_handle_write_attribute(zb_buf_t *const buf, const zb_zcl_parsed_hdr_t *cmd_info);
    static zb_uint8_t drv_zigbee_thermostat_handle_write_attribute_impl(const zb_zcl_write_attr_req_t *write_attr_req);
    static zb_uint8_t
    drv_zigbee_thermostat_handle_occupied_cooling_setpoint_write_attr(const zb_zcl_write_attr_req_t *write_attr_req);
    static zb_uint8_t drv_zigbee_thermostat_handle_system_mode_write_attr(const zb_zcl_write_attr_req_t *write_attr_req);
    static struct drv_zigbee_cmd_info drv_zigbee_get_sender_info(const zb_zcl_parsed_hdr_t *cmd_info);
    static void drv_zigbee_for_each_write_attr_record(zb_buf_t *buf,
                                                      void (*handler)(const zb_zcl_write_attr_req_t *const write_attr_req));
    static void
    drv_zigbee_handle_write_attribute_record_and_push_result_to_queue(const zb_zcl_write_attr_req_t *const write_attr_req);
    static bool drv_zigbee_is_all_results_in_queue_success();
    static void
    drv_zigbee_send_write_attr_resp_with_single_success_status_record(zb_buf_t *buf,
                                                                      const struct drv_zigbee_cmd_info *sender_info);
    static void drv_zigbee_send_write_attr_resp_with_failure_status_records_and_reset_queue(
        zb_buf_t *buf, const struct drv_zigbee_cmd_info *sender_info);
    static bool drv_zigbee_is_device_paired();
    static void drv_zigbee_change_state_and_call_callback_if_state_changed(enum drv_zigbee_state new_state);
    static void drv_zigbee_reboot_if_factory_reset_flag_is_set();
    static void drv_zigbee_handle_joining(zb_ret_t status);
    static void drv_zigbee_handle_leaving(zb_ret_t status, zb_zdo_app_signal_hdr_t *p_sg_p);
    
    // --------------------------------------------------------------------------------------------------------------------
    // DECLARATIONS OF CONVERSION FUNCTIONS
    // --------------------------------------------------------------------------------------------------------------------
    static const char *drv_zigbee_thermostat_attr_id_to_str(zb_uint16_t attr_id);
    static const char *drv_zigbee_zcl_status_to_str(zb_uint8_t status);
    static zb_uint8_t drv_zigbee_device_err_to_zcl_status(enum drv_zigbee_device_err err);
    
    /**
     * @defgroup ZbossStackOverrides Functions which override ZBOSS related functions.
     * @{
     */
    
    extern void zboss_signal_handler(zb_uint8_t param);
    
    /**
     * \brief Overwrites default ZBOSS implementation.
     *
     * As we are running FreeRTOS and this function can't handle going idle we must implement this function on our own
     * to overwrite the default behaviour which sleeps the MCU down.
     */
    extern zb_void_t zb_osif_go_idle(zb_void_t);
    
    /** @} */ // End of group ZbossStackOverrides Functions which override ZBOSS related functions.
    
    //! The task which handles the ZigBee stack.
    static void drv_zigbee_task(void *params);
    
    // --------------------------------------------------------------------------------------------------------------------
    // DEFINITIONS OF PUBLIC FUNCTIONS
    // --------------------------------------------------------------------------------------------------------------------
    ret_code_t drv_zigbee_init()
    {
        // TODO: more error code checks
    
        /* Set ZigBee stack logging level and traffic dump subsystem. */
        ZB_SET_TRACE_LEVEL(3);
        ZB_SET_TRACE_MASK(0x0C48);
        ZB_SET_TRAF_DUMP_ON();
    
        /* Initialize ZigBee stack. */
        ZB_INIT("beeblinker");
    
        zb_set_network_ed_role(ZB_TRANSCEIVER_ALL_CHANNELS_MASK);
        zb_set_nvram_erase_at_start(ERASE_PERSISTENT_CONFIG);
    
        zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
        zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
        drv_zigbee_sleepy_device_setup();
    
        ZB_AF_REGISTER_DEVICE_CTX(&beeblinker_ctx);
    
        ZB_AF_SET_ENDPOINT_HANDLER(BEEBLINKER_ZB_ENDPOINT, drv_zigbee_ep_handler);
    
        drv_zigbee_attr_init();
    
        m_zigbee_mux = os_recursive_mutex_create();
        if (m_zigbee_mux == (os_mutex_t)NULL)
            return USER_ERR_RTOS;
    
        if (os_task_create(drv_zigbee_task, "ZigBee", DRV_ZIGBEE_TASK_STACK_SIZE, NULL, DRV_ZIGBEE_TASK_PRIORITY, NULL) !=
            os_pass)
            return USER_ERR_RTOS;
    
        return NRF_SUCCESS;
    }
    
    ret_code_t drv_zigbee_update_local_temperature_attribute(float temperature, unsigned timeout_ms)
    {
        zb_uint16_t zcl_compliant_temperature = zigbee_thermostat_local_temperature_to_zcl_compliant(temperature);
        DRV_ZIGBEE_LOG_INFO("App: updating local temperature attribute to " NRF_LOG_FLOAT_MARKER " (ZCL compliant: 0x%04X)",
                            NRF_LOG_FLOAT(temperature),
                            zcl_compliant_temperature);
    
        if (os_recursive_mutex_take(m_zigbee_mux, timeout_ms) == os_false)
            return USER_ERR_RTOS;
    
        // Update the attribute's value and do not perform access check (the last argument).
        ZB_ZCL_SET_ATTRIBUTE(BEEBLINKER_ZB_ENDPOINT,
                             ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                             ZB_ZCL_CLUSTER_SERVER_ROLE,
                             ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID,
                             (zb_uint8_t *)&zcl_compliant_temperature,
                             ZB_FALSE);
    
        os_recursive_mutex_give(m_zigbee_mux);
    
        return NRF_SUCCESS;
    }
    
    void drv_zigbee_register_occupied_cooling_setpoint_update_clbk(enum drv_zigbee_device_err (*clbk)(float temperature,
                                                                                                      unsigned timeout_ms))
    {
        m_occupied_cooling_setpoint_update_clbk = clbk;
    }
    
    void drv_zigbee_register_system_mode_update_clbk(enum drv_zigbee_device_err (*clbk)(bool on_off_state,
                                                                                        unsigned timeout_ms))
    {
        m_system_mode_update_clbk = clbk;
    }
    
    void drv_zigbee_factory_reset()
    {
        os_recursive_mutex_take(m_zigbee_mux, os_no_timeout);
        DRV_ZIGBEE_LOG_INFO("Going to perform factory reset");
        m_factory_reset_performed = true;
        zb_bdb_reset_via_local_action(0);
        os_recursive_mutex_give(m_zigbee_mux);
    }
    
    void drv_zigbee_register_state_changed_callback(void (*clbk)(enum drv_zigbee_state new_state))
    {
        m_zigbee_state_changed_clbk = clbk;
    }
    
    zb_void_t zb_osif_go_idle(zb_void_t)
    {
        // Intentionally left empty.
    }
    
    // --------------------------------------------------------------------------------------------------------------------
    // DECLARATIONS OF PRIVATE FUNCTIONS AND PUBLIC OVERRIDES
    // --------------------------------------------------------------------------------------------------------------------
    static void drv_zigbee_leave_nwk(zb_uint8_t param)
    {
        zb_ret_t zb_err_code;
    
        /* We are going to leave */
        if (param)
        {
            zb_buf_t *p_buf = ZB_BUF_FROM_REF(param);
            zb_zdo_mgmt_leave_param_t *p_req_param;
    
            p_req_param = ZB_GET_BUF_PARAM(p_buf, zb_zdo_mgmt_leave_param_t);
            UNUSED_RETURN_VALUE(ZB_BZERO(p_req_param, sizeof(zb_zdo_mgmt_leave_param_t)));
    
            /* Set dst_addr == local address for local leave */
            p_req_param->dst_addr = ZB_PIBCACHE_NETWORK_ADDRESS();
            p_req_param->rejoin = ZB_FALSE;
            UNUSED_RETURN_VALUE(zdo_mgmt_leave_req(param, NULL));
        }
        else
        {
            zb_err_code = ZB_GET_OUT_BUF_DELAYED(drv_zigbee_leave_nwk);
            ZB_ERROR_CHECK(zb_err_code);
        }
    }
    
    static zb_void_t drv_zigbee_retry_join(zb_uint8_t leave_type)
    {
        zb_bool_t comm_status;
    
        if (leave_type == ZB_NWK_LEAVE_TYPE_RESET)
        {
            comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
            ZB_COMM_STATUS_CHECK(comm_status);
        }
    }
    
    static zb_void_t drv_zigbee_leave_and_join(zb_uint8_t param)
    {
        if (ZB_JOINED())
        {
            /* Leave network. Joining procedure will be initiated inisde ZigBee stack signal handler. */
            drv_zigbee_leave_nwk(param);
        }
        else
        {
            /* Already left network. Start joining procedure. */
            drv_zigbee_retry_join(ZB_NWK_LEAVE_TYPE_RESET);
    
            if (param)
            {
                ZB_FREE_BUF_BY_REF(param);
            }
        }
    }
    
    static zb_void_t drv_zigbee_sleepy_device_setup(void)
    {
        zb_set_rx_on_when_idle(ZB_FALSE);
    }
    
    static void drv_zigbee_attr_init(void)
    {
        /* Basic cluster attributes data */
        basic_attrs.zcl_version = ZB_ZCL_VERSION;
        basic_attrs.app_version = BEEBLINKER_INIT_BASIC_APP_VERSION;
        basic_attrs.stack_version = BEEBLINKER_INIT_BASIC_STACK_VERSION;
        basic_attrs.hw_version = BEEBLINKER_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(basic_attrs.manufacturer_name,
                              BEEBLINKER_INIT_BASIC_MANUF_NAME,
                              ZB_ZCL_STRING_CONST_SIZE(BEEBLINKER_INIT_BASIC_MANUF_NAME));
    
        ZB_ZCL_SET_STRING_VAL(
            basic_attrs.model_id, BEEBLINKER_INIT_BASIC_MODEL_ID, ZB_ZCL_STRING_CONST_SIZE(BEEBLINKER_INIT_BASIC_MODEL_ID));
    
        ZB_ZCL_SET_STRING_VAL(basic_attrs.date_code,
                              BEEBLINKER_INIT_BASIC_DATE_CODE,
                              ZB_ZCL_STRING_CONST_SIZE(BEEBLINKER_INIT_BASIC_DATE_CODE));
    
        basic_attrs.power_source = BEEBLINKER_INIT_BASIC_POWER_SOURCE;
        basic_attrs.sw_build_id = BEEBLINKER_INIT_BASIC_SW_BUILD_ID;
    
        /* Thermostat cluster attributes data */
        float occupied_cooling_setpoint_default_value = 22.0;
        uint16_t occupied_cooling_setpoint_default_value_zcl_compliant =
            zigbee_thermostat_local_temperature_to_zcl_compliant(occupied_cooling_setpoint_default_value);
        thermostat_attrs.occupied_cooling_setpoint = occupied_cooling_setpoint_default_value_zcl_compliant;
        thermostat_attrs.occupied_heating_setpoint = ZB_ZCL_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_DEFAULT_VALUE;
        thermostat_attrs.control_sequence_of_operation = ZB_ZCL_THERMOSTAT_CONTROL_SEQ_OF_OPERATION_COOLING_ONLY;
        thermostat_attrs.system_mode = ZB_ZCL_THERMOSTAT_SYSTEM_MODE_OFF;
    
        zb_uint16_t z = ZB_ZCL_THERMOSTAT_LOCAL_TEMPERATURE_INVALID;
        ZB_ZCL_SET_ATTRIBUTE(BEEBLINKER_ZB_ENDPOINT,
                             ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                             ZB_ZCL_CLUSTER_SERVER_ROLE,
                             ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID,
                             (zb_uint8_t *)&z,
                             ZB_FALSE);
    }
    
    void zboss_signal_handler(zb_uint8_t param)
    {
        zb_zdo_app_signal_hdr_t *p_sg_p = NULL;
        zb_zdo_app_signal_type_t sig = zb_get_app_signal(param, &p_sg_p);
        zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(param);
    
        switch (sig)
        {
        case ZB_BDB_SIGNAL_DEVICE_FIRST_START:
        case ZB_BDB_SIGNAL_DEVICE_REBOOT: drv_zigbee_handle_joining(status); break;
        case ZB_ZDO_SIGNAL_LEAVE: drv_zigbee_handle_leaving(status, p_sg_p); break;
        case ZB_COMMON_SIGNAL_CAN_SLEEP:
            // Normally you would call zb_sleep_now() here but we can't do it as we are running FreeRTOS.
            break;
        case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
            if (status != RET_OK)
                DRV_ZIGBEE_LOG_ERROR("Production config is not present or invalid");
            else
                DRV_ZIGBEE_LOG_INFO("Production config is ready");
            break;
        default:
            /* Unhandled signal. For more information see: zb_zdo_app_signal_type_e and zb_ret_e */
            DRV_ZIGBEE_LOG_INFO("Unhandled signal %d. Status: %d", sig, status);
            break;
        }
    
        if (param)
        {
            ZB_FREE_BUF_BY_REF(param);
        }
    }
    
    static zb_uint8_t drv_zigbee_ep_handler(zb_uint8_t param)
    {
        zb_buf_t *zcl_cmd_buf = (zb_buf_t *)ZB_BUF_FROM_REF(param);
        zb_zcl_parsed_hdr_t *cmd_info = ZB_GET_BUF_PARAM(zcl_cmd_buf, zb_zcl_parsed_hdr_t);
    
        if (drv_zigbee_is_thermostat_setpoint_raise_lower_command(cmd_info))
            drv_zigbee_thermostat_cmd_handle_setpoint_raise_lower(zcl_cmd_buf, cmd_info);
        else if (drv_zigbee_is_thermostat_write_attribute_command(cmd_info))
            drv_zigbee_thermostat_cmd_handle_write_attribute(zcl_cmd_buf, cmd_info);
        else
            // Let the ZBOSS stack handle the command as the command received is not any awaited command.
            return ZB_FALSE;
    
        // We handled the command so inform the ZBOSS stack that it must not do it.
        return ZB_TRUE;
    }
    
    static bool drv_zigbee_is_thermostat_setpoint_raise_lower_command(const zb_zcl_parsed_hdr_t *cmd_info)
    {
        return !cmd_info->is_common_command && cmd_info->cluster_id == ZB_ZCL_CLUSTER_ID_THERMOSTAT &&
               cmd_info->cmd_id == ZB_ZCL_CMD_THERMOSTAT_SETPOINT_RAISE_LOWER;
    }
    
    static bool drv_zigbee_is_thermostat_write_attribute_command(const zb_zcl_parsed_hdr_t *cmd_info)
    {
        return cmd_info->is_common_command && cmd_info->cluster_id == ZB_ZCL_CLUSTER_ID_THERMOSTAT &&
               cmd_info->cmd_id == ZB_ZCL_CMD_WRITE_ATTRIB;
    }
    
    static void drv_zigbee_thermostat_cmd_handle_setpoint_raise_lower(zb_buf_t *buf, const zb_zcl_parsed_hdr_t *cmd_info)
    {
        struct drv_zigbee_cmd_info sender_info = drv_zigbee_get_sender_info(cmd_info);
    
        // Reuse the buffer to send a response that we are not able to handle that command.
        ZB_ZCL_SEND_DEFAULT_RESP(buf,
                                 sender_info.addr,
                                 ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                                 sender_info.ep,
                                 BEEBLINKER_ZB_ENDPOINT,
                                 ZB_AF_HA_PROFILE_ID,
                                 ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                 sender_info.seq_num,
                                 ZB_ZCL_CMD_THERMOSTAT_SETPOINT_RAISE_LOWER,
                                 ZB_ZCL_STATUS_UNSUP_CLUST_CMD);
    
        DRV_ZIGBEE_LOG_INFO("Sending response to setpoint_raise_lower command: unsupported");
    }
    
    static void drv_zigbee_thermostat_cmd_handle_write_attribute(zb_buf_t *const buf, const zb_zcl_parsed_hdr_t *cmd_info)
    {
        struct drv_zigbee_cmd_info sender_info = drv_zigbee_get_sender_info(cmd_info);
    
        drv_zigbee_for_each_write_attr_record(buf, drv_zigbee_handle_write_attribute_record_and_push_result_to_queue);
    
        // Reuse the buffer to send the response.
        if (drv_zigbee_is_all_results_in_queue_success())
        {
            nrf_queue_reset(&m_write_attr_resp_queue);
    
            drv_zigbee_send_write_attr_resp_with_single_success_status_record(buf, &sender_info);
        }
        else
        {
            drv_zigbee_send_write_attr_resp_with_failure_status_records_and_reset_queue(buf, &sender_info);
        }
    }
    
    static struct drv_zigbee_cmd_info drv_zigbee_get_sender_info(const zb_zcl_parsed_hdr_t *cmd_info)
    {
        // Most probably the object on which the cmd_info pointer points occupies memory of the ZBOSS internal buffer.
        // This may be overwritten when the buffer is reused so it is good to use this function before putting data
        // to the buffer. To make it safe firstly obtain the data needed by the default response because they
        // may be overwritten on the call to ZB_ZCL_SEND_DEFAULT_RESP.
        struct drv_zigbee_cmd_info i = {.addr = cmd_info->addr_data.common_data.source.u.short_addr,
                                        .ep = cmd_info->addr_data.common_data.src_endpoint,
                                        .seq_num = cmd_info->seq_number};
        return i;
    }
    
    static void drv_zigbee_for_each_write_attr_record(zb_buf_t *buf,
                                                      void (*handler)(const zb_zcl_write_attr_req_t *const write_attr_req))
    {
        unsigned len = ZB_BUF_LEN(buf);
        zb_uint8_t *data_ptr = ZB_BUF_BEGIN(buf);
        zb_zcl_write_attr_req_t *write_attr_req;
        do
        {
            ZB_ZCL_GENERAL_GET_NEXT_WRITE_ATTR_REQ(data_ptr, len, write_attr_req);
            if (!write_attr_req)
                break;
            handler(write_attr_req);
    
        } while (true);
    }
    
    static void
    drv_zigbee_handle_write_attribute_record_and_push_result_to_queue(const zb_zcl_write_attr_req_t *const write_attr_req)
    {
        zb_uint8_t status = drv_zigbee_thermostat_handle_write_attribute_impl(write_attr_req);
    
        zb_uint16_t attr_id = write_attr_req->attr_id;
        struct drv_zigbee_write_attr_resp_struct write_attr_resp_data = {.attr_id = attr_id, .status = status};
        DRV_ZIGBEE_LOG_INFO("Handled write attribute command for attribute: %s, with status: %s",
                            drv_zigbee_thermostat_attr_id_to_str(attr_id),
                            drv_zigbee_zcl_status_to_str(status));
        nrf_queue_push(&m_write_attr_resp_queue, &write_attr_resp_data);
    }
    
    static zb_uint8_t drv_zigbee_thermostat_handle_write_attribute_impl(const zb_zcl_write_attr_req_t *write_attr_req)
    {
        switch (write_attr_req->attr_id)
        {
        case ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_COOLING_SETPOINT_ID:
            return drv_zigbee_thermostat_handle_occupied_cooling_setpoint_write_attr(write_attr_req);
        case ZB_ZCL_ATTR_THERMOSTAT_CONTROL_SEQUENCE_OF_OPERATION_ID: return ZB_ZCL_STATUS_READ_ONLY;
        case ZB_ZCL_ATTR_THERMOSTAT_SYSTEM_MODE_ID:
            return drv_zigbee_thermostat_handle_system_mode_write_attr(write_attr_req);
        default: return ZB_ZCL_STATUS_UNSUP_ATTRIB;
        }
    }
    
    static zb_uint8_t
    drv_zigbee_thermostat_handle_occupied_cooling_setpoint_write_attr(const zb_zcl_write_attr_req_t *write_attr_req)
    {
        if (m_occupied_cooling_setpoint_update_clbk == NULL)
            return ZB_ZCL_STATUS_NOT_FOUND;
    
        zb_uint16_t *zcl_compliant_temperature_ptr = (zb_uint16_t *)write_attr_req->attr_value;
        zb_uint16_t zcl_compliant_temperature = *zcl_compliant_temperature_ptr;
        float temperature = zigbee_thermostat_zcl_compliant_to_local_temperature(zcl_compliant_temperature);
    
        DRV_ZIGBEE_LOG_INFO("Update occupied_cooling_setpoint to: " NRF_LOG_FLOAT_MARKER, NRF_LOG_FLOAT(temperature));
    
        zb_uint8_t ret = drv_zigbee_device_err_to_zcl_status(
            m_occupied_cooling_setpoint_update_clbk(temperature, DRV_ZIGBEE_DEVICE_CALLBACK_TIMEOUT_MS));
    
        if (ret == ZB_ZCL_STATUS_SUCCESS)
        {
            thermostat_attrs.occupied_cooling_setpoint = zcl_compliant_temperature;
        }
    
        return ret;
    }
    
    static zb_uint8_t drv_zigbee_thermostat_handle_system_mode_write_attr(const zb_zcl_write_attr_req_t *write_attr_req)
    {
        if (m_system_mode_update_clbk == NULL)
            return ZB_ZCL_STATUS_NOT_FOUND;
    
        bool on_off_state;
        enum zb_zcl_thermostat_system_mode_e system_mode = write_attr_req->attr_value[0];
        if (system_mode == ZB_ZCL_THERMOSTAT_SYSTEM_MODE_OFF)
            on_off_state = false;
        else if (system_mode == ZB_ZCL_THERMOSTAT_SYSTEM_MODE_COOL)
            on_off_state = true;
        else
            return ZB_ZCL_STATUS_INVALID_VALUE;
    
        DRV_ZIGBEE_LOG_INFO("Update system_mode to: %s", on_off_state == true ? "on" : "off");
    
        zb_uint8_t ret = drv_zigbee_device_err_to_zcl_status(
            m_system_mode_update_clbk(on_off_state, DRV_ZIGBEE_DEVICE_CALLBACK_TIMEOUT_MS));
    
        if (ret == ZB_ZCL_STATUS_SUCCESS)
        {
            thermostat_attrs.system_mode = system_mode;
        }
    
        return ret;
    }
    
    static bool drv_zigbee_is_all_results_in_queue_success()
    {
        bool are_all_results_success = true;
    
        // Iterate over the whole queue. The items will be popped and pushed back so the whole queue must be
        // iterated over to keep the queue unchanged. The nrf_queue doesn't allow in its API to peek every element
        // so we must do it like that.
    
        // Get the number of the elements in the queue at the beginning as it will change when popping/pushing to the queue.
        for (unsigned num_elems = nrf_queue_utilization_get(&m_write_attr_resp_queue); num_elems; --num_elems)
        {
            struct drv_zigbee_write_attr_resp_struct write_attr_resp_data;
            nrf_queue_pop(&m_write_attr_resp_queue, &write_attr_resp_data);
            if (write_attr_resp_data.status != ZB_ZCL_STATUS_SUCCESS)
                are_all_results_success = false;
            // Keep the queue untouched
            nrf_queue_push(&m_write_attr_resp_queue, &write_attr_resp_data);
        }
        return are_all_results_success;
    }
    
    static void
    drv_zigbee_send_write_attr_resp_with_single_success_status_record(zb_buf_t *buf,
                                                                      const struct drv_zigbee_cmd_info *sender_info)
    {
        zb_uint8_t *cmd_ptr = NULL;
        ZB_ZCL_GENERAL_INIT_WRITE_ATTR_RESP(buf, cmd_ptr, sender_info->seq_num);
        ZB_ZCL_GENERAL_SUCCESS_WRITE_ATTR_RESP(cmd_ptr);
        ZB_ZCL_GENERAL_SEND_WRITE_ATTR_RESP(buf,
                                            cmd_ptr,
                                            sender_info->addr,
                                            ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                                            sender_info->ep,
                                            BEEBLINKER_ZB_ENDPOINT,
                                            ZB_AF_HA_PROFILE_ID,
                                            ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                            NULL);
    }
    
    static void drv_zigbee_send_write_attr_resp_with_failure_status_records_and_reset_queue(
        zb_buf_t *buf, const struct drv_zigbee_cmd_info *sender_info)
    {
    
        zb_uint8_t *cmd_ptr = NULL;
        struct drv_zigbee_write_attr_resp_struct write_attr_resp_data;
    
        ZB_ZCL_GENERAL_INIT_WRITE_ATTR_RESP(buf, cmd_ptr, sender_info->seq_num);
    
        // The queue is reset by popping all the elements.
        while (nrf_queue_pop(&m_write_attr_resp_queue, &write_attr_resp_data) == NRF_SUCCESS)
        {
            if (write_attr_resp_data.status != ZB_ZCL_STATUS_SUCCESS)
            {
                ZB_ZCL_GENERAL_ADD_STATUS_WRITE_ATTR_RESP(
                    buf, cmd_ptr, write_attr_resp_data.attr_id, write_attr_resp_data.status);
            }
        }
        ZB_ZCL_GENERAL_SEND_WRITE_ATTR_RESP(buf,
                                            cmd_ptr,
                                            sender_info->addr,
                                            ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                                            sender_info->ep,
                                            BEEBLINKER_ZB_ENDPOINT,
                                            ZB_AF_HA_PROFILE_ID,
                                            ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                            NULL);
    }
    
    static bool drv_zigbee_is_device_paired()
    {
        zb_ext_pan_id_t pan_id;
        zb_get_extended_pan_id(pan_id);
        zb_ext_pan_id_t empty_pan_id;
        memset(empty_pan_id, 0, sizeof(empty_pan_id));
        return memcmp(empty_pan_id, pan_id, sizeof(empty_pan_id)) != 0;
    }
    
    static void drv_zigbee_change_state_and_call_callback_if_state_changed(enum drv_zigbee_state new_state)
    {
        // Do nothing if the state is same
        if (new_state == m_state)
            return;
    
        m_state = new_state;
        if (m_zigbee_state_changed_clbk)
            m_zigbee_state_changed_clbk(new_state);
    }
    
    static void drv_zigbee_reboot_if_factory_reset_flag_is_set()
    {
        if (!m_factory_reset_performed)
            return;
    
        m_factory_reset_performed = false;
        drv_device_controller_reboot_device_from_task();
    }
    
    static void drv_zigbee_handle_joining(zb_ret_t status)
    {
        if (status == RET_OK)
        {
            DRV_ZIGBEE_LOG_INFO("Joined network successfully");
            drv_zigbee_change_state_and_call_callback_if_state_changed(DRV_ZIGBEE_STATE_PAIRED_AND_NETWORK_ON);
        }
        else
        {
            DRV_ZIGBEE_LOG_ERROR("Failed to join network. Status: %d", status);
            drv_zigbee_reboot_if_factory_reset_flag_is_set();
            bool is_paired = drv_zigbee_is_device_paired();
            drv_zigbee_change_state_and_call_callback_if_state_changed(is_paired ? DRV_ZIGBEE_STATE_PAIRED_AND_NETWORK_OFF
                                                                                 : DRV_ZIGBEE_STATE_NOT_PAIRED);
            drv_zigbee_leave_and_join(0);
        }
    }
    
    static void drv_zigbee_handle_leaving(zb_ret_t status, zb_zdo_app_signal_hdr_t *p_sg_p)
    {
        if (status == RET_OK)
        {
            zb_zdo_signal_leave_params_t *p_leave_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_leave_params_t);
            DRV_ZIGBEE_LOG_INFO("Network left. Leave type: %d", p_leave_params->leave_type);
            drv_zigbee_change_state_and_call_callback_if_state_changed(DRV_ZIGBEE_STATE_NOT_PAIRED);
            if (p_leave_params->leave_type == ZB_NWK_LEAVE_TYPE_RESET)
            {
                drv_zigbee_reboot_if_factory_reset_flag_is_set();
            }
            drv_zigbee_retry_join(p_leave_params->leave_type);
        }
        else
        {
            DRV_ZIGBEE_LOG_ERROR("Unable to leave network. Status: %d", status);
        }
    }
    
    // --------------------------------------------------------------------------------------------------------------------
    // ZIGBEE DRIVER'S TASK CODE
    // --------------------------------------------------------------------------------------------------------------------
    static void drv_zigbee_task(void *params)
    {
        UNUSED_PARAMETER(params);
    
        ret_code_t zb_err_code = zboss_start();
        ZB_ERROR_CHECK(zb_err_code);
    
        DRV_ZIGBEE_LOG_INFO("Starting.");
        bool is_paired = drv_zigbee_is_device_paired();
        drv_zigbee_change_state_and_call_callback_if_state_changed(is_paired ? DRV_ZIGBEE_STATE_PAIRED_AND_NETWORK_OFF
                                                                             : DRV_ZIGBEE_STATE_NOT_PAIRED);
    
        while (true)
        {
            // Do not check the return value because we wait undefinitely for the mutex so the call will always return
            // true.
            UNUSED_RETURN_VALUE(os_recursive_mutex_take(m_zigbee_mux, os_no_timeout));
            zboss_main_loop_iteration();
            UNUSED_RETURN_VALUE(os_recursive_mutex_give(m_zigbee_mux));
            os_delay_ms(1);
        }
    }
    
    // --------------------------------------------------------------------------------------------------------------------
    // DEFINITIONS OF CONVERSION FUNCTIONS
    // --------------------------------------------------------------------------------------------------------------------
    static const char *drv_zigbee_thermostat_attr_id_to_str(zb_uint16_t attr_id)
    {
        static const char local_temperature_str[] = "local_temperature";
        static const char occupied_cooling_setpoint_str[] = "occupied_cooling_setpoint";
        static const char occupied_heating_setpoint_str[] = "occupied_heating_setpoint";
        static const char system_mode_str[] = "system_mode";
        static const char control_sequence_of_operation_str[] = "control_sequence_of_operation";
    
        switch (attr_id)
        {
        case ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID: return local_temperature_str;
        case ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_COOLING_SETPOINT_ID: return occupied_cooling_setpoint_str;
        case ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID: return occupied_heating_setpoint_str;
        case ZB_ZCL_ATTR_THERMOSTAT_SYSTEM_MODE_ID: return system_mode_str;
        case ZB_ZCL_ATTR_THERMOSTAT_CONTROL_SEQUENCE_OF_OPERATION_ID: return control_sequence_of_operation_str;
        default: return unknown_str;
        }
    }
    
    static const char *drv_zigbee_zcl_status_to_str(zb_uint8_t status)
    {
        static const char success_str[] = "success", invalid_value_str[] = "invalid_value", timeout_str[] = "timeout",
                          notification_pending_str[] = "notification_pending", sw_fail_str[] = "software_failure",
                          hw_fail_str[] = "hardware_failure", not_found_str[] = "not_found", fail_str[] = "failure",
                          read_only_str[] = "read_only";
        switch (status)
        {
        case ZB_ZCL_STATUS_SUCCESS: return success_str;
        case ZB_ZCL_STATUS_INVALID_VALUE: return invalid_value_str;
        case ZB_ZCL_STATUS_TIMEOUT: return timeout_str;
        case ZB_ZCL_STATUS_NOTIFICATION_PENDING: return notification_pending_str;
        case ZB_ZCL_STATUS_SW_FAIL: return sw_fail_str;
        case ZB_ZCL_STATUS_HW_FAIL: return hw_fail_str;
        case ZB_ZCL_STATUS_NOT_FOUND: return not_found_str;
        case ZB_ZCL_STATUS_FAIL: return fail_str;
        case ZB_ZCL_STATUS_READ_ONLY: return read_only_str;
        default: return unknown_str;
        }
    }
    
    static zb_uint8_t drv_zigbee_device_err_to_zcl_status(enum drv_zigbee_device_err err)
    {
        switch (err)
        {
        case DRV_ZIGBEE_DEVICE_SUCCESS: return ZB_ZCL_STATUS_SUCCESS;
        case DRV_ZIGBEE_DEVICE_INVALID_VALUE: return ZB_ZCL_STATUS_INVALID_VALUE;
        case DRV_ZIGBEE_DEVICE_TIMEOUT: return ZB_ZCL_STATUS_TIMEOUT;
        case DRV_ZIGBEE_DEVICE_BUSY: return ZB_ZCL_STATUS_NOTIFICATION_PENDING;
        case DRV_ZIGBEE_DEVICE_SOFTWARE_FAILURE: return ZB_ZCL_STATUS_SW_FAIL;
        case DRV_ZIGBEE_DEVICE_HARDWARE_FAILURE: return ZB_ZCL_STATUS_HW_FAIL;
        case DRV_ZIGBEE_DEVICE_NOT_FOUND: return ZB_ZCL_STATUS_NOT_FOUND;
        case DRV_ZIGBEE_DEVICE_FAILURE: return ZB_ZCL_STATUS_FAIL;
        default: return ZB_ZCL_STATUS_FAIL;
        }
    }
    
    /**
     * @file	drv_zigbee_defs.h
     * @brief	Declares ZigBee macros and structures which help to define cluster list.
     * @author	Kacper Kowalski - [email protected]
     */
    
    #ifndef DRV_ZIGBEE_DEFS_H
    #define DRV_ZIGBEE_DEFS_H
    
    #include "zboss_api.h"
    
    typedef struct
    {
        zb_uint8_t zcl_version;
        zb_uint8_t app_version;
        zb_uint8_t stack_version;
        zb_uint8_t hw_version;
        zb_char_t manufacturer_name[32];
        zb_char_t model_id[32];
        zb_char_t date_code[16];
        zb_uint8_t power_source;
        zb_uint8_t sw_build_id;
    } lerta_device_basic_attrs_1_t;
    
    typedef struct
    {
        zb_int16_t local_temperature;
        zb_int16_t occupied_cooling_setpoint;
        zb_int16_t occupied_heating_setpoint;
        zb_uint8_t control_sequence_of_operation;
        zb_uint8_t system_mode;
    } lerta_device_thermostat_attrs_1_t;
    
    #define LERTA_ZB_HA_THERMOSTAT_1_IN_CLUSTER_NUM 2
    #define LERTA_ZB_HA_THERMOSTAT_1_OUT_CLUSTER_NUM 0
    
    #define LERTA_ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_1(attr_list,                                                            \
                                                     zcl_version,                                                          \
                                                     app_version,                                                          \
                                                     stack_version,                                                        \
                                                     hw_version,                                                           \
                                                     manufacturer_name,                                                    \
                                                     model_id,                                                             \
                                                     date_code,                                                            \
                                                     power_source,                                                         \
                                                     sw_build_id)                                                          \
        ZB_ZCL_START_DECLARE_ATTRIB_LIST(attr_list)                                                                        \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_ZCL_VERSION_ID, (zcl_version))                                              \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_APPLICATION_VERSION_ID, (app_version))                                      \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_STACK_VERSION_ID, (stack_version))                                          \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_HW_VERSION_ID, (hw_version))                                                \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (manufacturer_name))                                  \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (model_id))                                            \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_DATE_CODE_ID, (date_code))                                                  \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, (power_source))                                            \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BASIC_SW_BUILD_ID, (sw_build_id))                                                 \
        ZB_ZCL_FINISH_DECLARE_ATTRIB_LIST
    
    #define LERTA_ZB_ZCL_DECLARE_BASIC_ATTR_LIST_1(attr_list, attrs)                                                       \
        LERTA_ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_1(attr_list,                                                                \
                                                 &attrs.zcl_version,                                                       \
                                                 &attrs.app_version,                                                       \
                                                 &attrs.stack_version,                                                     \
                                                 &attrs.hw_version,                                                        \
                                                 attrs.manufacturer_name,                                                  \
                                                 attrs.model_id,                                                           \
                                                 attrs.date_code,                                                          \
                                                 &attrs.power_source,                                                      \
                                                 &attrs.sw_build_id)
    
    #define LERTA_ZB_ZCL_DECLARE_THERMOSTAT_ATTRIB_LIST_1(attr_list,                                                       \
                                                          local_temperature,                                               \
                                                          occupied_cooling_setpoint,                                       \
                                                          occupied_heating_setpoint,                                       \
                                                          control_sequence_of_operation,                                   \
                                                          system_mode)                                                     \
        ZB_ZCL_START_DECLARE_ATTRIB_LIST(attr_list)                                                                        \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID, (local_temperature))                             \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_COOLING_SETPOINT_ID, (occupied_cooling_setpoint))             \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID, (occupied_heating_setpoint))             \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_THERMOSTAT_CONTROL_SEQUENCE_OF_OPERATION_ID, (control_sequence_of_operation))     \
        ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_THERMOSTAT_SYSTEM_MODE_ID, (system_mode))                                         \
        ZB_ZCL_FINISH_DECLARE_ATTRIB_LIST
    
    #define LERTA_ZB_ZCL_DECLARE_THERMOSTAT_ATTR_LIST_1(attr_list, attrs)                                                  \
        LERTA_ZB_ZCL_DECLARE_THERMOSTAT_ATTRIB_LIST_1(attr_list,                                                           \
                                                      &attrs.local_temperature,                                            \
                                                      &attrs.occupied_cooling_setpoint,                                    \
                                                      &attrs.occupied_heating_setpoint,                                    \
                                                      &attrs.control_sequence_of_operation,                                \
                                                      &attrs.system_mode)
    
    #define LERTA_ZB_HA_DECLARE_BEEBLINKER_CLUSTER_LIST_1(cluster_list_name, basic_attr_list, thermostat_attr_list)        \
        zb_zcl_cluster_desc_t cluster_list_name[] = {                                                                      \
            ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_BASIC,                                                                   \
                                ZB_ZCL_ARRAY_SIZE(basic_attr_list, zb_zcl_attr_t),                                         \
                                (basic_attr_list),                                                                         \
                                ZB_ZCL_CLUSTER_SERVER_ROLE,                                                                \
                                ZB_ZCL_MANUF_CODE_INVALID),                                                                \
            ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_THERMOSTAT,                                                              \
                                ZB_ZCL_ARRAY_SIZE(thermostat_attr_list, zb_zcl_attr_t),                                    \
                                (thermostat_attr_list),                                                                    \
                                ZB_ZCL_CLUSTER_SERVER_ROLE,                                                                \
                                ZB_ZCL_MANUF_CODE_INVALID),                                                                \
        }
    
    #define LERTA_ZB_ZCL_DECLARE_BEEBLINKER_SIMPLE_DESC_1(ep_name, ep_id, in_clust_num, out_clust_num)                     \
        ZB_DECLARE_SIMPLE_DESC(in_clust_num, out_clust_num);                                                               \
        ZB_AF_SIMPLE_DESC_TYPE(in_clust_num, out_clust_num)                                                                \
        simple_desc_##ep_name = {ep_id,                                                                                    \
                                 ZB_AF_HA_PROFILE_ID,                                                                      \
                                 ZB_HA_THERMOSTAT_DEVICE_ID,                                                               \
                                 ZB_HA_DEVICE_VER_THERMOSTAT,                                                              \
                                 0,                                                                                        \
                                 in_clust_num,                                                                             \
                                 out_clust_num,                                                                            \
                                 {                                                                                         \
                                     ZB_ZCL_CLUSTER_ID_BASIC,                                                              \
                                     ZB_ZCL_CLUSTER_ID_THERMOSTAT,                                                         \
                                 }}
    
    #define LERTA_ZB_HA_DECLARE_BEEBLINKER_EP_1(ep_name, ep_id, cluster_list)                                              \
        LERTA_ZB_ZCL_DECLARE_BEEBLINKER_SIMPLE_DESC_1(                                                                     \
            ep_name, ep_id, LERTA_ZB_HA_THERMOSTAT_1_IN_CLUSTER_NUM, LERTA_ZB_HA_THERMOSTAT_1_OUT_CLUSTER_NUM);            \
        ZBOSS_DEVICE_DECLARE_REPORTING_CTX(reporting_info##device_ctx_name, ZB_HA_THERMOSTAT_REPORT_ATTR_COUNT);           \
        ZB_AF_DECLARE_ENDPOINT_DESC(ep_name,                                                                               \
                                    ep_id,                                                                                 \
                                    ZB_AF_HA_PROFILE_ID,                                                                   \
                                    0,                                                                                     \
                                    NULL,                                                                                  \
                                    ZB_ZCL_ARRAY_SIZE(cluster_list, zb_zcl_cluster_desc_t),                                \
                                    cluster_list,                                                                          \
                                    (zb_af_simple_desc_1_1_t *)&simple_desc_##ep_name,                                     \
                                    ZB_HA_THERMOSTAT_REPORT_ATTR_COUNT,                                                    \
                                    reporting_info##device_ctx_name,                                                       \
                                    0,                                                                                     \
                                    NULL)
    
    #define LERTA_ZB_HA_DECLARE_BEEBLINKER_CTX_1(device_ctx, ep_name) ZBOSS_DECLARE_DEVICE_CTX_1_EP(device_ctx, ep_name)
    
    #endif /* DRV_ZIGBEE_DEFS_H */
    


    7357.sdk_config.h

    Sorry, for such a late reply.

    Here is the code which handles Zigbee networking. You won't be able to compile it because it is a part of a project, but I hope that it will be sufficient.

  • I'm collecting the dump, but with the library, with debug symbols and big trace level, the device will not get into the bad state.
    I will wait longer.

  • Hi.

    I've forwarded this information to our developer team, I need some assistance for this.

    Best regards,

    Andreas

Related