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

ZigBee problems with coordinator to subscribe the multi sensor

Good day.

I am currently developing with two NRF52840 DK boards, and I also have two NRF Dongles. On a dongle a sniffer for ZigBee. I am working with SDK 3.2. This is my first project with ZigBee, so I don't have much know-how yet.

My goal is to implement the coordinator as like CLI agent. So that it subscribes to the multi-sensor and receives data. Is so to speak an A to B communication.

With "zb_zdo_match_desc_req()" I get the short address and the endpoint of the sensor. Then with "zb_zdo_ieee_addr_req()" I get the long address  (EUI64) of the sensor. After that the "zb_zdo_bind_req()" request starts (Between coordinator and sensor) and in the callback function ("p_resp->status") this is confirmed successfully with ZB_ZDP_STATUS_SUCCESS. However, I only connect to the ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT cluster.

My questions:
1) Is it necessary to connect both clusters (temperature/pressure) to subscribe to the multisensor? If so, is the bind request simply done again with the ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT?

2) Is subscribing the sensor in the first step as below, correct?

// Step 8:
// Subscribe on Sensor
static void subscribe_device(zb_uint8_t param)
{
    zb_buf_t                         * p_buf  = ZB_BUF_FROM_REF(param);
    configure_reporting_req_t          req;
    tsn_ctx_t                        * p_tsn_cli;
    zb_uint8_t                       * p_cmd_ptr;
    zb_ret_t                           zb_err_code;
    //zb_bool_t                          subscribe;
    zb_ieee_addr_t                     sensor_ieee_adr;

    NRF_LOG_INFO("----------------------------------------");
    NRF_LOG_INFO("Step 8: subscribe_device");


    req.profile_id   = ZB_AF_HA_PROFILE_ID;
    req.cluster_id   = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;    //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT; //
    req.attr_id      = ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
    req.attr_type    = ZB_ZCL_ATTR_TYPE_S16;                //ZB_ZCL_ATTR_TYPE_16BIT;

    req.interval_min = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL;
    req.interval_max = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL;

    req.remote_node.addr_short = m_device_ctx.bulb_params.short_address;
    req.remote_addr_mode       = ZB_APS_ADDR_MODE_16_ENDP_PRESENT;      //= parse_address(addr_buf, &req.remote_node, ADDR_ANY);
    req.remote_ep              = m_device_ctx.bulb_params.endpoint; 
    
    p_buf = ZB_GET_OUT_BUF();

    NRF_LOG_INFO("Configure Reporting");

    p_tsn_cli = get_free_tsn_ctx();
    if (!p_tsn_cli)
    {
        NRF_LOG_ERROR("Too many configure reporting requests");
        ZB_FREE_BUF(p_buf);
        return;
    }
   
    // Configure new tsn context.
    p_tsn_cli->taken = true;
    //p_tsn_cli->p_cli = p_cli;
    p_tsn_cli->tsn   = ZCL_CTX().seq_number;

    ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_SRV_REQ(p_buf, 
                                                    p_cmd_ptr, 
                                                    ZB_ZCL_ENABLE_DEFAULT_RESPONSE);

    ZB_ZCL_GENERAL_ADD_SEND_REPORT_CONFIGURE_REPORTING_REQ(p_cmd_ptr,
                                                           req.attr_id, 
                                                           req.attr_type, 
                                                           req.interval_min, 
                                                           req.interval_max,
                                                           ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE);

    ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ(p_buf, 
                                                p_cmd_ptr,
                                                req.remote_node, 
                                                req.remote_addr_mode, 
                                                req.remote_ep, 
                                                m_device_ctx.co_params.endpoint, //CONTROLL_ENDPOINT
                                                req.profile_id, 
                                                req.cluster_id, 
                                                NULL);
    NRF_LOG_INFO("Report sended Waiting for Values");
    //zb_err_code = ZB_SCHEDULE_ALARM(zb_subscribe_timeout, p_tsn_cli->tsn, ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT * ZB_TIME_ONE_SECOND);
    if (zb_err_code != RET_OK)
    {
        NRF_LOG_ERROR("Unable to schedule timeout timer");
        invalidate_ctx(p_tsn_cli);
    }
    NRF_LOG_INFO("End");
}

3) Does it even need "cmd_zb_subscribe_unsubscribe_cb" and what is that unsubscribe for?

My problems:
1)  The "ep_handler_report" is not called, but I see in Wireshark that a Report Attributes has been sent?

Is there still something to change at the sensor, because there I have left everything as is.

My ep_handler_report Handler:

 
static zb_uint8_t ep_handler_report(zb_uint8_t param)
{
    NRF_LOG_INFO("Ep Handler Report");
    zb_buf_t            *  p_zcl_cmd_buf = (zb_buf_t *)ZB_BUF_FROM_REF(param);
    zb_zcl_parsed_hdr_t *  p_cmd_info    = ZB_GET_BUF_PARAM(p_zcl_cmd_buf, zb_zcl_parsed_hdr_t);
    tsn_ctx_t           *  p_tsn_ctx;

    if (p_cmd_info->cmd_id == ZB_ZCL_CMD_REPORT_ATTRIB)
    {
        NRF_LOG_INFO("print_attr");
        print_attr(p_cmd_info, param);
        ZB_FREE_BUF_BY_REF(param);
        return ZB_TRUE;
    }
    else if (p_cmd_info->cmd_id == ZB_ZCL_CMD_CONFIG_REPORT_RESP)
    {
        // Find command context by ZCL sequence number.
        p_tsn_ctx = get_ctx_by_tsn(p_cmd_info->seq_number);
        if (p_tsn_ctx != NULL)
        {

            NRF_LOG_WARNING("Unsubscribe cb");
            cmd_zb_subscribe_unsubscribe_cb(p_tsn_ctx, param);
            return ZB_TRUE;
        }
    }
    NRF_LOG_INFO("False Handler report");
    ZB_FREE_BUF_BY_REF(param);
    return ZB_FALSE;
}
  
/* Register callback for handling ZCL commands. */
ZB_AF_SET_ENDPOINT_HANDLER(m_device_ctx.bulb_params.endpoint, ep_handler_report);

The other functions as well as the output of the data I took from the CLI as well as from other discussions.

With the function "print_attr()" the data is output (Same function as with CLI), what am I doing wrong here with subscribe?

2) After a while the network crashes, any idea what this is? The Connected LED on the sensor goes out.

I would also be glad if you could give me a quick rundown on the process for subscribing to devices. If you want the whole code, I can share it with pleasure.

Thanks in advance. Slight smile

With kind regards

Jonas T

  • Hi Jonas,

    1) Is it necessary to connect both clusters (temperature/pressure) to subscribe to the multisensor? If so, is the bind request simply done again with the ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT?

    If you want to receive attribute reports from both clusters then yes. You need to create a binding for each cluster you want to receive reports from, and you do that by sending individual bind requests to each cluster.

    2) Is subscribing the sensor in the first step as below, correct?

    It looks correct to me.

    3) Does it even need "cmd_zb_subscribe_unsubscribe_cb" and what is that unsubscribe for?

    No you do not need this callback. In the CLI example this callback is used to check the status of the Configure Reporting Response command received after sending the Configure Reporting command, to see if it was successful or not.

    Unsubscribe is for disabling reporting. In both the case where you subscribe and where you unsubscribe you send the same command to the remote device, the Configure Reporting command. The only differences between these two are the min and max interval fields of the command. When you subscribe these are set to valid values to configure periodic reporting, while unsubscribe will set min to 0x000F and max to 0xFFFF, indicating that it should not periodically report.

    1)  The "ep_handler_report" is not called, but I see in Wireshark that a Report Attributes has been sent?

    Make sure to register the device context before registering the endpoint handler. For example:

    ZB_AF_REGISTER_DEVICE_CTX(&device_ctx);
    ZB_AF_SET_ENDPOINT_HANDLER(DEVICE_ENDPOINT, ep_handler_report);

    Also make sure you are using the correct endpoint. From your ZB_AF_SET_ENDPOINT_HANDLER it seems like you might be using the light switch example, since you are using m_device_ctx.bulb_params.endpoint. If that is the case, then the endpoint given by m_device_ctx.bulb_params.endpoint is the endpoint of the light bulb. The endpoint handler you register with ZB_AF_SET_ENDPOINT_HANDLER will handle ZCL packets incoming on the endpoint you use when you register it, so this endpoint must be an endpoint registered on the device, and it must be the same endpoint as used for the device context. So for the light switch you would have:

    ZB_AF_REGISTER_DEVICE_CTX(&dimmer_switch_ctx);
    ZB_AF_SET_ENDPOINT_HANDLER(LIGHT_SWITCH_ENDPOINT, ep_handler_report);
    2) After a while the network crashes, any idea what this is? The Connected LED on the sensor goes out.

    A beacon request is sent by a device wanting to join a network as a part of scanning for networks. Devices can do passive or active scans. In the case of active scans the device will send out a beacon request to try to discover networks on the channel. If there is a network, then nearby routers will send a beacon in response.

    Do you have any indication as to why the network crashes? If you upload a sniffer log of the issue as a pcap I can look at it and see if I can find what the issue might be.

    Best regards,

    Marte

  • Hi Marte,

    Thank you very much for answering my questions. I have included the light switch in the coordinator, so the lamp can be switched on and off (Is another project, but I have changed a lot here). That's why some variable names are still on the old name.

    Short question: the coordinator has the endpoint 0, right?

    The endpoint (Sensor) has the end point 10.

    Below I listed my "ZB_AF_REGISTER_DEVICE_CTX" and "ZB_AF_SET_ENDPOINT_HANDLER". Can you maybe take a look if this is so correct? Have about the same Configurations as the CLI.

    #define COORDINATOR_ENDPOINT     0
    
    // Variable structure
    typedef struct _coordintoor_bulb_parameter_
    {
        zb_uint8_t     endpoint;
        zb_uint16_t    short_address;
        zb_uint8_t       status;
        zb_ieee_addr_t long_address;
    } coordintoor_bulb_parameter;
    
    typedef struct _button_states_
    {
        zb_bool_t      button_pressed;
        zb_time_t      timestamp;
    } coordintoor_button_states;
    
    typedef struct _coordinator_params_
    {
        zb_uint8_t     endpoint;
        //zb_uint16_t   short_address;
        zb_ieee_addr_t long_address;
    } coordinator_params; 
                  
    typedef struct _coordinator_ctx_
    {
        coordintoor_bulb_parameter  bulb_params;
        coordintoor_button_states   button;
        coordinator_params          co_params;
    } coordinator_ctx;                  
    
    // Configurations
    
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
    
    ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CLUSTER_LIST(co_controll_cluster,
                                                   basic_attr_list,
                                                   identify_attr_list);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_EP(co_controll_ep,
                                        COORDINATOR_ENDPOINT,
                                        co_controll_cluster);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CTX(co_controll_ctx, co_controll_ep);
    
    
    // In the main
    
    /* Initialize application context structure. */
    UNUSED_RETURN_VALUE(ZB_MEMSET(&m_device_ctx, 0, sizeof(coordinator_ctx)));
    
    /* Set default bulb short_addr. */
    m_device_ctx.bulb_params.short_address = 0xFFFF;
    
    /* Register dimmer switch device context (endpoints). */
    ZB_AF_REGISTER_DEVICE_CTX(&co_controll_ctx);
    
    /* Register callback for handling ZCL commands. */
    ZB_AF_SET_ENDPOINT_HANDLER(COORDINATOR_ENDPOINT, ep_handler_report);
    
    /* Keep or erase NVRAM to save the network parameters after device reboot or power-off. */
    zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);

    Because of the network crash, I have tested again. This only occurs after the binding request with the "ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT". Attached, I send you the sniffer data and the code that performs the binding. Maybe you will find a problem. The funny thing is that the sensor responds to the binding request, with Success, but after that the callback function is not called Disappointed (Look down below in the image sniffer data (marked yellow)).

    Still attached is my bind function as well as the corresponding callback function, maybe this helps you a bit. The long addresses are passed correctly after own checks (NRF_LOG_INFO...).

    // STEP 7:
    
    static zb_void_t zb_bind_callback(zb_uint8_t param)
    {
        NRF_LOG_INFO("Bind Callback");
        zb_buf_t           * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zdo_bind_resp_t * p_resp = (zb_zdo_bind_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ret_t             zb_err_code;
    
        m_device_ctx.bulb_params.status = p_resp->status; 
    
        if (m_device_ctx.bulb_params.status == ZB_ZDP_STATUS_SUCCESS)
        {	
            NRF_LOG_INFO("Step 7: Bind successfully on Target: 0x%04x, Endpoint: %d", m_device_ctx.bulb_params.short_address, m_device_ctx.bulb_params.endpoint);
            ZB_FREE_BUF_BY_REF(param);	
            //subscribe_device(param);
        }
        else
        {  
            NRF_LOG_WARNING("bind faild %d :(",p_resp->status);
        }
    }
    
    // STEP 6:
    
    static zb_void_t bind_device(zb_uint8_t param)
    {   
        zb_buf_t                  * p_buf  = ZB_BUF_FROM_REF(param);  // Resolve buffer number to buffer address 
        zb_zdo_bind_req_param_t   * p_req;
        uint8_t			tsn;
        zb_ieee_addr_t              dst_ieee_addr;
        zb_osif_get_ieee_eui64(dst_ieee_addr);
    
        p_buf = ZB_GET_OUT_BUF();
        if (!p_buf)
        {
            NRF_LOG_ERROR("failed to execute command (buf alloc failed)");
            return;
        }
    
        p_req  = ZB_GET_BUF_PARAM(p_buf, zb_zdo_bind_req_param_t);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 6: Try to bind");
    
        //ZB_MEMCPY(&p_req->src_address,           &m_device_ctx.bulb_params.long_address, sizeof(zb_ieee_addr_t));   //ieee address of sensor
        //ZB_MEMCPY(&p_req->dst_address.addr_long, &dst_ieee_addr,                         sizeof(zb_ieee_addr_t));   //ieee address of coordinator
    
        for (uint8_t i=0; i<8; i++)
        {
            p_req->src_address[i] = m_device_ctx.bulb_params.long_address[i];     //ieee address of sensor
            p_req->dst_address.addr_long[i] = dst_ieee_addr[i];                   //ieee address of coordinator
        }
    
        p_req->dst_addr_mode = ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
    
        p_req->src_endp      = m_device_ctx.bulb_params.endpoint;                 //endpoint of sensor
        p_req->dst_endp      = COORDINATOR_ENDPOINT;                              //endpoint of coordinator "0"
    
        p_req->cluster_id    = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;                //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;
        p_req->req_dst_addr  = m_device_ctx.bulb_params.short_address;            //short address of sensor
    
        tsn = zb_zdo_bind_req(ZB_REF_FROM_BUF(p_buf), zb_bind_callback);
    
        NRF_LOG_INFO("tsn: %d", tsn);
    
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_INFO("failed to send request, %d", tsn);
    	    return;
        }
        return;
    }

    Sniffer Data:

    If I do not call the "bind_device" function, the sensor remains connected in the network. This means that it should be the "bind_device" function that is the problem.

    Thanks again and best regards,

    Jonas

  • Hi Jonas,

    Jonas T said:
    Short question: the coordinator has the endpoint 0, right?

    You cannot use endpoint 0 for your application, as it is reserved for the data interface to the ZDO. 

    Jonas T said:
    Below I listed my "ZB_AF_REGISTER_DEVICE_CTX" and "ZB_AF_SET_ENDPOINT_HANDLER". Can you maybe take a look if this is so correct?

    It looks correct, just make sure to change COORDINATOR_ENDPOINT to a valid endpoint (1-254).

    Jonas T said:
    Because of the network crash, I have tested again. This only occurs after the binding request with the "ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT". Attached, I send you the sniffer data and the code that performs the binding. Maybe you will find a problem.

    From your sniffer log and what you say about the bind callback not being called it seems like the coordinator stops working either right after sending the bind request or immediately when it receives the response but before it is able go into the callback function. The issue might be related to your coordinator endpoint, since you are creating a binding on an endpoint that is reserved and should not be used in the application. You should change COORDINATOR_ENDPOINT to something else and see if that fixes the issue. Other than that I do not see any obvious issues with your bind request and callback. If you are still seing the problem after changing the endpoint value you can upload your project here and I can test it on my side.

    Best regards,

    Marte

  • Hi Marte,

    Thank you very much for response. I did the coordinator number wrong and have now changed it. Thank you for the advice. Slight smile However, unfortunately, the error can not be fixed Hushed. I also copied the main and loaded into a new ZigBee light example (light_coordinator [ZigBee_3_2\examples\zigbee\light_control\light_coordinator"). But again the same error came out. Slight frown

    The aim of the project is to read out the multi sensor with a coordinator and to output it on the interface (e.g. uart, display...).

    But I'll try to get only the temperature values from the sensor, later the pressure will follow.

    I have now enclosed the entire project folder for you and will point out the locations. Additionally I have attached the Main File to them again.

    All code has been implemented in the "main.c" file. All functions are listed below and can be found via the project search in the main (Would recommend). They have also been labeled and numbered in large ASCII text. I then also adjusted the naming of some variables, as well as from Coordinator to "Sensor logger".

    Function names for the search:
    Signal Handler: "zboss_signal_handler". (Line 1039)

    1) Send a match request: "send_match_desc_req" (Line 968)
    Callback function: "cmd_zb_match_desc_cb"

    2) Long address request: "zb_ieee_addr_req"  (Line 894)
    Callback function: "ieee_addr_cb"

    3) Send bind request: "bind_device" (Line 779)
    Callback function: "zb_bind_callback"

    4) Subscribe function: "subscribe_device" (Line 670)

    Do I also make a little bit of a mix-up with the buffers? If so, do you have any tips or internet sites?

    Now I wish you still good luck with testing and thank you again. Hope everything works. Ok hand

    With kind regards

    Jonas

    // ****************************************************************************
    // Project      : ZigBee Project
    // Processor    : PCA10056
    // Compiler     : SEGGER Embedded Studio
    // Autor        : Jonas T
    // Date         : 06.05.2022
    // Version      : V0.1
    // Description  : Coordinator for reading Multisensor (Sensor logger)
    // ****************************************************************************
    
     //----------------------------------------------------------------------------------------
     // ___               _             _            
     //|_ _|  _ _    __  | |  _  _   __| |  ___   ___
     // | |  | ' \  / _| | | | || | / _` | / -_) (_-<
     //|___| |_||_| \__| |_|  \_,_| \__,_| \___| /__/
                                                   
    #include "zboss_api.h"
    #include "zb_mem_config_max.h"
    #include "zb_error_handler.h"
    #include "zigbee_helpers.h"
    
    #include "app_timer.h"
    #include "boards.h"
    #include "bsp.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "nrf.h"
    #include "nrf_drv_gpiote.h"
    
     //----------------------------------------------------------------------------------------
     // ___           __   _              
     //|   \   ___   / _| (_)  _ _    ___ 
     //| |) | / -_) |  _| | | | ' \  / -_)
     //|___/  \___| |_|   |_| |_||_| \___|
    
    #ifdef  BOARD_PCA10059   
    #include "Hardware_Configuration.h"
    #define LED_ERROR     1
    #define LED_CONNECTED 2
    #define LED_JOINING   3
    
    #define PIN_SCHALTER          NRF_GPIO_PIN_MAP(1, 15)
    #define PIN_TASTER_RED        2
    #define PIN_TASTER_WITHE      NRF_GPIO_PIN_MAP(1, 13)
    #define PIN_TASTER_WITHE_BIG  29
    #else
    
    #endif
    
    #define ERASE_PERSISTENT_CONFIG             ZB_TRUE   // See join process       /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. NOTE: If this option is set to ZB_TRUE then do full device erase for all network devices before running other samples. */
    #define MAX_CHILDREN                        10                                  /**< The maximum amount of connected devices. Setting this value to 0 disables association to this device.  */
    #define IEEE_CHANNEL_MASK                   (1l << ZIGBEE_CHANNEL)              /**< Scan only one, predefined channel to find the coordinator. */
    
    #define MATCH_DESC_REQ_START_DELAY          (2 * ZB_TIME_ONE_SECOND)            /**< Delay between the light switch startup and light bulb finding procedure. */
    #define IEEE_ADDRESSS_REQ_DELAY             (2 * ZB_TIME_ONE_SECOND)            /**< Delay between MATCH_DESC_REQ and IEEE_ADDRESSS_REQ */
    #define BIND_REQ_DELAY                      (2 * ZB_TIME_ONE_SECOND)            /**< Delay between IEEE_ADDRESSS_REQ and BIND_REQ */
    // #define MATCH_DESC_REQ_TIMEOUT              (5 * ZB_TIME_ONE_SECOND)            /**< Timeout for finding procedure. */
    #define TIME_ONE_SECOND                     ZB_TIME_ONE_SECOND
    #define MATCH_DESC_REQ_ROLE                 ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE    /**< Find only non-sleepy device. */
    
    // (I have another Button input module for Dongle, but now i make it on PCA10056)
    #ifdef  BOARD_PCA10059                                                          /**< If it is Dongle */
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_0                       /**< LED indicating that network is opened for new nodes. */
    #define LIGHT_SWITCH_BUTTON_ON            PIN_TASTER_WITHE                      /**< Button ID used to switch on the light bulb. */
    #define LIGHT_SWITCH_BUTTON_OFF           PIN_TASTER_RED                        /**< Button ID used to switch off the light bulb. */
    #define ZIGBEE_NETWORK_REOPEN_BUTTON      PIN_TASTER_WITHE_BIG                  /**< Button which reopens the Zigbee Network. */
    #else
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_2                       /**< LED indicating that network is opened for new nodes. */
    #define BULB_FOUND_LED                    BSP_BOARD_LED_3                       /**< LED indicating that light witch found a light bulb to control. (LED Connected)*/
    #define ZIGBEE_NETWORK_REOPEN_BUTTON      BSP_BOARD_BUTTON_0                    /**< Button which reopens the Zigbee Network. */
    #define LIGHT_SWITCH_BUTTON_ON            BSP_BOARD_BUTTON_1                    /**< Button ID used to switch on the light bulb. */
    #define LIGHT_SWITCH_BUTTON_OFF           BSP_BOARD_BUTTON_2                    /**< Button ID used to switch off the light bulb. */
    #endif
    
    #define ZIGBEE_MANUAL_STEERING              ZB_FALSE                              /**< If set to 1 then device will not open the network after forming or reboot. */
    
    //#define LIGHT_SWITCH_BUTTON_THRESHOLD       ZB_TIME_ONE_SECOND                      /**< Number of beacon intervals the button should be pressed to dimm the light bulb. */
    //#define LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO  ZB_MILLISECONDS_TO_BEACON_INTERVAL(50)  /**< Delay between button state checks used in order to detect button long press. */
    //#define LIGHT_SWITCH_BUTTON_LONG_POLL_TMO   ZB_MILLISECONDS_TO_BEACON_INTERVAL(300) /**< Time after which the button state is checked again to detect button hold - the dimm command is sent again. */
    
    // Defines how long to wait, in seconds, for Configure Reporting Response.
    #define ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT     5
    // Defines how many report attribute requests can be run concurrently.
    #define ZIGBEE_CONFIGURE_REPORT_TSN                  3
    // Defines default value for minimum interval inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL 1
    // Defines default value for maximum interval inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL 60
    // Defines default value for minimum value change inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE NULL
    
    #define SENSOR_LOGGER_ENDPOINT  12   // Valid Endpoint 1-254
    #define POWER_SOURCE            ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE
    
    #ifndef ZB_COORDINATOR_ROLE
    #error Define ZB_COORDINATOR_ROLE to compile coordinator source code.
    #endif
    
     //----------------------------------------------------------------------------------------
     //__   __               _          _      _            
     //\ \ / /  __ _   _ _  (_)  __ _  | |__  | |  ___   ___
     // \ V /  / _` | | '_| | | / _` | | '_ \ | | / -_) (_-<
     //  \_/   \__,_| |_|   |_| \__,_| |_.__/ |_| \___| /__/
    
    typedef struct _sensor_parameter_
    {
      zb_uint8_t              endpoint;
      zb_uint16_t             short_address;
      zb_uint8_t              status;
      zb_ieee_addr_t          long_address;
    } sensor_parameter_t;
    
    typedef struct _sensor_logger_button_
    {
      zb_bool_t               button_pressed;
      zb_time_t               timestamp;
    } sensor_logger_button_t;
    
    typedef struct _sensor_logger_params_
    {
      //zb_uint8_t            endpoint;
      //zb_ieee_addr_t        long_address;
    } sensor_logger_params_t; 
                  
    typedef struct _coordinator_ctx_
    {
      sensor_parameter_t              sensor_params;
      sensor_logger_button_t          button;
      sensor_logger_params_t          co_params;
    } sensor_logger_ctx_t;                            //ctx = (Device) context
    
    typedef struct {
        zb_uint16_t   profile_id;
        zb_uint16_t   cluster_id;
        zb_uint16_t   attr_id;
        zb_uint8_t    attr_type;
        zb_uint16_t   interval_min;
        zb_uint16_t   interval_max;
        zb_addr_u     remote_node;
        addr_type_t   remote_addr_mode;
        zb_uint8_t    remote_ep;
    } configure_reporting_req_t;
    
    // This structure allows for binding ZBOSS transaction and CLI object.
    typedef struct {
        //nrf_cli_t const * p_cli;
        uint8_t             tsn;
        bool                taken;
        bool                is_broadcast;
    } tsn_ctx_t;
    
    static sensor_logger_ctx_t  m_device_ctx;
    static zb_uint8_t           m_attr_zcl_version    = ZB_ZCL_VERSION;
    static zb_uint8_t           m_attr_power_source   = POWER_SOURCE;
    static zb_uint16_t          m_attr_identify_time  = 0;
    static tsn_ctx_t m_tsn_ctx[ZIGBEE_CONFIGURE_REPORT_TSN];
    
     //----------------------------------------------------------------------------------------
     //  ___                 __   _                              _     _              
     // / __|  ___   _ _    / _| (_)  __ _   _  _   _ _   __ _  | |_  (_)  ___   _ _  
     //| (__  / _ \ | ' \  |  _| | | / _` | | || | | '_| / _` | |  _| | | / _ \ | ' \ 
     // \___| \___/ |_||_| |_|   |_| \__, |  \_,_| |_|   \__,_|  \__| |_| \___/ |_||_|
     //                              |___/                                            
    
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
    
    ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CLUSTER_LIST(co_controll_cluster,
                                                  basic_attr_list,
                                                  identify_attr_list);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_EP(co_controll_ep,
                                        SENSOR_LOGGER_ENDPOINT,
                                        co_controll_cluster);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CTX(co_controll_ctx, co_controll_ep);
    
     //----------------------------------------------------------------------------------------
     // ___                      _     _              
     //| __|  _  _   _ _    __  | |_  (_)  ___   _ _  
     //| _|  | || | | ' \  / _| |  _| | | / _ \ | ' \ 
     //|_|    \_,_| |_||_| \__|  \__| |_| \___/ |_||_|
    
    /**@brief Function for initializing the nrf log module.                                   
     */                                                                                       
    static void log_init(void)                                                                
    {                                                                                         
        ret_code_t err_code;
        
        err_code = NRF_LOG_INIT(NULL);                                             
        APP_ERROR_CHECK(err_code);                                                            
                                                                                              
        NRF_LOG_DEFAULT_BACKENDS_INIT();                                                      
    }                                                                                         
                                                                                              
    /**@brief Function for the Timer initialization.                                          
     *                                                                                        
     * @details Initializes the timer module. This creates and starts application timers.     
     */                                                                                       
    static void timers_init(void)                                                             
    {                                                                                         
        ret_code_t err_code;                                                                  
                                                                                              
        // Initialize timer module.                                                           
        err_code = app_timer_init();                                                          
        APP_ERROR_CHECK(err_code);                                                            
    }                                                                                         
    
    /**@brief Callback for button events. (ONLY FOR DONGLE)                          
     *                                                                                        
     * @param[in]   pin      Pin number
     * @param[in]   action   Pin action     
     */    
    #ifdef  BOARD_PCA10059
    static void button_interrup_handle(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        zb_ret_t            zb_err_code;
        zb_bool_t           comm_status;
        zb_uint32_t         button;
        bool send_command = false;
    
        switch (pin)
        {
            case PIN_TASTER_WITHE_BIG:
                comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                
                if (comm_status)
                {
                    NRF_LOG_INFO("Top level comissioning restated");
                }
                else
                {
                    NRF_LOG_INFO("Top level comissioning hasn't finished yet!");
                }
                break;
    
            case PIN_TASTER_WITHE:
                //button = LIGHT_SWITCH_BUTTON_ON;
                //send_command = true;
                break;
    
            case PIN_TASTER_RED:
                //button = LIGHT_SWITCH_BUTTON_OFF;
                //send_command = true;
                break;
            break;
    
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", pin);
                break;
        }
        //if (send_command)
        //{
        //    if (!m_device_ctx.button.button_pressed)
        //    {
        //         m_device_ctx.button.button_pressed = ZB_TRUE;
        //         m_device_ctx.button.timestamp = ZB_TIMER_GET();
    
        //         zb_err_code = ZB_SCHEDULE_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO);
        //         ZB_ERROR_CHECK(zb_err_code);
        //    }
        //}
    }
    
    
    static void gpio_init()
    {
        ret_code_t err_code;   
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true); // Falling edge interrupt deetection
        in_config.pull = NRF_GPIO_PIN_PULLUP;
    
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_WITHE_BIG, &in_config, button_interrup_handle); //Initialize the interrupt pin
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_WITHE, &in_config, button_interrup_handle);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_RED, &in_config, button_interrup_handle);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_WITHE_BIG, true); //Enable the interrupt events
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_WITHE, true);
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_RED, true);
    }
    
    //https://www.youtube.com/watch?v=f1A2zWKo6Fk
    #else
    
    /**@brief Callback for button events. (PCA10056)                                                    
     *                                                                                        
     * @param[in]   evt      Incoming event from the BSP subsystem.                           
     */                                                                                       
    static void buttons_handler(bsp_event_t evt)
    {
        NRF_LOG_INFO("Button Pressed %d", evt);
        zb_ret_t            zb_err_code;
        zb_bool_t           comm_status;
        zb_uint32_t         button;
    
        bool send_command = false;
    
        switch(evt)
        {
            case BSP_EVENT_KEY_0:
                comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                
                if (comm_status)
                {
                    NRF_LOG_INFO("Top level comissioning restated");
                }
                else
                {
                    NRF_LOG_INFO("Top level comissioning hasn't finished yet!");
                }
                break;
    
            case BSP_EVENT_KEY_1:
                //button = LIGHT_SWITCH_BUTTON_ON;
                //send_command = true;
                break;
    
            case BSP_EVENT_KEY_2:
                //button = LIGHT_SWITCH_BUTTON_OFF;
                //send_command = true;
                break;
            case BSP_EVENT_KEY_3:
                NRF_LOG_INFO("Nothing declared Button 4");
                break;
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
                break;
        }
    }
    #endif
    
    /**@brief Function to convert data types                                                                    
     */      
    int zcl_attr_to_str(char * p_str_buf, uint16_t buf_len, zb_uint16_t attr_type, zb_uint8_t * p_attr)
    {
        NRF_LOG_INFO("zcl_attr_to_str");
        int bytes_written = 0;
        int string_len;
        int i;
    
        if ((p_str_buf == NULL) || (p_attr == NULL))
        {
            return -1;
        }
    
        switch (attr_type)
        {
            /* Boolean */
            case ZB_ZCL_ATTR_TYPE_BOOL:
                bytes_written = snprintf(p_str_buf, buf_len, "%s", *((zb_bool_t *)p_attr) ? "True" : "False");
                break;
    
            /* 1 byte */
            case ZB_ZCL_ATTR_TYPE_8BIT:
            case ZB_ZCL_ATTR_TYPE_8BITMAP:
            case ZB_ZCL_ATTR_TYPE_U8:
            case ZB_ZCL_ATTR_TYPE_8BIT_ENUM:
                bytes_written = snprintf(p_str_buf, buf_len, "%hu", *((zb_uint8_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S8:
                bytes_written = snprintf(p_str_buf, buf_len, "%hd", *((zb_int8_t*)p_attr));
                break;
    
            /* 2 bytes */
            case ZB_ZCL_ATTR_TYPE_16BIT:
            case ZB_ZCL_ATTR_TYPE_16BITMAP:
            case ZB_ZCL_ATTR_TYPE_U16:
            case ZB_ZCL_ATTR_TYPE_16BIT_ENUM:
                bytes_written = snprintf(p_str_buf, buf_len, "%hu", *((zb_uint16_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S16:
                bytes_written = snprintf(p_str_buf, buf_len, "%hd", *((zb_int16_t*)p_attr));
                break;
    
            /* 4 bytes */
            case ZB_ZCL_ATTR_TYPE_32BIT:
            case ZB_ZCL_ATTR_TYPE_32BITMAP:
            case ZB_ZCL_ATTR_TYPE_U32:
                bytes_written = snprintf(p_str_buf, buf_len, "%u", *((zb_uint32_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S32:
                bytes_written = snprintf(p_str_buf, buf_len, "%d", *((zb_int32_t*)p_attr));
                break;
    
            /* String */
            case ZB_ZCL_ATTR_TYPE_CHAR_STRING:
                string_len = p_attr[0];
                p_attr++;
    
                if ((buf_len - bytes_written) < (string_len + 1))
                {
                    return -1;
                }
    
                for (i = 0; i < string_len; i++)
                {
                    /*lint -save -e661 */
                    p_str_buf[bytes_written + i] = ((char *)p_attr)[i];
                    /*lint -restore */
                }
                p_str_buf[bytes_written + i] = '\0';
                bytes_written += string_len + 1;
                break;
    
            case ZB_ZCL_ATTR_TYPE_IEEE_ADDR:
                /*lint -e661 -e662 -save */
                bytes_written = to_hex_str(p_str_buf, buf_len, (const uint8_t *)p_attr, sizeof(zb_64bit_addr_t), true);
                /*lint -restore */
                break;
    
            default:
                bytes_written = snprintf(p_str_buf, buf_len, "Value type 0x%x unsupported", attr_type);
                break;
        }
    
        return bytes_written;
    }
    
    /**
     * @brief Return a pointer to context with the given transaction sequence number.
     *
     * @param[in] tsn ZBOSS transaction sequence number
     *
     * @return a pointer to context or NULL if context for given TSN wasn't found.
     */
    static tsn_ctx_t * get_ctx_by_tsn(uint8_t tsn)
    {
        NRF_LOG_INFO("get_ctx_by_tsn");
        for (uint8_t i = 0; i < ARRAY_SIZE(m_tsn_ctx); i++)
        {
            if ((m_tsn_ctx[i].taken == true) && (m_tsn_ctx[i].tsn == tsn))
            {
                return &m_tsn_ctx[i];
            }
        }
    
        return NULL;
    }
    
    /**
     * @brief Get a pointer to a free context.
     *
     * @return a pointer to context structure or NULL if all contexts are taken.
     */
    static tsn_ctx_t * get_free_tsn_ctx(void)
    {
        NRF_LOG_INFO("get_free_tsn_ctx");
        for (uint8_t i = 0; i < ARRAY_SIZE(m_tsn_ctx); i++)
        {
            if (!m_tsn_ctx[i].taken)
            {
                return &m_tsn_ctx[i];
            }
        }
    
        return NULL;
    }
    
    /**
     * Invalidate context.
     *
     * @param[in] p_tsn_ctx a pointer to transaction context.
     */
    static void invalidate_ctx(tsn_ctx_t * p_tsn_ctx)
    {
        p_tsn_ctx->taken = false;
        p_tsn_ctx->tsn   = 0xFF;
        //p_tsn_ctx->p_cli = NULL;
    }
    /*
    static zb_void_t zb_subscribe_timeout(zb_uint8_t param)
    {
        NRF_LOG_INFO("zb_subscribe_timeout");
        tsn_ctx_t * p_tsn_ctx = get_ctx_by_tsn(param);
    
        if (!p_tsn_ctx)
        {
            return;
        }
        invalidate_ctx(p_tsn_ctx);
    }*/
    /*
    static void cmd_zb_subscribe_unsubscribe_cb(tsn_ctx_t * p_tsn_ctx, zb_uint8_t param)
    {
        NRF_LOG_INFO("unsubscribe  callback ");
        
        zb_ret_t                           zb_err_code;
        zb_buf_t                         * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zcl_configure_reporting_res_t * p_resp = NULL;
        zb_bool_t                          failed = ZB_FALSE;
       
        zb_err_code = ZB_SCHEDULE_ALARM_CANCEL(zb_subscribe_timeout, ZB_ALARM_ANY_PARAM);
        if (zb_err_code != RET_OK)
        {
          //  print_error(p_tsn_ctx->p_cli, "Unable to cancel timeout timer");
          //  goto free_tsn_ctx;
    
           NRF_LOG_INFO("Unable to cancel timeout timer");
        }
    
        // Check if response contains only status code.
        if (sizeof(zb_zcl_configure_reporting_res_t) > ZB_BUF_LEN(p_buf))
        {
            p_resp = (zb_zcl_configure_reporting_res_t*)ZB_BUF_BEGIN(p_buf);
            if (p_resp->status == ZB_ZCL_STATUS_SUCCESS)
            {
              NRF_LOG_INFO("  reporting   is ok ");
            }
            else
            {
               NRF_LOG_INFO( "Error: Unable to configure reporting. Status: %d", p_resp->status);
            }
        }
        // Received a full Configure Reporting Response frame.
        ZB_ZCL_GENERAL_GET_NEXT_CONFIGURE_REPORTING_RES(p_buf, p_resp);
        if (p_resp == NULL)
        {
          NRF_LOG_INFO("Unable to parse configure reporting response");
        }
        while (p_resp != NULL)
        {
            if (p_resp->status == ZB_ZCL_STATUS_SUCCESS)
            {
                switch (p_resp->direction)
                {
                    case ZB_ZCL_CONFIGURE_REPORTING_SEND_REPORT:
                        NRF_LOG_INFO("Local subscription to attribute ID %hx updated\r\n",p_resp->attr_id);
                        break;
    
                    case ZB_ZCL_CONFIGURE_REPORTING_RECV_REPORT:
                        NRF_LOG_INFO( "Remote node subscription to receive attribute ID %hx updated\r\n",   p_resp->attr_id);
                        break;
    
                    default:
                        NRF_LOG_INFO( "Unknown reporting configuration direction for attribute %hx",p_resp->attr_id);
                        failed = ZB_TRUE;
                        break;
                }
            }
            else
            {
                NRF_LOG_INFO( "Unable to configure attribute %hx reporting. Status: %hd\r\n",  p_resp->attr_id, p_resp->status);
                failed = ZB_TRUE;
            }
            ZB_ZCL_GENERAL_GET_NEXT_CONFIGURE_REPORTING_RES(p_buf, p_resp);
        }
        if (failed == ZB_TRUE)
        {
            NRF_LOG_INFO("One or more attributes reporting were not configured successfully");
        }
    }*/
    
    static void print_attr(zb_zcl_parsed_hdr_t * p_zcl_hdr, zb_uint8_t param)
    {
        NRF_LOG_INFO("Print Attr");
        zb_buf_t                 * p_buf         = ZB_BUF_FROM_REF(param);
        zb_zcl_report_attr_req_t * p_attr_resp   = NULL;
        int                        bytes_written = 0;
        char                       print_buf[255];
    
        if (p_zcl_hdr->addr_data.common_data.source.addr_type == ZB_ZCL_ADDR_TYPE_SHORT)
        {
            NRF_LOG_INFO( "Received value  node 0x%04x", p_zcl_hdr->addr_data.common_data.source.u.short_addr);
        }
    
        else
        {
            bytes_written = ieee_addr_to_str(print_buf, sizeof(print_buf), p_zcl_hdr->addr_data.common_data.source.u.ieee_addr);
            if (bytes_written < 0)
            {
               NRF_LOG_INFO( "Received value updates from the remote node (unknown address)");
            }
            else
            {
                NRF_LOG_INFO( "Received value updates from node 0x%s", nrf_log_push(print_buf));
            }
        }
        ZB_ZCL_GENERAL_GET_NEXT_REPORT_ATTR_REQ(p_buf, p_attr_resp);
    
        NRF_LOG_INFO("Profile: 0x%04x Cluster: 0x%04x Attribute: 0x%04x Type: %hu Valuesss: %s",
                      p_zcl_hdr->profile_id, 
                      p_zcl_hdr->cluster_id, 
                      p_attr_resp->attr_id,
                      p_attr_resp->attr_type, 
                      nrf_log_push(print_buf));
    
        bytes_written = 0;
    
        while (p_attr_resp != NULL)
        {
            bytes_written = zcl_attr_to_str(&print_buf[bytes_written],
                                            sizeof(print_buf) - bytes_written,
                                            p_attr_resp->attr_type,
                                            p_attr_resp->attr_value);
    
            if (bytes_written < 0)
            {
                NRF_LOG_ERROR("Unable to print updated attribute value");
            }
    
            else
            {
                NRF_LOG_INFO("Profile: 0x%04x Cluster: 0x%04x Attribute: 0x%04x Type: %hu Value: %s",
                              p_zcl_hdr->profile_id, 
                              p_zcl_hdr->cluster_id, 
                              p_attr_resp->attr_id,
                              p_attr_resp->attr_type, 
                              nrf_log_push(print_buf));
            }
            ZB_ZCL_GENERAL_GET_NEXT_REPORT_ATTR_REQ(p_buf, p_attr_resp);
        }
    }
    
    /**@brief The Handler to 'intercept' every frame coming to the endpoint
     *
     * @param param[in]  Reference to a ZBOSS buffer
     *
     * @returns ZB_TRUE if ZCL command was processed.
     */
    static zb_uint8_t ep_handler_report(zb_uint8_t param)
    {
        NRF_LOG_INFO("Ep Handler Report");
        zb_buf_t            *  p_zcl_cmd_buf = (zb_buf_t *)ZB_BUF_FROM_REF(param);
        zb_zcl_parsed_hdr_t *  p_cmd_info    = ZB_GET_BUF_PARAM(p_zcl_cmd_buf, zb_zcl_parsed_hdr_t);
        //tsn_ctx_t           *  p_tsn_ctx;
    
        if (p_cmd_info->cmd_id == ZB_ZCL_CMD_REPORT_ATTRIB)
        {
            NRF_LOG_INFO("print_attr");
            print_attr(p_cmd_info, param);
            ZB_FREE_BUF_BY_REF(param);
            return ZB_TRUE;
        }
        else if (p_cmd_info->cmd_id == ZB_ZCL_CMD_CONFIG_REPORT_RESP)
        {
            // Find command context by ZCL sequence number.
            /*p_tsn_ctx = get_ctx_by_tsn(p_cmd_info->seq_number);
            if (p_tsn_ctx != NULL)
            {
    
                NRF_LOG_WARNING("Unsubscribe cb");
                //cmd_zb_subscribe_unsubscribe_cb(p_tsn_ctx, param);
                return ZB_TRUE;
            }*/
        }
        NRF_LOG_INFO("False Handler report");
        ZB_FREE_BUF_BY_REF(param);
        return ZB_FALSE;
    }
    
     //----------------------------------------------------------------------------------------
     // _ _      ___          _                      _   _          
     //| | |    / __|  _  _  | |__   ___  __   _ _  (_) | |__   ___ 
     //|_  _|   \__ \ | || | | '_ \ (_-< / _| | '_| | | | '_ \ / -_)
     //  |_|    |___/  \_,_| |_.__/ /__/ \__| |_|   |_| |_.__/ \___|
                                                                  
    /*@brief Step 4: Send a subscribe request
     *
     * @param param[in]  Reference to a ZBOSS buffer
     */
    static void subscribe_device(zb_uint8_t param)
    {
        zb_buf_t                         * p_buf  = ZB_BUF_FROM_REF(param);
        configure_reporting_req_t          req;
        tsn_ctx_t                        * p_tsn_cli;
        zb_uint8_t                       * p_cmd_ptr;
        zb_ret_t                           zb_err_code;
        //zb_bool_t                          subscribe;
        zb_ieee_addr_t                     sensor_ieee_adr;
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 4: subscribe_device");
    
    
        req.profile_id   = ZB_AF_HA_PROFILE_ID;
        req.cluster_id   = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;    //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT; //
        req.attr_id      = ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
        req.attr_type    = ZB_ZCL_ATTR_TYPE_16BIT;                //ZB_ZCL_ATTR_TYPE_S16;
    
        req.interval_min = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL;
        req.interval_max = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL;
    
        req.remote_node.addr_short = m_device_ctx.sensor_params.short_address;
        req.remote_addr_mode       = ZB_APS_ADDR_MODE_16_ENDP_PRESENT;      //= parse_address(addr_buf, &req.remote_node, ADDR_ANY);
        req.remote_ep              = m_device_ctx.sensor_params.endpoint; 
        
        p_buf = ZB_GET_OUT_BUF();
    
        NRF_LOG_INFO("Configure Reporting");
    
        p_tsn_cli = get_free_tsn_ctx();
        if (!p_tsn_cli)
        {
            NRF_LOG_ERROR("Too many configure reporting requests");
            ZB_FREE_BUF(p_buf);
            return;
        }
       
        // Configure new tsn context.
        p_tsn_cli->taken = true;
        //p_tsn_cli->p_cli = p_cli;
        p_tsn_cli->tsn   = ZCL_CTX().seq_number;
    
        ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_SRV_REQ(p_buf, 
                                                        p_cmd_ptr, 
                                                        ZB_ZCL_ENABLE_DEFAULT_RESPONSE);
    
        ZB_ZCL_GENERAL_ADD_SEND_REPORT_CONFIGURE_REPORTING_REQ(p_cmd_ptr,
                                                               req.attr_id, 
                                                               req.attr_type, 
                                                               req.interval_min, 
                                                               req.interval_max,
                                                               ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE);
    
        ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ(p_buf, 
                                                    p_cmd_ptr,
                                                    req.remote_node, 
                                                    req.remote_addr_mode, 
                                                    req.remote_ep, 
                                                    SENSOR_LOGGER_ENDPOINT, //CONTROLL_ENDPOINT
                                                    req.profile_id, 
                                                    req.cluster_id, 
                                                    NULL);
    
        NRF_LOG_INFO("Report sended Waiting for Values");
        //zb_err_code = ZB_SCHEDULE_ALARM(zb_subscribe_timeout, p_tsn_cli->tsn, ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT * ZB_TIME_ONE_SECOND);
        if (zb_err_code != RET_OK)
        {
            NRF_LOG_ERROR("Unable to schedule timeout timer");
            invalidate_ctx(p_tsn_cli);
        }
        NRF_LOG_INFO("End");
    }
    
     //----------------------------------------------------------------------------------------
     // ____    _      _             _ 
     //|__ /   | |__  (_)  _ _    __| |
     // |_ \   | '_ \ | | | ' \  / _` |
     //|___/   |_.__/ |_| |_||_| \__,_|
                
    /*@brief A callback function for binding 
     *
     * @param[in]  index of buffer
     */
    static zb_void_t zb_bind_callback(zb_uint8_t param)
    {
        NRF_LOG_INFO("Bind Callback");
        zb_buf_t           * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zdo_bind_resp_t * p_resp = (zb_zdo_bind_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ret_t             zb_err_code;
    
        m_device_ctx.sensor_params.status = p_resp->status; 
    
        if (m_device_ctx.sensor_params.status == ZB_ZDP_STATUS_SUCCESS)
        {	
            NRF_LOG_INFO("Step 7: Bind successfully on Target: 0x%04x, Endpoint: %d", m_device_ctx.sensor_params.short_address, m_device_ctx.sensor_params.endpoint);
            ZB_FREE_BUF_BY_REF(param);	
            //subscribe_device(param);
        }
        else
        {  
            NRF_LOG_WARNING("bind faild %d :(",p_resp->status);
        }
    }
                         
    /*@brief Step 3: Function send a binding request
     *
     * @param[in]  index of buffer
     */
    static zb_void_t bind_device(zb_uint8_t param)
    {   
        zb_buf_t                  * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zdo_bind_req_param_t   * p_req;
        uint8_t			tsn;
        zb_ieee_addr_t              dst_ieee_addr;
        zb_ret_t                    zb_err_code;
        zb_osif_get_ieee_eui64(dst_ieee_addr);
    
        p_buf = ZB_GET_OUT_BUF();
        if (!p_buf)
        {
            NRF_LOG_ERROR("failed to execute command (buf alloc failed)");
            return;
        }
    
        p_req  = ZB_GET_BUF_PARAM(p_buf, zb_zdo_bind_req_param_t);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 3: Try to bind");
    
        //ZB_MEMCPY(&p_req->src_address,           &m_device_ctx.sensor_params.long_address, sizeof(zb_ieee_addr_t));   //ieee address of sensor
        //ZB_MEMCPY(&p_req->dst_address.addr_long, &dst_ieee_addr,                          izeof(zb_ieee_addr_t));   //ieee address of coordinator
    
        //uint8_t var = 7; // Reverse assignment
        for (uint8_t i = 0; i < 8; i++)
        {
            p_req->src_address[i] = m_device_ctx.sensor_params.long_address[i];   //ieee address of sensor
            p_req->dst_address.addr_long[i] = dst_ieee_addr[i];                   //ieee address of coordinator
            //var--;
        }
    
        p_req->dst_addr_mode = /*ZB_APS_ADDR_MODE_64_ENDP_PRESENT;*/ ZB_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
    
        p_req->src_endp      = m_device_ctx.sensor_params.endpoint;               //endpoint of sensor
        p_req->dst_endp      = SENSOR_LOGGER_ENDPOINT;                            //endpoint of coordinator
    
        p_req->cluster_id    = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;                //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;
        p_req->req_dst_addr  = m_device_ctx.sensor_params.short_address;          //short address of sensor
    
    
        //Enclosed the data are output again
        NRF_LOG_INFO("Long address of Sensor");  
        for (uint8_t i = 0; i < 8; i++)
        {
            NRF_LOG_INFO("src_address:    %hx", p_req->src_address[i]);
        }
        NRF_LOG_INFO("Long address of Coordinator");  
        for (uint8_t i = 0; i < 8; i++)
        {
            NRF_LOG_INFO("dst_address:    %hx", p_req->dst_address.addr_long[i]);
        }  
    
        NRF_LOG_INFO("dst_addr_mode:  %d", p_req->dst_addr_mode);
        NRF_LOG_INFO("src_endp:       %d", p_req->src_endp);
        NRF_LOG_INFO("dst_endp:       %d", p_req->dst_endp);
        NRF_LOG_INFO("cluster_id:     0x%04x", p_req->cluster_id);
        NRF_LOG_INFO("req_dst_addr:   0x%04x", p_req->req_dst_addr);
    
        //----
        tsn = zb_zdo_bind_req(ZB_REF_FROM_BUF(p_buf), zb_bind_callback);
    
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_INFO("failed to send request, %d", tsn);
    	return;
        }
        return;
    }
    
     //----------------------------------------------------------------------------------------
     // ___     _                                     _      _       
     //|_  )   (_)  ___   ___   ___         __ _   __| |  __| |  _ _ 
     // / /    | | / -_) / -_) / -_)       / _` | / _` | / _` | | '_|
     ///___|   |_| \___| \___| \___|  ___  \__,_| \__,_| \__,_| |_|  
     //                              |___|                           
    
    /**@brief A callback function for EUI64 address response.
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    static zb_void_t ieee_addr_cb(uint8_t param)
    {
        zb_buf_t                   * p_buf        = ZB_BUF_FROM_REF(param);    
        zb_zdo_ieee_addr_resp_t    * p_resp       = (zb_zdo_ieee_addr_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ieee_addr_t               ieee_addr;
        zb_uint16_t                  nwk_addr;
        zb_address_ieee_ref_t        addr_ref;
        zb_ret_t                     zb_err_code;
        zb_char_t                    addr_buf[8 * 2 + 1];  //   8 bytes (2 characters) plus one byte for null-terminator. 
    
        if (p_resp->status == ZB_ZDP_STATUS_SUCCESS)
        { 
            for (uint8_t i=0; i<8; i++)
            {
                m_device_ctx.sensor_params.long_address[i] = p_resp->ieee_addr_remote_dev[i];
            }
            // ZB_LETOH64(m_device_ctx.sensor_params.long_address, p_resp->ieee_addr_remote_dev);
            UNUSED_RETURN_VALUE(ieee_addr_to_str(addr_buf, sizeof(addr_buf), p_resp->ieee_addr_remote_dev)); //m_device_ctx.sensor_params.long_address));
            NRF_LOG_INFO("Received EUI64 address for device 0x%04x -> %s.", m_device_ctx.sensor_params.short_address, NRF_LOG_PUSH(addr_buf));
            //Netzwerk constant
            zb_err_code = ZB_SCHEDULE_ALARM(bind_device, param, BIND_REQ_DELAY);
            APP_ERROR_CHECK(zb_err_code);
        }
        else
        {
            NRF_LOG_WARNING("Unable to resolve EUI64 source address. Status: %d\r\n", p_resp->status);
        }
        //zb_free_buf(p_buf);
    }
    
    /**@brief STEP 2: Sending a EUI64 request
     *
     * @param[in] bufid     Reference number to ZBOSS memory buffer.
     */
    static zb_void_t zb_ieee_addr_req(zb_uint8_t bufid)
    {
        zb_zdo_ieee_addr_req_t *req = NULL;
        zb_buf_t               *buf = ZB_BUF_FROM_REF(bufid);
        zb_uint8_t              tsn;
    
        ZB_BUF_INITIAL_ALLOC(buf, sizeof(zb_zdo_ieee_addr_req_t), req);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 2: Send an EUI64 request: Device: 0x%04x, Endpoint: %d", m_device_ctx.sensor_params.short_address, m_device_ctx.sensor_params.endpoint);
        
        // Create new IEEE address request and fill with default values.
        req->start_index  = 0;
        req->request_type = 0;
        req->nwk_addr     = m_device_ctx.sensor_params.short_address;
    
        tsn = zb_zdo_ieee_addr_req(bufid, ieee_addr_cb);
        
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_WARNING("Failed to send IEEE address request for address: 0x%04x, error code: %d", m_device_ctx.sensor_params.short_address, tsn);
            //zb_free_buf(p_buf);
        }
    }
    
     //----------------------------------------------------------------------------------------
     // _                    _          _               _                 
     /// |    _ __    __ _  | |_   __  | |_          __| |  ___   ___  __ 
     //| |   | '  \  / _` | |  _| / _| | ' \        / _` | / -_) (_-< / _|
     //|_|   |_|_|_| \__,_|  \__| \__| |_||_|  ___  \__,_| \___| /__/ \__|
     //                                       |___|             
               
    /**@brief A callback function for send match desc
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    static void cmd_zb_match_desc_cb(zb_uint8_t param)
    {
        zb_buf_t                   * p_buf        = ZB_BUF_FROM_REF(param);                               // Resolve buffer number to buffer address
        zb_zdo_match_desc_resp_t   * p_resp       = (zb_zdo_match_desc_resp_t *)ZB_BUF_BEGIN(p_buf);      // Get the begining of the response
        zb_apsde_data_indication_t * p_ind        = ZB_GET_BUF_PARAM(p_buf, zb_apsde_data_indication_t);  // Get the pointer to the parameters buffer, which stores APS layer response
        zb_uint8_t                 * p_match_ep;   
        zb_ret_t                     zb_err_code;
    
        if ((p_resp->status == ZB_ZDP_STATUS_SUCCESS) && (p_resp->match_len > 0))
        {
            p_match_ep = (zb_uint8_t *)(p_resp + 1);
    
            /* We are searching for exact cluster, so only 1 EP may be found */
            m_device_ctx.sensor_params.endpoint      = *p_match_ep;
            m_device_ctx.sensor_params.short_address =  p_ind->src_addr;
    
            /* Match EP list follows right after response header */
            NRF_LOG_INFO("Sensor found on Address: src_addr= %hx ep= %d", p_ind->src_addr, *p_match_ep);
            
            // Netzwerk constant
            zb_err_code = ZB_SCHEDULE_ALARM(zb_ieee_addr_req, param, IEEE_ADDRESSS_REQ_DELAY);
            APP_ERROR_CHECK(zb_err_code);
        }
        else
        {
            NRF_LOG_INFO("Error in callback");
        }
    
        if (param)
        {
            ZB_FREE_BUF_BY_REF(param);
        }
    }
    
    /**@brief STEP 1: Send match request to sensor
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    void send_match_desc_req(zb_uint8_t param)
    {
        zb_buf_t                  *buf = ZB_BUF_FROM_REF(param);
        zb_zdo_match_desc_param_t *req;
        zb_ret_t                   zb_err_code;                  
        ZB_BUF_INITIAL_ALLOC(buf, sizeof(zb_zdo_match_desc_param_t) + (2 + 3) * sizeof(zb_uint16_t), req);
        
        req->nwk_addr = ZB_NWK_BROADCAST_ALL_DEVICES;                   //send to coordinator
        req->addr_of_interest = req->nwk_addr;
        req->profile_id = ZB_AF_HA_PROFILE_ID;                          //0x0104;   //ZB_AF_HA_PROFILE_ID
        req->num_in_clusters = 2;
        req->num_out_clusters = 0;
        req->cluster_list[0] = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;      //0x0402;  //ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT
        req->cluster_list[1] = ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;  //0x0403;  //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 1: Send match request to sensor");
        zb_err_code = zb_zdo_match_desc_req(param, cmd_zb_match_desc_cb);             //ZB_REF_FROM_BUF(buf), cmd_zb_match_desc_cb);
        if(zb_err_code != ZB_ZDP_STATUS_SUCCESS)
        {
            NRF_LOG_ERROR("Failed send match request: %d", zb_err_code);
        }
    }
    
    /**@brief Function for initializing LEDs and Buttons.
     */
    static void leds_buttons_init(void)
    {
    #ifdef  BOARD_PCA10056
        uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
        APP_ERROR_CHECK(err_code);
        /* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
    #else 
        bsp_board_init(BSP_INIT_LEDS);
    #endif
        bsp_board_leds_off();
    }
    
    /**@brief Callback used in order to visualise network steering period.
     *
     * @param[in]   param   Not used. Required by callback type definition.
     */
    static zb_void_t steering_finished(zb_uint8_t param)
    {
        UNUSED_PARAMETER(param);
        NRF_LOG_INFO("Network steering finished");
        bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #ifdef  BOARD_PCA10059
        LED(LED_JOINING, 0);
    #else
        bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
    }
    
    /**@brief Retry to form a Zigbee network. */
    static zb_void_t bdb_restart_top_level_commissioning(zb_uint8_t param)
    {
        UNUSED_RETURN_VALUE(bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING));
    }
    
     //----------------------------------------------------------------------------------------
     // ___   _                        _     _  _                    _   _             
     /// __| (_)  __ _   _ _    __ _  | |   | || |  __ _   _ _    __| | | |  ___   _ _ 
     //\__ \ | | / _` | | ' \  / _` | | |   | __ | / _` | | ' \  / _` | | | / -_) | '_|
     //|___/ |_| \__, | |_||_| \__,_| |_|   |_||_| \__,_| |_||_| \__,_| |_| \___| |_|  
     //          |___/                                                                 
    
    /**@brief ZigBee stack event handler.
     *
     * @param[in]   param   Reference to ZigBee stack buffer used to pass arguments (signal).
     */
    void zboss_signal_handler(zb_uint8_t param)
    {
        /* Read signal description out of memory buffer. */
        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);
        zb_buf_t                 *p_buf       = ZB_BUF_FROM_REF(param);
        zb_ret_t                  zb_err_code;
        zb_bool_t                 comm_status;
    
        switch(sig)
        {
            case ZB_ZDO_SIGNAL_SKIP_STARTUP:
                if (zb_bdb_is_factory_new())
                {
                    NRF_LOG_INFO("Start network steering & formation.");
                    comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING | ZB_BDB_NETWORK_FORMATION);
                    ZB_COMM_STATUS_CHECK(comm_status);
                }
                else
                {
                    comm_status = bdb_start_top_level_commissioning(ZB_BDB_INITIALIZATION);
                    ZB_COMM_STATUS_CHECK(comm_status);
                }
                break;
    
            case ZB_BDB_SIGNAL_DEVICE_FIRST_START: // Device started and commissioned first time after NVRAM erase.
                if (status == RET_OK)
                {
                    if (ZIGBEE_MANUAL_STEERING == ZB_FALSE)
                    {
                        NRF_LOG_INFO("Start network steering.");
                        comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                        ZB_COMM_STATUS_CHECK(comm_status);
                    }
                }
                else
                {
                    NRF_LOG_ERROR("Failed to form network.");
                }
                break;
    
            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)
                {
                    NRF_LOG_ERROR("Device startup failed. Status: %d. Retry network formation after 1 second.", status);
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 0);
    #else
                    bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(bdb_restart_top_level_commissioning, 0, ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            case ZB_BDB_SIGNAL_STEERING:
                if (status == RET_OK)
                {
                    /* Schedule an alarm to notify about the end of steering period */
                    NRF_LOG_INFO("Network steering started");
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 1);
    #else
                    bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(steering_finished, 0, ZB_TIME_ONE_SECOND * ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                else
                {
                    NRF_LOG_INFO("Network steering failed to start. Status: %d. Retry network formation after 1 second.", status);
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 0);
    #else
                    bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(bdb_restart_top_level_commissioning, 0, ZB_TIME_ONE_SECOND);
                    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(p_sg_p, zb_zdo_signal_device_annce_params_t);
                    NRF_LOG_INFO("Device with a short address 0x%04x commissionned", dev_annce_params->device_short_addr);
    
                     /* Check the device address */
                    if (m_device_ctx.sensor_params.short_address == 0xFFFF)
                    {
                          zb_err_code = ZB_SCHEDULE_ALARM(send_match_desc_req, param, MATCH_DESC_REQ_START_DELAY);
                          ZB_ERROR_CHECK(zb_err_code);
                    }
                }
                break;
    
            case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
                if (status != RET_OK)
                {
                    NRF_LOG_WARNING("Production config is not present or invalid");
                }
                break;
    
            case ZB_ZDO_SIGNAL_DEVICE_UPDATE:
                {
                    char ieee_addr_buf[17] = {0};
                    zb_zdo_signal_device_update_params_t * p_update_params;
                    p_update_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_device_update_params_t);
                    UNUSED_RETURN_VALUE(ieee_addr_to_str(ieee_addr_buf, sizeof(ieee_addr_buf), p_update_params->long_addr));//p_update_params->long_addr));
                    NRF_LOG_INFO("(Safety Check) Device has updated its status in the network, short address: 0x%04x, long address: %s, status: %d",
                                  p_update_params->short_addr, 
                                  NRF_LOG_PUSH(ieee_addr_buf), 
                                  p_update_params->status);
                }
                break;
    
            default:
                /* Unhandled signal. For more information see: zb_zdo_app_signal_type_e and zb_ret_e */
                NRF_LOG_INFO("Unhandled signal %d. Status: %d", sig, status);
                break;
        }
    
        /* All callbacks should either reuse or free passed buffers. If param == 0, the buffer is invalid (not passed) */
        if (param)
        {
            ZB_FREE_BUF_BY_REF(param);
        }
    }
    
     //----------------------------------------------------------------------------------------
     // __  __          _        
     //|  \/  |  __ _  (_)  _ _  
     //| |\/| | / _` | | | | ' \ 
     //|_|  |_| \__,_| |_| |_||_|
                               
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        zb_ret_t       zb_err_code;
        zb_ieee_addr_t ieee_addr;
    
        // Initialize.
        timers_init();
        log_init();
        #ifdef  BOARD_PCA10059
         // Harware_init(); 
          gpio_init();
        #else
          leds_buttons_init(); 
        #endif
    
        /* Set ZigBee stack logging level and traffic dump subsystem. */
        ZB_SET_TRACE_LEVEL(ZIGBEE_TRACE_LEVEL);
        ZB_SET_TRACE_MASK(ZIGBEE_TRACE_MASK);
        ZB_SET_TRAF_DUMP_OFF();
    
        /* Initialize ZigBee stack. */
        ZB_INIT("Sensor logger");
    
        /* Set device address to the value read from FICR registers. */
        zb_osif_get_ieee_eui64(ieee_addr);
        zb_set_long_address(ieee_addr);
    
        /* Set channels on which the coordinator will try to create a new network. */
        zb_set_network_coordinator_role(IEEE_CHANNEL_MASK);
        zb_set_max_children(MAX_CHILDREN);
    
        zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
        zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
    
        /* Initialize application context structure. */
        UNUSED_RETURN_VALUE(ZB_MEMSET(&m_device_ctx, 0, sizeof(sensor_logger_ctx_t)));
        /* Set default sensor short_addr. */
        m_device_ctx.sensor_params.short_address = 0xFFFF;
    
        /* Register dimmer switch device context (endpoints). */
        ZB_AF_REGISTER_DEVICE_CTX(&co_controll_ctx);
    
        /* Register callback for handling ZCL commands. */
        ZB_AF_SET_ENDPOINT_HANDLER(SENSOR_LOGGER_ENDPOINT, ep_handler_report);
    
        /* Keep or erase NVRAM to save the network parameters after device reboot or power-off. */
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
    
        /** Start Zigbee Stack. */
        if (ZIGBEE_MANUAL_STEERING == ZB_TRUE)
        {
            zb_err_code = zboss_start_no_autostart();
        }
        else
        {
            zb_err_code = zboss_start();
        }
    
        ZB_ERROR_CHECK(zb_err_code);
        NRF_LOG_INFO("Starting While Loop");
        while(1)
        {
            zboss_main_loop_iteration();
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        }
    }
    
    
    /**
     * @}
     */
    

    // ****************************************************************************
    // Project      : ZigBee Project
    // Processor    : PCA10056
    // Compiler     : SEGGER Embedded Studio
    // Autor        : Jonas T
    // Date         : 06.05.2022
    // Version      : V0.1
    // Description  : Coordinator for reading Multisensor (Sensor logger)
    // ****************************************************************************
    
     //----------------------------------------------------------------------------------------
     // ___               _             _            
     //|_ _|  _ _    __  | |  _  _   __| |  ___   ___
     // | |  | ' \  / _| | | | || | / _` | / -_) (_-<
     //|___| |_||_| \__| |_|  \_,_| \__,_| \___| /__/
                                                   
    #include "zboss_api.h"
    #include "zb_mem_config_max.h"
    #include "zb_error_handler.h"
    #include "zigbee_helpers.h"
    
    #include "app_timer.h"
    #include "boards.h"
    #include "bsp.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "nrf.h"
    #include "nrf_drv_gpiote.h"
    
     //----------------------------------------------------------------------------------------
     // ___           __   _              
     //|   \   ___   / _| (_)  _ _    ___ 
     //| |) | / -_) |  _| | | | ' \  / -_)
     //|___/  \___| |_|   |_| |_||_| \___|
    
    #ifdef  BOARD_PCA10059   
    #include "Hardware_Configuration.h"
    #define LED_ERROR     1
    #define LED_CONNECTED 2
    #define LED_JOINING   3
    
    #define PIN_SCHALTER          NRF_GPIO_PIN_MAP(1, 15)
    #define PIN_TASTER_RED        2
    #define PIN_TASTER_WITHE      NRF_GPIO_PIN_MAP(1, 13)
    #define PIN_TASTER_WITHE_BIG  29
    #else
    
    #endif
    
    #define ERASE_PERSISTENT_CONFIG             ZB_TRUE   // See join process       /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. NOTE: If this option is set to ZB_TRUE then do full device erase for all network devices before running other samples. */
    #define MAX_CHILDREN                        10                                  /**< The maximum amount of connected devices. Setting this value to 0 disables association to this device.  */
    #define IEEE_CHANNEL_MASK                   (1l << ZIGBEE_CHANNEL)              /**< Scan only one, predefined channel to find the coordinator. */
    
    #define MATCH_DESC_REQ_START_DELAY          (2 * ZB_TIME_ONE_SECOND)            /**< Delay between the light switch startup and light bulb finding procedure. */
    #define IEEE_ADDRESSS_REQ_DELAY             (2 * ZB_TIME_ONE_SECOND)            /**< Delay between MATCH_DESC_REQ and IEEE_ADDRESSS_REQ */
    #define BIND_REQ_DELAY                      (2 * ZB_TIME_ONE_SECOND)            /**< Delay between IEEE_ADDRESSS_REQ and BIND_REQ */
    // #define MATCH_DESC_REQ_TIMEOUT              (5 * ZB_TIME_ONE_SECOND)            /**< Timeout for finding procedure. */
    #define TIME_ONE_SECOND                     ZB_TIME_ONE_SECOND
    #define MATCH_DESC_REQ_ROLE                 ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE    /**< Find only non-sleepy device. */
    
    // (I have another Button input module for Dongle, but now i make it on PCA10056)
    #ifdef  BOARD_PCA10059                                                          /**< If it is Dongle */
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_0                       /**< LED indicating that network is opened for new nodes. */
    #define LIGHT_SWITCH_BUTTON_ON            PIN_TASTER_WITHE                      /**< Button ID used to switch on the light bulb. */
    #define LIGHT_SWITCH_BUTTON_OFF           PIN_TASTER_RED                        /**< Button ID used to switch off the light bulb. */
    #define ZIGBEE_NETWORK_REOPEN_BUTTON      PIN_TASTER_WITHE_BIG                  /**< Button which reopens the Zigbee Network. */
    #else
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_2                       /**< LED indicating that network is opened for new nodes. */
    #define BULB_FOUND_LED                    BSP_BOARD_LED_3                       /**< LED indicating that light witch found a light bulb to control. (LED Connected)*/
    #define ZIGBEE_NETWORK_REOPEN_BUTTON      BSP_BOARD_BUTTON_0                    /**< Button which reopens the Zigbee Network. */
    #define LIGHT_SWITCH_BUTTON_ON            BSP_BOARD_BUTTON_1                    /**< Button ID used to switch on the light bulb. */
    #define LIGHT_SWITCH_BUTTON_OFF           BSP_BOARD_BUTTON_2                    /**< Button ID used to switch off the light bulb. */
    #endif
    
    #define ZIGBEE_MANUAL_STEERING              ZB_FALSE                              /**< If set to 1 then device will not open the network after forming or reboot. */
    
    //#define LIGHT_SWITCH_BUTTON_THRESHOLD       ZB_TIME_ONE_SECOND                      /**< Number of beacon intervals the button should be pressed to dimm the light bulb. */
    //#define LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO  ZB_MILLISECONDS_TO_BEACON_INTERVAL(50)  /**< Delay between button state checks used in order to detect button long press. */
    //#define LIGHT_SWITCH_BUTTON_LONG_POLL_TMO   ZB_MILLISECONDS_TO_BEACON_INTERVAL(300) /**< Time after which the button state is checked again to detect button hold - the dimm command is sent again. */
    
    // Defines how long to wait, in seconds, for Configure Reporting Response.
    #define ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT     5
    // Defines how many report attribute requests can be run concurrently.
    #define ZIGBEE_CONFIGURE_REPORT_TSN                  3
    // Defines default value for minimum interval inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL 1
    // Defines default value for maximum interval inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL 60
    // Defines default value for minimum value change inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE NULL
    
    #define SENSOR_LOGGER_ENDPOINT  12   // Valid Endpoint 1-254
    #define POWER_SOURCE            ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE
    
    #ifndef ZB_COORDINATOR_ROLE
    #error Define ZB_COORDINATOR_ROLE to compile coordinator source code.
    #endif
    
     //----------------------------------------------------------------------------------------
     //__   __               _          _      _            
     //\ \ / /  __ _   _ _  (_)  __ _  | |__  | |  ___   ___
     // \ V /  / _` | | '_| | | / _` | | '_ \ | | / -_) (_-<
     //  \_/   \__,_| |_|   |_| \__,_| |_.__/ |_| \___| /__/
    
    typedef struct _sensor_parameter_
    {
      zb_uint8_t              endpoint;
      zb_uint16_t             short_address;
      zb_uint8_t              status;
      zb_ieee_addr_t          long_address;
    } sensor_parameter_t;
    
    typedef struct _sensor_logger_button_
    {
      zb_bool_t               button_pressed;
      zb_time_t               timestamp;
    } sensor_logger_button_t;
    
    typedef struct _sensor_logger_params_
    {
      //zb_uint8_t            endpoint;
      //zb_ieee_addr_t        long_address;
    } sensor_logger_params_t; 
                  
    typedef struct _coordinator_ctx_
    {
      sensor_parameter_t              sensor_params;
      sensor_logger_button_t          button;
      sensor_logger_params_t          co_params;
    } sensor_logger_ctx_t;                            //ctx = (Device) context
    
    typedef struct {
        zb_uint16_t   profile_id;
        zb_uint16_t   cluster_id;
        zb_uint16_t   attr_id;
        zb_uint8_t    attr_type;
        zb_uint16_t   interval_min;
        zb_uint16_t   interval_max;
        zb_addr_u     remote_node;
        addr_type_t   remote_addr_mode;
        zb_uint8_t    remote_ep;
    } configure_reporting_req_t;
    
    // This structure allows for binding ZBOSS transaction and CLI object.
    typedef struct {
        //nrf_cli_t const * p_cli;
        uint8_t             tsn;
        bool                taken;
        bool                is_broadcast;
    } tsn_ctx_t;
    
    static sensor_logger_ctx_t  m_device_ctx;
    static zb_uint8_t           m_attr_zcl_version    = ZB_ZCL_VERSION;
    static zb_uint8_t           m_attr_power_source   = POWER_SOURCE;
    static zb_uint16_t          m_attr_identify_time  = 0;
    static tsn_ctx_t m_tsn_ctx[ZIGBEE_CONFIGURE_REPORT_TSN];
    
     //----------------------------------------------------------------------------------------
     //  ___                 __   _                              _     _              
     // / __|  ___   _ _    / _| (_)  __ _   _  _   _ _   __ _  | |_  (_)  ___   _ _  
     //| (__  / _ \ | ' \  |  _| | | / _` | | || | | '_| / _` | |  _| | | / _ \ | ' \ 
     // \___| \___/ |_||_| |_|   |_| \__, |  \_,_| |_|   \__,_|  \__| |_| \___/ |_||_|
     //                              |___/                                            
    
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
    
    ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CLUSTER_LIST(co_controll_cluster,
                                                  basic_attr_list,
                                                  identify_attr_list);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_EP(co_controll_ep,
                                        SENSOR_LOGGER_ENDPOINT,
                                        co_controll_cluster);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CTX(co_controll_ctx, co_controll_ep);
    
     //----------------------------------------------------------------------------------------
     // ___                      _     _              
     //| __|  _  _   _ _    __  | |_  (_)  ___   _ _  
     //| _|  | || | | ' \  / _| |  _| | | / _ \ | ' \ 
     //|_|    \_,_| |_||_| \__|  \__| |_| \___/ |_||_|
    
    /**@brief Function for initializing the nrf log module.                                   
     */                                                                                       
    static void log_init(void)                                                                
    {                                                                                         
        ret_code_t err_code;
        
        err_code = NRF_LOG_INIT(NULL);                                             
        APP_ERROR_CHECK(err_code);                                                            
                                                                                              
        NRF_LOG_DEFAULT_BACKENDS_INIT();                                                      
    }                                                                                         
                                                                                              
    /**@brief Function for the Timer initialization.                                          
     *                                                                                        
     * @details Initializes the timer module. This creates and starts application timers.     
     */                                                                                       
    static void timers_init(void)                                                             
    {                                                                                         
        ret_code_t err_code;                                                                  
                                                                                              
        // Initialize timer module.                                                           
        err_code = app_timer_init();                                                          
        APP_ERROR_CHECK(err_code);                                                            
    }                                                                                         
    
    /**@brief Callback for button events. (ONLY FOR DONGLE)                          
     *                                                                                        
     * @param[in]   pin      Pin number
     * @param[in]   action   Pin action     
     */    
    #ifdef  BOARD_PCA10059
    static void button_interrup_handle(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        zb_ret_t            zb_err_code;
        zb_bool_t           comm_status;
        zb_uint32_t         button;
        bool send_command = false;
    
        switch (pin)
        {
            case PIN_TASTER_WITHE_BIG:
                comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                
                if (comm_status)
                {
                    NRF_LOG_INFO("Top level comissioning restated");
                }
                else
                {
                    NRF_LOG_INFO("Top level comissioning hasn't finished yet!");
                }
                break;
    
            case PIN_TASTER_WITHE:
                //button = LIGHT_SWITCH_BUTTON_ON;
                //send_command = true;
                break;
    
            case PIN_TASTER_RED:
                //button = LIGHT_SWITCH_BUTTON_OFF;
                //send_command = true;
                break;
            break;
    
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", pin);
                break;
        }
        //if (send_command)
        //{
        //    if (!m_device_ctx.button.button_pressed)
        //    {
        //         m_device_ctx.button.button_pressed = ZB_TRUE;
        //         m_device_ctx.button.timestamp = ZB_TIMER_GET();
    
        //         zb_err_code = ZB_SCHEDULE_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO);
        //         ZB_ERROR_CHECK(zb_err_code);
        //    }
        //}
    }
    
    
    static void gpio_init()
    {
        ret_code_t err_code;   
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true); // Falling edge interrupt deetection
        in_config.pull = NRF_GPIO_PIN_PULLUP;
    
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_WITHE_BIG, &in_config, button_interrup_handle); //Initialize the interrupt pin
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_WITHE, &in_config, button_interrup_handle);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_RED, &in_config, button_interrup_handle);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_WITHE_BIG, true); //Enable the interrupt events
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_WITHE, true);
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_RED, true);
    }
    
    //https://www.youtube.com/watch?v=f1A2zWKo6Fk
    #else
    
    /**@brief Callback for button events. (PCA10056)                                                    
     *                                                                                        
     * @param[in]   evt      Incoming event from the BSP subsystem.                           
     */                                                                                       
    static void buttons_handler(bsp_event_t evt)
    {
        NRF_LOG_INFO("Button Pressed %d", evt);
        zb_ret_t            zb_err_code;
        zb_bool_t           comm_status;
        zb_uint32_t         button;
    
        bool send_command = false;
    
        switch(evt)
        {
            case BSP_EVENT_KEY_0:
                comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                
                if (comm_status)
                {
                    NRF_LOG_INFO("Top level comissioning restated");
                }
                else
                {
                    NRF_LOG_INFO("Top level comissioning hasn't finished yet!");
                }
                break;
    
            case BSP_EVENT_KEY_1:
                //button = LIGHT_SWITCH_BUTTON_ON;
                //send_command = true;
                break;
    
            case BSP_EVENT_KEY_2:
                //button = LIGHT_SWITCH_BUTTON_OFF;
                //send_command = true;
                break;
            case BSP_EVENT_KEY_3:
                NRF_LOG_INFO("Nothing declared Button 4");
                break;
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
                break;
        }
    }
    #endif
    
    /**@brief Function to convert data types                                                                    
     */      
    int zcl_attr_to_str(char * p_str_buf, uint16_t buf_len, zb_uint16_t attr_type, zb_uint8_t * p_attr)
    {
        NRF_LOG_INFO("zcl_attr_to_str");
        int bytes_written = 0;
        int string_len;
        int i;
    
        if ((p_str_buf == NULL) || (p_attr == NULL))
        {
            return -1;
        }
    
        switch (attr_type)
        {
            /* Boolean */
            case ZB_ZCL_ATTR_TYPE_BOOL:
                bytes_written = snprintf(p_str_buf, buf_len, "%s", *((zb_bool_t *)p_attr) ? "True" : "False");
                break;
    
            /* 1 byte */
            case ZB_ZCL_ATTR_TYPE_8BIT:
            case ZB_ZCL_ATTR_TYPE_8BITMAP:
            case ZB_ZCL_ATTR_TYPE_U8:
            case ZB_ZCL_ATTR_TYPE_8BIT_ENUM:
                bytes_written = snprintf(p_str_buf, buf_len, "%hu", *((zb_uint8_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S8:
                bytes_written = snprintf(p_str_buf, buf_len, "%hd", *((zb_int8_t*)p_attr));
                break;
    
            /* 2 bytes */
            case ZB_ZCL_ATTR_TYPE_16BIT:
            case ZB_ZCL_ATTR_TYPE_16BITMAP:
            case ZB_ZCL_ATTR_TYPE_U16:
            case ZB_ZCL_ATTR_TYPE_16BIT_ENUM:
                bytes_written = snprintf(p_str_buf, buf_len, "%hu", *((zb_uint16_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S16:
                bytes_written = snprintf(p_str_buf, buf_len, "%hd", *((zb_int16_t*)p_attr));
                break;
    
            /* 4 bytes */
            case ZB_ZCL_ATTR_TYPE_32BIT:
            case ZB_ZCL_ATTR_TYPE_32BITMAP:
            case ZB_ZCL_ATTR_TYPE_U32:
                bytes_written = snprintf(p_str_buf, buf_len, "%u", *((zb_uint32_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S32:
                bytes_written = snprintf(p_str_buf, buf_len, "%d", *((zb_int32_t*)p_attr));
                break;
    
            /* String */
            case ZB_ZCL_ATTR_TYPE_CHAR_STRING:
                string_len = p_attr[0];
                p_attr++;
    
                if ((buf_len - bytes_written) < (string_len + 1))
                {
                    return -1;
                }
    
                for (i = 0; i < string_len; i++)
                {
                    /*lint -save -e661 */
                    p_str_buf[bytes_written + i] = ((char *)p_attr)[i];
                    /*lint -restore */
                }
                p_str_buf[bytes_written + i] = '\0';
                bytes_written += string_len + 1;
                break;
    
            case ZB_ZCL_ATTR_TYPE_IEEE_ADDR:
                /*lint -e661 -e662 -save */
                bytes_written = to_hex_str(p_str_buf, buf_len, (const uint8_t *)p_attr, sizeof(zb_64bit_addr_t), true);
                /*lint -restore */
                break;
    
            default:
                bytes_written = snprintf(p_str_buf, buf_len, "Value type 0x%x unsupported", attr_type);
                break;
        }
    
        return bytes_written;
    }
    
    /**
     * @brief Return a pointer to context with the given transaction sequence number.
     *
     * @param[in] tsn ZBOSS transaction sequence number
     *
     * @return a pointer to context or NULL if context for given TSN wasn't found.
     */
    static tsn_ctx_t * get_ctx_by_tsn(uint8_t tsn)
    {
        NRF_LOG_INFO("get_ctx_by_tsn");
        for (uint8_t i = 0; i < ARRAY_SIZE(m_tsn_ctx); i++)
        {
            if ((m_tsn_ctx[i].taken == true) && (m_tsn_ctx[i].tsn == tsn))
            {
                return &m_tsn_ctx[i];
            }
        }
    
        return NULL;
    }
    
    /**
     * @brief Get a pointer to a free context.
     *
     * @return a pointer to context structure or NULL if all contexts are taken.
     */
    static tsn_ctx_t * get_free_tsn_ctx(void)
    {
        NRF_LOG_INFO("get_free_tsn_ctx");
        for (uint8_t i = 0; i < ARRAY_SIZE(m_tsn_ctx); i++)
        {
            if (!m_tsn_ctx[i].taken)
            {
                return &m_tsn_ctx[i];
            }
        }
    
        return NULL;
    }
    
    /**
     * Invalidate context.
     *
     * @param[in] p_tsn_ctx a pointer to transaction context.
     */
    static void invalidate_ctx(tsn_ctx_t * p_tsn_ctx)
    {
        p_tsn_ctx->taken = false;
        p_tsn_ctx->tsn   = 0xFF;
        //p_tsn_ctx->p_cli = NULL;
    }
    /*
    static zb_void_t zb_subscribe_timeout(zb_uint8_t param)
    {
        NRF_LOG_INFO("zb_subscribe_timeout");
        tsn_ctx_t * p_tsn_ctx = get_ctx_by_tsn(param);
    
        if (!p_tsn_ctx)
        {
            return;
        }
        invalidate_ctx(p_tsn_ctx);
    }*/
    /*
    static void cmd_zb_subscribe_unsubscribe_cb(tsn_ctx_t * p_tsn_ctx, zb_uint8_t param)
    {
        NRF_LOG_INFO("unsubscribe  callback ");
        
        zb_ret_t                           zb_err_code;
        zb_buf_t                         * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zcl_configure_reporting_res_t * p_resp = NULL;
        zb_bool_t                          failed = ZB_FALSE;
       
        zb_err_code = ZB_SCHEDULE_ALARM_CANCEL(zb_subscribe_timeout, ZB_ALARM_ANY_PARAM);
        if (zb_err_code != RET_OK)
        {
          //  print_error(p_tsn_ctx->p_cli, "Unable to cancel timeout timer");
          //  goto free_tsn_ctx;
    
           NRF_LOG_INFO("Unable to cancel timeout timer");
        }
    
        // Check if response contains only status code.
        if (sizeof(zb_zcl_configure_reporting_res_t) > ZB_BUF_LEN(p_buf))
        {
            p_resp = (zb_zcl_configure_reporting_res_t*)ZB_BUF_BEGIN(p_buf);
            if (p_resp->status == ZB_ZCL_STATUS_SUCCESS)
            {
              NRF_LOG_INFO("  reporting   is ok ");
            }
            else
            {
               NRF_LOG_INFO( "Error: Unable to configure reporting. Status: %d", p_resp->status);
            }
        }
        // Received a full Configure Reporting Response frame.
        ZB_ZCL_GENERAL_GET_NEXT_CONFIGURE_REPORTING_RES(p_buf, p_resp);
        if (p_resp == NULL)
        {
          NRF_LOG_INFO("Unable to parse configure reporting response");
        }
        while (p_resp != NULL)
        {
            if (p_resp->status == ZB_ZCL_STATUS_SUCCESS)
            {
                switch (p_resp->direction)
                {
                    case ZB_ZCL_CONFIGURE_REPORTING_SEND_REPORT:
                        NRF_LOG_INFO("Local subscription to attribute ID %hx updated\r\n",p_resp->attr_id);
                        break;
    
                    case ZB_ZCL_CONFIGURE_REPORTING_RECV_REPORT:
                        NRF_LOG_INFO( "Remote node subscription to receive attribute ID %hx updated\r\n",   p_resp->attr_id);
                        break;
    
                    default:
                        NRF_LOG_INFO( "Unknown reporting configuration direction for attribute %hx",p_resp->attr_id);
                        failed = ZB_TRUE;
                        break;
                }
            }
            else
            {
                NRF_LOG_INFO( "Unable to configure attribute %hx reporting. Status: %hd\r\n",  p_resp->attr_id, p_resp->status);
                failed = ZB_TRUE;
            }
            ZB_ZCL_GENERAL_GET_NEXT_CONFIGURE_REPORTING_RES(p_buf, p_resp);
        }
        if (failed == ZB_TRUE)
        {
            NRF_LOG_INFO("One or more attributes reporting were not configured successfully");
        }
    }*/
    
    static void print_attr(zb_zcl_parsed_hdr_t * p_zcl_hdr, zb_uint8_t param)
    {
        NRF_LOG_INFO("Print Attr");
        zb_buf_t                 * p_buf         = ZB_BUF_FROM_REF(param);
        zb_zcl_report_attr_req_t * p_attr_resp   = NULL;
        int                        bytes_written = 0;
        char                       print_buf[255];
    
        if (p_zcl_hdr->addr_data.common_data.source.addr_type == ZB_ZCL_ADDR_TYPE_SHORT)
        {
            NRF_LOG_INFO( "Received value  node 0x%04x", p_zcl_hdr->addr_data.common_data.source.u.short_addr);
        }
    
        else
        {
            bytes_written = ieee_addr_to_str(print_buf, sizeof(print_buf), p_zcl_hdr->addr_data.common_data.source.u.ieee_addr);
            if (bytes_written < 0)
            {
               NRF_LOG_INFO( "Received value updates from the remote node (unknown address)");
            }
            else
            {
                NRF_LOG_INFO( "Received value updates from node 0x%s", nrf_log_push(print_buf));
            }
        }
        ZB_ZCL_GENERAL_GET_NEXT_REPORT_ATTR_REQ(p_buf, p_attr_resp);
    
        NRF_LOG_INFO("Profile: 0x%04x Cluster: 0x%04x Attribute: 0x%04x Type: %hu Valuesss: %s",
                      p_zcl_hdr->profile_id, 
                      p_zcl_hdr->cluster_id, 
                      p_attr_resp->attr_id,
                      p_attr_resp->attr_type, 
                      nrf_log_push(print_buf));
    
        bytes_written = 0;
    
        while (p_attr_resp != NULL)
        {
            bytes_written = zcl_attr_to_str(&print_buf[bytes_written],
                                            sizeof(print_buf) - bytes_written,
                                            p_attr_resp->attr_type,
                                            p_attr_resp->attr_value);
    
            if (bytes_written < 0)
            {
                NRF_LOG_ERROR("Unable to print updated attribute value");
            }
    
            else
            {
                NRF_LOG_INFO("Profile: 0x%04x Cluster: 0x%04x Attribute: 0x%04x Type: %hu Value: %s",
                              p_zcl_hdr->profile_id, 
                              p_zcl_hdr->cluster_id, 
                              p_attr_resp->attr_id,
                              p_attr_resp->attr_type, 
                              nrf_log_push(print_buf));
            }
            ZB_ZCL_GENERAL_GET_NEXT_REPORT_ATTR_REQ(p_buf, p_attr_resp);
        }
    }
    
    /**@brief The Handler to 'intercept' every frame coming to the endpoint
     *
     * @param param[in]  Reference to a ZBOSS buffer
     *
     * @returns ZB_TRUE if ZCL command was processed.
     */
    static zb_uint8_t ep_handler_report(zb_uint8_t param)
    {
        NRF_LOG_INFO("Ep Handler Report");
        zb_buf_t            *  p_zcl_cmd_buf = (zb_buf_t *)ZB_BUF_FROM_REF(param);
        zb_zcl_parsed_hdr_t *  p_cmd_info    = ZB_GET_BUF_PARAM(p_zcl_cmd_buf, zb_zcl_parsed_hdr_t);
        //tsn_ctx_t           *  p_tsn_ctx;
    
        if (p_cmd_info->cmd_id == ZB_ZCL_CMD_REPORT_ATTRIB)
        {
            NRF_LOG_INFO("print_attr");
            print_attr(p_cmd_info, param);
            ZB_FREE_BUF_BY_REF(param);
            return ZB_TRUE;
        }
        else if (p_cmd_info->cmd_id == ZB_ZCL_CMD_CONFIG_REPORT_RESP)
        {
            // Find command context by ZCL sequence number.
            /*p_tsn_ctx = get_ctx_by_tsn(p_cmd_info->seq_number);
            if (p_tsn_ctx != NULL)
            {
    
                NRF_LOG_WARNING("Unsubscribe cb");
                //cmd_zb_subscribe_unsubscribe_cb(p_tsn_ctx, param);
                return ZB_TRUE;
            }*/
        }
        NRF_LOG_INFO("False Handler report");
        ZB_FREE_BUF_BY_REF(param);
        return ZB_FALSE;
    }
    
     //----------------------------------------------------------------------------------------
     // _ _      ___          _                      _   _          
     //| | |    / __|  _  _  | |__   ___  __   _ _  (_) | |__   ___ 
     //|_  _|   \__ \ | || | | '_ \ (_-< / _| | '_| | | | '_ \ / -_)
     //  |_|    |___/  \_,_| |_.__/ /__/ \__| |_|   |_| |_.__/ \___|
                                                                  
    /*@brief Step 4: Send a subscribe request
     *
     * @param param[in]  Reference to a ZBOSS buffer
     */
    static void subscribe_device(zb_uint8_t param)
    {
        zb_buf_t                         * p_buf  = ZB_BUF_FROM_REF(param);
        configure_reporting_req_t          req;
        tsn_ctx_t                        * p_tsn_cli;
        zb_uint8_t                       * p_cmd_ptr;
        zb_ret_t                           zb_err_code;
        //zb_bool_t                          subscribe;
        zb_ieee_addr_t                     sensor_ieee_adr;
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 4: subscribe_device");
    
    
        req.profile_id   = ZB_AF_HA_PROFILE_ID;
        req.cluster_id   = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;    //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT; //
        req.attr_id      = ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
        req.attr_type    = ZB_ZCL_ATTR_TYPE_16BIT;                //ZB_ZCL_ATTR_TYPE_S16;
    
        req.interval_min = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL;
        req.interval_max = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL;
    
        req.remote_node.addr_short = m_device_ctx.sensor_params.short_address;
        req.remote_addr_mode       = ZB_APS_ADDR_MODE_16_ENDP_PRESENT;      //= parse_address(addr_buf, &req.remote_node, ADDR_ANY);
        req.remote_ep              = m_device_ctx.sensor_params.endpoint; 
        
        p_buf = ZB_GET_OUT_BUF();
    
        NRF_LOG_INFO("Configure Reporting");
    
        p_tsn_cli = get_free_tsn_ctx();
        if (!p_tsn_cli)
        {
            NRF_LOG_ERROR("Too many configure reporting requests");
            ZB_FREE_BUF(p_buf);
            return;
        }
       
        // Configure new tsn context.
        p_tsn_cli->taken = true;
        //p_tsn_cli->p_cli = p_cli;
        p_tsn_cli->tsn   = ZCL_CTX().seq_number;
    
        ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_SRV_REQ(p_buf, 
                                                        p_cmd_ptr, 
                                                        ZB_ZCL_ENABLE_DEFAULT_RESPONSE);
    
        ZB_ZCL_GENERAL_ADD_SEND_REPORT_CONFIGURE_REPORTING_REQ(p_cmd_ptr,
                                                               req.attr_id, 
                                                               req.attr_type, 
                                                               req.interval_min, 
                                                               req.interval_max,
                                                               ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE);
    
        ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ(p_buf, 
                                                    p_cmd_ptr,
                                                    req.remote_node, 
                                                    req.remote_addr_mode, 
                                                    req.remote_ep, 
                                                    SENSOR_LOGGER_ENDPOINT, //CONTROLL_ENDPOINT
                                                    req.profile_id, 
                                                    req.cluster_id, 
                                                    NULL);
    
        NRF_LOG_INFO("Report sended Waiting for Values");
        //zb_err_code = ZB_SCHEDULE_ALARM(zb_subscribe_timeout, p_tsn_cli->tsn, ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT * ZB_TIME_ONE_SECOND);
        if (zb_err_code != RET_OK)
        {
            NRF_LOG_ERROR("Unable to schedule timeout timer");
            invalidate_ctx(p_tsn_cli);
        }
        NRF_LOG_INFO("End");
    }
    
     //----------------------------------------------------------------------------------------
     // ____    _      _             _ 
     //|__ /   | |__  (_)  _ _    __| |
     // |_ \   | '_ \ | | | ' \  / _` |
     //|___/   |_.__/ |_| |_||_| \__,_|
                
    /*@brief A callback function for binding 
     *
     * @param[in]  index of buffer
     */
    static zb_void_t zb_bind_callback(zb_uint8_t param)
    {
        NRF_LOG_INFO("Bind Callback");
        zb_buf_t           * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zdo_bind_resp_t * p_resp = (zb_zdo_bind_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ret_t             zb_err_code;
    
        m_device_ctx.sensor_params.status = p_resp->status; 
    
        if (m_device_ctx.sensor_params.status == ZB_ZDP_STATUS_SUCCESS)
        {	
            NRF_LOG_INFO("Step 7: Bind successfully on Target: 0x%04x, Endpoint: %d", m_device_ctx.sensor_params.short_address, m_device_ctx.sensor_params.endpoint);
            ZB_FREE_BUF_BY_REF(param);	
            //subscribe_device(param);
        }
        else
        {  
            NRF_LOG_WARNING("bind faild %d :(",p_resp->status);
        }
    }
                         
    /*@brief Step 3: Function send a binding request
     *
     * @param[in]  index of buffer
     */
    static zb_void_t bind_device(zb_uint8_t param)
    {   
        zb_buf_t                  * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zdo_bind_req_param_t   * p_req;
        uint8_t			tsn;
        zb_ieee_addr_t              dst_ieee_addr;
        zb_ret_t                    zb_err_code;
        zb_osif_get_ieee_eui64(dst_ieee_addr);
    
        p_buf = ZB_GET_OUT_BUF();
        if (!p_buf)
        {
            NRF_LOG_ERROR("failed to execute command (buf alloc failed)");
            return;
        }
    
        p_req  = ZB_GET_BUF_PARAM(p_buf, zb_zdo_bind_req_param_t);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 3: Try to bind");
    
        //ZB_MEMCPY(&p_req->src_address,           &m_device_ctx.sensor_params.long_address, sizeof(zb_ieee_addr_t));   //ieee address of sensor
        //ZB_MEMCPY(&p_req->dst_address.addr_long, &dst_ieee_addr,                          izeof(zb_ieee_addr_t));   //ieee address of coordinator
    
        //uint8_t var = 7; // Reverse assignment
        for (uint8_t i = 0; i < 8; i++)
        {
            p_req->src_address[i] = m_device_ctx.sensor_params.long_address[i];   //ieee address of sensor
            p_req->dst_address.addr_long[i] = dst_ieee_addr[i];                   //ieee address of coordinator
            //var--;
        }
    
        p_req->dst_addr_mode = /*ZB_APS_ADDR_MODE_64_ENDP_PRESENT;*/ ZB_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
    
        p_req->src_endp      = m_device_ctx.sensor_params.endpoint;               //endpoint of sensor
        p_req->dst_endp      = SENSOR_LOGGER_ENDPOINT;                            //endpoint of coordinator
    
        p_req->cluster_id    = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;                //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;
        p_req->req_dst_addr  = m_device_ctx.sensor_params.short_address;          //short address of sensor
    
    
        //Enclosed the data are output again
        NRF_LOG_INFO("Long address of Sensor");  
        for (uint8_t i = 0; i < 8; i++)
        {
            NRF_LOG_INFO("src_address:    %hx", p_req->src_address[i]);
        }
        NRF_LOG_INFO("Long address of Coordinator");  
        for (uint8_t i = 0; i < 8; i++)
        {
            NRF_LOG_INFO("dst_address:    %hx", p_req->dst_address.addr_long[i]);
        }  
    
        NRF_LOG_INFO("dst_addr_mode:  %d", p_req->dst_addr_mode);
        NRF_LOG_INFO("src_endp:       %d", p_req->src_endp);
        NRF_LOG_INFO("dst_endp:       %d", p_req->dst_endp);
        NRF_LOG_INFO("cluster_id:     0x%04x", p_req->cluster_id);
        NRF_LOG_INFO("req_dst_addr:   0x%04x", p_req->req_dst_addr);
    
        //----
        tsn = zb_zdo_bind_req(ZB_REF_FROM_BUF(p_buf), zb_bind_callback);
    
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_INFO("failed to send request, %d", tsn);
    	return;
        }
        return;
    }
    
     //----------------------------------------------------------------------------------------
     // ___     _                                     _      _       
     //|_  )   (_)  ___   ___   ___         __ _   __| |  __| |  _ _ 
     // / /    | | / -_) / -_) / -_)       / _` | / _` | / _` | | '_|
     ///___|   |_| \___| \___| \___|  ___  \__,_| \__,_| \__,_| |_|  
     //                              |___|                           
    
    /**@brief A callback function for EUI64 address response.
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    static zb_void_t ieee_addr_cb(uint8_t param)
    {
        zb_buf_t                   * p_buf        = ZB_BUF_FROM_REF(param);    
        zb_zdo_ieee_addr_resp_t    * p_resp       = (zb_zdo_ieee_addr_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ieee_addr_t               ieee_addr;
        zb_uint16_t                  nwk_addr;
        zb_address_ieee_ref_t        addr_ref;
        zb_ret_t                     zb_err_code;
        zb_char_t                    addr_buf[8 * 2 + 1];  //   8 bytes (2 characters) plus one byte for null-terminator. 
    
        if (p_resp->status == ZB_ZDP_STATUS_SUCCESS)
        { 
            for (uint8_t i=0; i<8; i++)
            {
                m_device_ctx.sensor_params.long_address[i] = p_resp->ieee_addr_remote_dev[i];
            }
            // ZB_LETOH64(m_device_ctx.sensor_params.long_address, p_resp->ieee_addr_remote_dev);
            UNUSED_RETURN_VALUE(ieee_addr_to_str(addr_buf, sizeof(addr_buf), p_resp->ieee_addr_remote_dev)); //m_device_ctx.sensor_params.long_address));
            NRF_LOG_INFO("Received EUI64 address for device 0x%04x -> %s.", m_device_ctx.sensor_params.short_address, NRF_LOG_PUSH(addr_buf));
            //Netzwerk constant
            zb_err_code = ZB_SCHEDULE_ALARM(bind_device, param, BIND_REQ_DELAY);
            APP_ERROR_CHECK(zb_err_code);
        }
        else
        {
            NRF_LOG_WARNING("Unable to resolve EUI64 source address. Status: %d\r\n", p_resp->status);
        }
        //zb_free_buf(p_buf);
    }
    
    /**@brief STEP 2: Sending a EUI64 request
     *
     * @param[in] bufid     Reference number to ZBOSS memory buffer.
     */
    static zb_void_t zb_ieee_addr_req(zb_uint8_t bufid)
    {
        zb_zdo_ieee_addr_req_t *req = NULL;
        zb_buf_t               *buf = ZB_BUF_FROM_REF(bufid);
        zb_uint8_t              tsn;
    
        ZB_BUF_INITIAL_ALLOC(buf, sizeof(zb_zdo_ieee_addr_req_t), req);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 2: Send an EUI64 request: Device: 0x%04x, Endpoint: %d", m_device_ctx.sensor_params.short_address, m_device_ctx.sensor_params.endpoint);
        
        // Create new IEEE address request and fill with default values.
        req->start_index  = 0;
        req->request_type = 0;
        req->nwk_addr     = m_device_ctx.sensor_params.short_address;
    
        tsn = zb_zdo_ieee_addr_req(bufid, ieee_addr_cb);
        
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_WARNING("Failed to send IEEE address request for address: 0x%04x, error code: %d", m_device_ctx.sensor_params.short_address, tsn);
            //zb_free_buf(p_buf);
        }
    }
    
     //----------------------------------------------------------------------------------------
     // _                    _          _               _                 
     /// |    _ __    __ _  | |_   __  | |_          __| |  ___   ___  __ 
     //| |   | '  \  / _` | |  _| / _| | ' \        / _` | / -_) (_-< / _|
     //|_|   |_|_|_| \__,_|  \__| \__| |_||_|  ___  \__,_| \___| /__/ \__|
     //                                       |___|             
               
    /**@brief A callback function for send match desc
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    static void cmd_zb_match_desc_cb(zb_uint8_t param)
    {
        zb_buf_t                   * p_buf        = ZB_BUF_FROM_REF(param);                               // Resolve buffer number to buffer address
        zb_zdo_match_desc_resp_t   * p_resp       = (zb_zdo_match_desc_resp_t *)ZB_BUF_BEGIN(p_buf);      // Get the begining of the response
        zb_apsde_data_indication_t * p_ind        = ZB_GET_BUF_PARAM(p_buf, zb_apsde_data_indication_t);  // Get the pointer to the parameters buffer, which stores APS layer response
        zb_uint8_t                 * p_match_ep;   
        zb_ret_t                     zb_err_code;
    
        if ((p_resp->status == ZB_ZDP_STATUS_SUCCESS) && (p_resp->match_len > 0))
        {
            p_match_ep = (zb_uint8_t *)(p_resp + 1);
    
            /* We are searching for exact cluster, so only 1 EP may be found */
            m_device_ctx.sensor_params.endpoint      = *p_match_ep;
            m_device_ctx.sensor_params.short_address =  p_ind->src_addr;
    
            /* Match EP list follows right after response header */
            NRF_LOG_INFO("Sensor found on Address: src_addr= %hx ep= %d", p_ind->src_addr, *p_match_ep);
            
            // Netzwerk constant
            zb_err_code = ZB_SCHEDULE_ALARM(zb_ieee_addr_req, param, IEEE_ADDRESSS_REQ_DELAY);
            APP_ERROR_CHECK(zb_err_code);
        }
        else
        {
            NRF_LOG_INFO("Error in callback");
        }
    
        if (param)
        {
            ZB_FREE_BUF_BY_REF(param);
        }
    }
    
    /**@brief STEP 1: Send match request to sensor
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    void send_match_desc_req(zb_uint8_t param)
    {
        zb_buf_t                  *buf = ZB_BUF_FROM_REF(param);
        zb_zdo_match_desc_param_t *req;
        zb_ret_t                   zb_err_code;                  
        ZB_BUF_INITIAL_ALLOC(buf, sizeof(zb_zdo_match_desc_param_t) + (2 + 3) * sizeof(zb_uint16_t), req);
        
        req->nwk_addr = ZB_NWK_BROADCAST_ALL_DEVICES;                   //send to coordinator
        req->addr_of_interest = req->nwk_addr;
        req->profile_id = ZB_AF_HA_PROFILE_ID;                          //0x0104;   //ZB_AF_HA_PROFILE_ID
        req->num_in_clusters = 2;
        req->num_out_clusters = 0;
        req->cluster_list[0] = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;      //0x0402;  //ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT
        req->cluster_list[1] = ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;  //0x0403;  //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 1: Send match request to sensor");
        zb_err_code = zb_zdo_match_desc_req(param, cmd_zb_match_desc_cb);             //ZB_REF_FROM_BUF(buf), cmd_zb_match_desc_cb);
        if(zb_err_code != ZB_ZDP_STATUS_SUCCESS)
        {
            NRF_LOG_ERROR("Failed send match request: %d", zb_err_code);
        }
    }
    
    /**@brief Function for initializing LEDs and Buttons.
     */
    static void leds_buttons_init(void)
    {
    #ifdef  BOARD_PCA10056
        uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
        APP_ERROR_CHECK(err_code);
        /* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
    #else 
        bsp_board_init(BSP_INIT_LEDS);
    #endif
        bsp_board_leds_off();
    }
    
    /**@brief Callback used in order to visualise network steering period.
     *
     * @param[in]   param   Not used. Required by callback type definition.
     */
    static zb_void_t steering_finished(zb_uint8_t param)
    {
        UNUSED_PARAMETER(param);
        NRF_LOG_INFO("Network steering finished");
        bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #ifdef  BOARD_PCA10059
        LED(LED_JOINING, 0);
    #else
        bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
    }
    
    /**@brief Retry to form a Zigbee network. */
    static zb_void_t bdb_restart_top_level_commissioning(zb_uint8_t param)
    {
        UNUSED_RETURN_VALUE(bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING));
    }
    
     //----------------------------------------------------------------------------------------
     // ___   _                        _     _  _                    _   _             
     /// __| (_)  __ _   _ _    __ _  | |   | || |  __ _   _ _    __| | | |  ___   _ _ 
     //\__ \ | | / _` | | ' \  / _` | | |   | __ | / _` | | ' \  / _` | | | / -_) | '_|
     //|___/ |_| \__, | |_||_| \__,_| |_|   |_||_| \__,_| |_||_| \__,_| |_| \___| |_|  
     //          |___/                                                                 
    
    /**@brief ZigBee stack event handler.
     *
     * @param[in]   param   Reference to ZigBee stack buffer used to pass arguments (signal).
     */
    void zboss_signal_handler(zb_uint8_t param)
    {
        /* Read signal description out of memory buffer. */
        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);
        zb_buf_t                 *p_buf       = ZB_BUF_FROM_REF(param);
        zb_ret_t                  zb_err_code;
        zb_bool_t                 comm_status;
    
        switch(sig)
        {
            case ZB_ZDO_SIGNAL_SKIP_STARTUP:
                if (zb_bdb_is_factory_new())
                {
                    NRF_LOG_INFO("Start network steering & formation.");
                    comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING | ZB_BDB_NETWORK_FORMATION);
                    ZB_COMM_STATUS_CHECK(comm_status);
                }
                else
                {
                    comm_status = bdb_start_top_level_commissioning(ZB_BDB_INITIALIZATION);
                    ZB_COMM_STATUS_CHECK(comm_status);
                }
                break;
    
            case ZB_BDB_SIGNAL_DEVICE_FIRST_START: // Device started and commissioned first time after NVRAM erase.
                if (status == RET_OK)
                {
                    if (ZIGBEE_MANUAL_STEERING == ZB_FALSE)
                    {
                        NRF_LOG_INFO("Start network steering.");
                        comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                        ZB_COMM_STATUS_CHECK(comm_status);
                    }
                }
                else
                {
                    NRF_LOG_ERROR("Failed to form network.");
                }
                break;
    
            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)
                {
                    NRF_LOG_ERROR("Device startup failed. Status: %d. Retry network formation after 1 second.", status);
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 0);
    #else
                    bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(bdb_restart_top_level_commissioning, 0, ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            case ZB_BDB_SIGNAL_STEERING:
                if (status == RET_OK)
                {
                    /* Schedule an alarm to notify about the end of steering period */
                    NRF_LOG_INFO("Network steering started");
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 1);
    #else
                    bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(steering_finished, 0, ZB_TIME_ONE_SECOND * ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                else
                {
                    NRF_LOG_INFO("Network steering failed to start. Status: %d. Retry network formation after 1 second.", status);
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 0);
    #else
                    bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(bdb_restart_top_level_commissioning, 0, ZB_TIME_ONE_SECOND);
                    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(p_sg_p, zb_zdo_signal_device_annce_params_t);
                    NRF_LOG_INFO("Device with a short address 0x%04x commissionned", dev_annce_params->device_short_addr);
    
                     /* Check the device address */
                    if (m_device_ctx.sensor_params.short_address == 0xFFFF)
                    {
                          zb_err_code = ZB_SCHEDULE_ALARM(send_match_desc_req, param, MATCH_DESC_REQ_START_DELAY);
                          ZB_ERROR_CHECK(zb_err_code);
                    }
                }
                break;
    
            case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
                if (status != RET_OK)
                {
                    NRF_LOG_WARNING("Production config is not present or invalid");
                }
                break;
    
            case ZB_ZDO_SIGNAL_DEVICE_UPDATE:
                {
                    char ieee_addr_buf[17] = {0};
                    zb_zdo_signal_device_update_params_t * p_update_params;
                    p_update_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_device_update_params_t);
                    UNUSED_RETURN_VALUE(ieee_addr_to_str(ieee_addr_buf, sizeof(ieee_addr_buf), p_update_params->long_addr));//p_update_params->long_addr));
                    NRF_LOG_INFO("(Safety Check) Device has updated its status in the network, short address: 0x%04x, long address: %s, status: %d",
                                  p_update_params->short_addr, 
                                  NRF_LOG_PUSH(ieee_addr_buf), 
                                  p_update_params->status);
                }
                break;
    
            default:
                /* Unhandled signal. For more information see: zb_zdo_app_signal_type_e and zb_ret_e */
                NRF_LOG_INFO("Unhandled signal %d. Status: %d", sig, status);
                break;
        }
    
        /* All callbacks should either reuse or free passed buffers. If param == 0, the buffer is invalid (not passed) */
        if (param)
        {
            ZB_FREE_BUF_BY_REF(param);
        }
    }
    
     //----------------------------------------------------------------------------------------
     // __  __          _        
     //|  \/  |  __ _  (_)  _ _  
     //| |\/| | / _` | | | | ' \ 
     //|_|  |_| \__,_| |_| |_||_|
                               
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        zb_ret_t       zb_err_code;
        zb_ieee_addr_t ieee_addr;
    
        // Initialize.
        timers_init();
        log_init();
        #ifdef  BOARD_PCA10059
         // Harware_init(); 
          gpio_init();
        #else
          leds_buttons_init(); 
        #endif
    
        /* Set ZigBee stack logging level and traffic dump subsystem. */
        ZB_SET_TRACE_LEVEL(ZIGBEE_TRACE_LEVEL);
        ZB_SET_TRACE_MASK(ZIGBEE_TRACE_MASK);
        ZB_SET_TRAF_DUMP_OFF();
    
        /* Initialize ZigBee stack. */
        ZB_INIT("Sensor logger");
    
        /* Set device address to the value read from FICR registers. */
        zb_osif_get_ieee_eui64(ieee_addr);
        zb_set_long_address(ieee_addr);
    
        /* Set channels on which the coordinator will try to create a new network. */
        zb_set_network_coordinator_role(IEEE_CHANNEL_MASK);
        zb_set_max_children(MAX_CHILDREN);
    
        zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
        zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
    
        /* Initialize application context structure. */
        UNUSED_RETURN_VALUE(ZB_MEMSET(&m_device_ctx, 0, sizeof(sensor_logger_ctx_t)));
        /* Set default sensor short_addr. */
        m_device_ctx.sensor_params.short_address = 0xFFFF;
    
        /* Register dimmer switch device context (endpoints). */
        ZB_AF_REGISTER_DEVICE_CTX(&co_controll_ctx);
    
        /* Register callback for handling ZCL commands. */
        ZB_AF_SET_ENDPOINT_HANDLER(SENSOR_LOGGER_ENDPOINT, ep_handler_report);
    
        /* Keep or erase NVRAM to save the network parameters after device reboot or power-off. */
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
    
        /** Start Zigbee Stack. */
        if (ZIGBEE_MANUAL_STEERING == ZB_TRUE)
        {
            zb_err_code = zboss_start_no_autostart();
        }
        else
        {
            zb_err_code = zboss_start();
        }
    
        ZB_ERROR_CHECK(zb_err_code);
        NRF_LOG_INFO("Starting While Loop");
        while(1)
        {
            zboss_main_loop_iteration();
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        }
    }
    
    
    /**
     * @}
     */
    
    multi_sensor_data_logger.zip

  • Hi Jonas,

    Thanks for the detailed and clear explanation and code! Makes it much easier for us to debug projects and understand what is actually going on Slight smile

    I have started looking at your issue, and it seems to be buffer leak. The device gets a hard fault in zb_get_buf.

    When I commented out p_buf = ZB_GET_OUT_BUF(); in bind_device(), as well as the if statement for the buffer (lines 793-798), the device continued to run after the binding, and ran for about a minute before stopping. After also commenting out = ZB_BUF_FROM_REF(param); on line 677 in subscribe_device() so that the line was only zb_buf_t * p_buf; it ran for longer, about 4 minutes. All three times it crashed because of hard fault in zb_get_buf, and I suspect that is because it is not able to allocate a new buffer because they are all used. I have not had the chance to go through the entire project and find all possible problems yet, but I see that you are allocating a lot of buffers and scheduling alarms, so I would suggest starting by looking at this, so the places you use ZB_GET_OUT_BUF, ZB_BUF_FROM_REF, ZB_SCHEDULE_ALARM, etc. 

    When the device was running it worked as expected, successfully creating a binding, receiving attribute reports and calling the endpoint handler, so that part works as it should until the hard fault.

    I will keep looking into the problem tomorrow.

    Jonas T said:
    Do I also make a little bit of a mix-up with the buffers? If so, do you have any tips or internet sites?

    ZB_GET_OUT_BUF is used to allocate a new out buffer, while ZB_BUF_FROM_REF is a helper function to get a buffer by using its reference, and is used instead of buffer pointers. You can read more about this in Zigbee stack memory management subsystem.

    Best regards,

    Marte

Related