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

ZCL Tunneling - RequestTunnel not received

I am trying to establish a tunnel from ZigBee client to ZigBee server on nRF52840 using "nRF5 SDK for Thread and Zigbee v4.1.0".

Starting with the examples "examples\zigbee\light_control\light_bulb" (server) and "light_switch" (client) a HA_DIMMABLE_LIGHT_ENDPOINT connection gets established.

Establishing a tunnel fails, the server does not even receive the RequestTunnel message (on ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL)  though from my point of view, the server is set up correctly. Is there any example code available showing how to utilize ZigBee ZCL Smart Energy Tunneling?

This is how the server is set up:

#define TUNNELING_ENDPOINT_ID 11
#define TUNNELING_PROFILE_ID 0x10a
#define TUNNELING_DEVICE_ID 0x500
ZB_ZCL_DECLARE_TUNNELING_ATTRIB_LIST(tunneling_attr_list, &m_dev_ctx.tunneling_attr.close_tunnel_timeout);
zb_zcl_cluster_desc_t tunneling_clusters[]={
    ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_TUNNELING,
        ZB_ZCL_ARRAY_SIZE(tunneling_attr_list, zb_zcl_attr_t),
        tunneling_attr_list,
        ZB_ZCL_CLUSTER_SERVER_ROLE,
        MANUF_CODE)
};
zb_af_simple_desc_1_1_t simple_desc_tunnel={
    TUNNELING_ENDPOINT_ID,
    TUNNELING_PROFILE_ID,
    TUNNELING_DEVICE_ID,
    1, 0,
    1, 0,
    { ZB_ZCL_CLUSTER_ID_TUNNELING }
};
ZB_AF_DECLARE_ENDPOINT_DESC(tunneling_ep, TUNNELING_ENDPOINT_ID,
    TUNNELING_PROFILE_ID, 0, NULL,
    ZB_ZCL_ARRAY_SIZE(tunneling_clusters, zb_zcl_cluster_desc_t), tunneling_clusters,
    &simple_desc_tunnel,
    0, NULL, 0, NULL);
ZBOSS_DECLARE_DEVICE_CTX_2_EP(dimmable_light_ctx, dimmable_light_ep, tunneling_ep);
...
ZB_AF_REGISTER_DEVICE_CTX(&dimmable_light_ctx);
ZB_ZCL_CLUSTER_ID_TUNNELING_SERVER_ROLE_INIT();
ZB_AF_SET_ENDPOINT_HANDLER(TUNNELING_ENDPOINT_ID,
  zb_tunnel_endpoint_handler); // <---- zb_tunnel_endpoint_handler never gets invoked upon client RequestTunnel

How the client is set up:

#define TUNNELING_ENDPOINT_ID 11
#define TUNNELING_PROFILE_ID 0x10a
#define TUNNELING_DEVICE_ID 0x500
#define TUNNELING_PROTOCOL_ID 200
zb_zcl_cluster_desc_t tunneling_clusters[]={
    ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_TUNNELING,
        0, NULL,
        ZB_ZCL_CLUSTER_CLIENT_ROLE,
        TUNNELING_MANUF_CODE)
};
zb_af_simple_desc_1_1_t simple_desc_tunnel={
    TUNNELING_ENDPOINT_ID,
    TUNNELING_PROFILE_ID,
    TUNNELING_DEVICE_ID,
    1, 0,
    0, 1,
    { ZB_ZCL_CLUSTER_ID_TUNNELING }
};
ZB_AF_DECLARE_ENDPOINT_DESC(tunneling_ep, TUNNELING_ENDPOINT_ID,
    TUNNELING_PROFILE_ID, 0, NULL,
    ZB_ZCL_ARRAY_SIZE(tunneling_clusters, zb_zcl_cluster_desc_t), tunneling_clusters,
    &simple_desc_tunnel,
    0, NULL, 0, NULL);
ZBOSS_DECLARE_DEVICE_CTX_2_EP(dimmer_switch_ctx, dimmer_switch_ep, tunneling_ep);

static void tunnel_request(zb_bufid_t bufid)
{
    ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL(bufid,
        m_device_ctx.bulb_params.short_addr,
        ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
        TUNNELING_ENDPOINT_ID,
        LIGHT_SWITCH_ENDPOINT, // <--- With TUNNELING_ENDPOINT_ID, tunnel_request_cb does not get invoked!
        TUNNELING_PROFILE_ID,
        ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
        tunnel_request_cb, // <---- tunnel_request_cb gets invoked!
        TUNNELING_PROTOCOL_ID,
        MANUF_CODE,
        ZB_FALSE,
        100);
}
...
ZB_AF_REGISTER_DEVICE_CTX(&dimmer_switch_ctx);
ZB_ZCL_CLUSTER_ID_TUNNELING_CLIENT_ROLE_INIT();
ZB_AF_SET_ENDPOINT_HANDLER(TUNNELING_ENDPOINT_ID, zb_tunnel_endpoint_handler);

Parents
  • /**
     * Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     *
     * @defgroup zigbee_examples_light_bulb main.c
     * @{
     * @ingroup zigbee_examples
     * @brief Dimmable light sample (HA profile)
     */
    
    #include "sdk_config.h"
    #include "zboss_api.h"
    #include "zboss_api_addons.h"
    #include "zb_mem_config_med.h"
    #include "zb_error_handler.h"
    #include "zb_nrf52_internal.h"
    #include "zigbee_helpers.h"
    
    #include "bsp.h"
    #include "boards.h"
    #include "app_pwm.h"
    #include "app_timer.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #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 ERASE_PERSISTENT_CONFIG           ZB_TRUE                              /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. */
    
    /* Basic cluster attributes initial values. */
    #define BULB_INIT_BASIC_APP_VERSION       01                                    /**< Version of the application software (1 byte). */
    #define BULB_INIT_BASIC_STACK_VERSION     10                                    /**< Version of the implementation of the Zigbee stack (1 byte). */
    #define BULB_INIT_BASIC_HW_VERSION        11                                    /**< Version of the hardware of the device (1 byte). */
    #define BULB_INIT_BASIC_MANUF_NAME        "Nordic"                              /**< Manufacturer name (32 bytes). */
    #define BULB_INIT_BASIC_MODEL_ID          "Tunnel server"                  /**< Model number assigned by manufacturer (32-bytes long string). */
    #define BULB_INIT_BASIC_DATE_CODE         "20180416"                            /**< First 8 bytes specify the date of manufacturer of the device in ISO 8601 format (YYYYMMDD). The rest (8 bytes) are manufacturer specific. */
    #define BULB_INIT_BASIC_POWER_SOURCE      ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE   /**< Type of power sources available for the device. For possible values see section 3.2.2.2.8 of ZCL specification. */
    #define BULB_INIT_BASIC_LOCATION_DESC     "Office desk"                         /**< Describes the physical location of the device (16 bytes). May be modified during commisioning process. */
    #define BULB_INIT_BASIC_PH_ENV            ZB_ZCL_BASIC_ENV_UNSPECIFIED          /**< Describes the type of physical environment. For possible values see section 3.2.2.2.10 of ZCL specification. */
    
    #define IDENTIFY_MODE_BSP_EVT             BSP_EVENT_KEY_0                       /**< Button event used to enter the Bulb into the Identify mode. */
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_0                       /**< LED indicating that light switch successfully joind Zigbee network. */
    #define BULB_LED                          LED_RGB_RED                       /**< LED immitaing dimmable light bulb. */
    
    #if !defined ZB_ROUTER_ROLE
    #error Define ZB_ROUTER_ROLE to compile light bulb (Router) source code.
    #endif
    
    /* Main application customizable context. Stores all settings and static values. */
    typedef struct
    {
        zb_zcl_basic_attrs_ext_t         basic_attr;
        zb_zcl_tunneling_attrs_t         tunneling_attr;
    } bulb_device_ctx_t;
    
    static bulb_device_ctx_t m_dev_ctx;
    
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(basic_attr_list,
                                         &m_dev_ctx.basic_attr.zcl_version,
                                         &m_dev_ctx.basic_attr.app_version,
                                         &m_dev_ctx.basic_attr.stack_version,
                                         &m_dev_ctx.basic_attr.hw_version,
                                         m_dev_ctx.basic_attr.mf_name,
                                         m_dev_ctx.basic_attr.model_id,
                                         m_dev_ctx.basic_attr.date_code,
                                         &m_dev_ctx.basic_attr.power_source,
                                         m_dev_ctx.basic_attr.location_id,
                                         &m_dev_ctx.basic_attr.ph_env,
                                         m_dev_ctx.basic_attr.sw_ver);
    
    #define TUNNELING_ENDPOINT_ID 11
    #define TUNNELING_PROFILE_ID ZB_AF_HA_PROFILE_ID
    #define TUNNELING_DEVICE_ID 0x508 // Remote Communications Device
    #define TUNNELING_PROTOCOL_ID 200
    #define TUNNELING_MANUF_CODE 3910
    ZB_ZCL_DECLARE_TUNNELING_ATTRIB_LIST(tunneling_attr_list, &m_dev_ctx.tunneling_attr.close_tunnel_timeout);
    zb_zcl_cluster_desc_t tunneling_clusters[]={
            ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_BASIC,
                    ZB_ZCL_ARRAY_SIZE(basic_attr_list, zb_zcl_attr_t),
                    basic_attr_list,
                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                    ZB_ZCL_MANUF_CODE_INVALID),
            ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_TUNNELING,
                    ZB_ZCL_ARRAY_SIZE(tunneling_attr_list, zb_zcl_attr_t),
                    tunneling_attr_list,
                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                    TUNNELING_MANUF_CODE)
    };
    zb_af_simple_desc_1_1_t simple_desc_tunnel={
            TUNNELING_ENDPOINT_ID,
            TUNNELING_PROFILE_ID,
            TUNNELING_DEVICE_ID,
            1, 0,
            2, 0,
            { ZB_ZCL_CLUSTER_ID_BASIC, ZB_ZCL_CLUSTER_ID_TUNNELING }
    };
    ZB_AF_DECLARE_ENDPOINT_DESC(tunneling_ep, TUNNELING_ENDPOINT_ID,
            TUNNELING_PROFILE_ID, 0, NULL,
            ZB_ZCL_ARRAY_SIZE(tunneling_clusters, zb_zcl_cluster_desc_t), tunneling_clusters,
            &simple_desc_tunnel,
            0, NULL, 0, NULL);
    ZBOSS_DECLARE_DEVICE_CTX_1_EP(dimmable_light_ctx, tunneling_ep);
    
    /**@brief Function for initializing the application timer.
     */
    static void timer_init(void)
    {
        uint32_t error_code = app_timer_init();
        APP_ERROR_CHECK(error_code);
    }
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    /**@brief Callback for button events.
     *
     * @param[in]   evt      Incoming event from the BSP subsystem.
     */
    static void buttons_handler(bsp_event_t evt)
    {
        switch(evt)
        {
            case IDENTIFY_MODE_BSP_EVT:
                break;
    
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
                break;
        }
    }
    
    
    /**@brief Function for initializing LEDs and a single PWM channel.
     */
    static void leds_buttons_init(void)
    {
        ret_code_t       err_code;
    
        /* Initialize all LEDs and buttons. */
        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. */
        nrf_gpio_cfg_input(BSP_SW1, NRF_GPIO_PIN_PULLUP);
    }
    
    /**@brief Function for initializing all clusters attributes.
     */
    static void bulb_clusters_attr_init(void)
    {
        /* Basic cluster attributes data */
        m_dev_ctx.basic_attr.zcl_version   = ZB_ZCL_VERSION;
        m_dev_ctx.basic_attr.app_version   = BULB_INIT_BASIC_APP_VERSION;
        m_dev_ctx.basic_attr.stack_version = BULB_INIT_BASIC_STACK_VERSION;
        m_dev_ctx.basic_attr.hw_version    = BULB_INIT_BASIC_HW_VERSION;
    
        /* Use ZB_ZCL_SET_STRING_VAL to set strings, because the first byte should
         * contain string length without trailing zero.
         *
         * For example "test" string wil be encoded as:
         *   [(0x4), 't', 'e', 's', 't']
         */
        ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.mf_name,
                              BULB_INIT_BASIC_MANUF_NAME,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MANUF_NAME));
    
        ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.model_id,
                              BULB_INIT_BASIC_MODEL_ID,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MODEL_ID));
    
        ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.date_code,
                              BULB_INIT_BASIC_DATE_CODE,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_DATE_CODE));
    
        m_dev_ctx.basic_attr.power_source = BULB_INIT_BASIC_POWER_SOURCE;
    
        ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.location_id,
                              BULB_INIT_BASIC_LOCATION_DESC,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_LOCATION_DESC));
    
    
        m_dev_ctx.basic_attr.ph_env = BULB_INIT_BASIC_PH_ENV;
    
        m_dev_ctx.tunneling_attr.close_tunnel_timeout=60;//ZB_ZCL_TUNNELING_CLOSE_TUNNEL_TIMEOUT_DEFAULT_VALUE;
    }
    
    /**@brief Function which tries to sleep down the MCU 
     *
     * Function which sleeps the MCU on the non-sleepy End Devices to optimize the power saving.
     * The weak definition inside the OSIF layer provides some minimal working template
     */
    zb_void_t zb_osif_go_idle(zb_void_t)
    {
        //TODO: implement your own logic if needed
        zb_osif_wait_for_event();
    }
    
    /**@brief Callback function for handling ZCL commands.
     *
     * @param[in]   bufid   Reference to Zigbee stack buffer used to pass received data.
     */
    static zb_void_t zcl_device_cb(zb_bufid_t bufid)
    {
        zb_zcl_device_callback_param_t * p_device_cb_param = ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
    
        NRF_LOG_INFO("zcl_device_cb id %hd", p_device_cb_param->device_cb_id);
    
        /* Set default response value. */
        p_device_cb_param->status = RET_OK;
    
        switch (p_device_cb_param->device_cb_id)
        {
            default:
                p_device_cb_param->status = RET_ERROR;
                break;
        }
    
        NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
    }
    
    /**@brief Zigbee stack event handler.
     *
     * @param[in]   bufid   Reference to the Zigbee stack buffer used to pass signal.
     */
    void zboss_signal_handler(zb_bufid_t bufid)
    {
        /* Update network status LED */
        zigbee_led_status_update(bufid, ZIGBEE_NETWORK_STATE_LED);
    
        zb_zdo_app_signal_hdr_t      * p_sg_p = NULL;
        zb_zdo_app_signal_type_t       sig    = zb_get_app_signal(bufid, &p_sg_p);
    
        NRF_LOG_INFO("zboss_signal_handler: %i", sig);
    
        switch(sig)
        {
            default:
    		/* No application-specific behavior is required. Call default signal handler. */
    		ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
        }
    
        if (bufid)
        {
            zb_buf_free(bufid);
        }
    }
    
    static zb_zcl_parsed_hdr_t tunnel_header;
    static zb_uint16_t max_incoming_transfer_size;
    static const zb_uint16_t tunnel_id=72;
    
    static void request_tunnel_response(zb_bufid_t bufid)
    {
    	NRF_LOG_INFO("Tunneling request response");
        ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL_RESPONSE(bufid, tunnel_header.addr_data.common_data.source.u,
        		tunnel_header.addr_data.common_data.source.addr_type == ZB_ZCL_ADDR_TYPE_SHORT ? ZB_APS_ADDR_MODE_16_ENDP_PRESENT : ZB_APS_ADDR_MODE_64_ENDP_PRESENT,
    					TUNNELING_ENDPOINT_ID, TUNNELING_ENDPOINT_ID, ZB_AF_HA_PROFILE_ID,
    					ZB_ZCL_DISABLE_DEFAULT_RESPONSE, ZB_ZCL_GET_SEQ_NUM(),
    					NULL, tunnel_id,
    					ZB_ZCL_TUNNELING_STATUS_SUCCESS, max_incoming_transfer_size );
    }
    
    static void tunnel_send_transfer_data_cb(zb_bufid_t bufid)
    {
        NRF_LOG_INFO("tunnel_send_transfer_data_cb: %d", bufid);
        zb_buf_free(bufid);
    }
    
    static void tunnel_send_transfer_data(zb_bufid_t bufid)
    {
        zb_uint8_t *data=(zb_uint8_t*)"server data";
        NRF_LOG_INFO("Transfer data: %d/%d", tunnel_id, strlen((char*)data));
        zb_ret_t zb_err_code=ZB_ZCL_TUNNELING_SERVER_SEND_TRANSFER_DATA(bufid, TUNNELING_ENDPOINT_ID, TUNNELING_PROFILE_ID,
                ZB_ZCL_DISABLE_DEFAULT_RESPONSE, tunnel_send_transfer_data_cb,
                tunnel_id, strlen((char*)data), data);
        ZB_ERROR_CHECK(zb_err_code);
    }
    
    static zb_uint8_t zb_tunnel_endpoint_handler(zb_bufid_t bufid)
    {
    	zb_zcl_parsed_hdr_t * header = ZB_BUF_GET_PARAM(bufid, zb_zcl_parsed_hdr_t);
        NRF_LOG_INFO("zb_tunnel_endpoint_handler: %i", header->cmd_id);
    
    	switch(header->cmd_id)
    	{
    		case ZB_ZCL_TUNNELING_CLI_CMD_REQUEST_TUNNEL:
    		{
    			zb_zcl_tunneling_request_tunnel_t tun;
    			zb_zcl_parse_status_t status;
    
    			ZB_ZCL_TUNNELING_GET_REQUEST_TUNNEL(&tun, bufid, status);
    			NRF_LOG_INFO("Tunneling request: %d/%d/%d", tun.protocol_id, tun.manufacturer_code, status);
    			if (status==ZB_ZCL_PARSE_STATUS_SUCCESS &&
    				tun.protocol_id==TUNNELING_PROTOCOL_ID &&
    				tun.manufacturer_code==TUNNELING_MANUF_CODE)
    			{
    				zb_bufid_t buf_resp = zb_buf_get_out();
    				tunnel_header=*header;
    				max_incoming_transfer_size=tun.max_incoming_transfer_size;
    				zb_ret_t zb_err_code=ZB_SCHEDULE_APP_ALARM(request_tunnel_response, buf_resp, ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
    
                    zb_bufid_t buf_resp2 = zb_buf_get_out();
                    zb_err_code=ZB_SCHEDULE_APP_ALARM(tunnel_send_transfer_data, buf_resp2, 5*ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
    			}
                zb_buf_free(bufid);
    		    return ZB_TRUE;
    		}
    		case ZB_ZCL_TUNNELING_CLI_CMD_TRANSFER_DATA:
    		{
    			zb_zcl_tunneling_transfer_data_payload_t data;
    			zb_zcl_parse_status_t status;
    
    			ZB_ZCL_TUNNELING_GET_TRANSFER_DATA(&data, bufid, status);
    			NRF_LOG_INFO("Transfer data: %d/%d", data.data_size, status);
    			if (status==ZB_ZCL_PARSE_STATUS_SUCCESS)
    			{
    				NRF_LOG_INFO("%s", data.tun_data);
    			}
                zb_buf_free(bufid);
    		    return ZB_TRUE;
    		}
    		case ZB_ZCL_TUNNELING_CLI_CMD_CLOSE_TUNNEL:
            {
                zb_zcl_tunneling_close_tunnel_t tun;
                zb_zcl_parse_status_t status;
    
                ZB_ZCL_TUNNELING_GET_CLOSE_TUNNEL(&tun, bufid, status);
                NRF_LOG_INFO("Tunnel close: %d/%d", tun.tunnel_id, status);
                zb_buf_free(bufid);
                return ZB_TRUE;
            }
            case ZB_ZCL_TUNNELING_SRV_CMD_TUNNEL_CLOSURE_NOTIFICATION:
            {
                NRF_LOG_INFO("Tunnel closed/timeout");
                break;
            }
    	}
    
        return ZB_FALSE;
    }
    
    static void init_setunnel()
    {
        ZB_ZCL_CLUSTER_ID_TUNNELING_SERVER_ROLE_INIT();
        ZB_AF_SET_ENDPOINT_HANDLER(TUNNELING_ENDPOINT_ID, zb_tunnel_endpoint_handler);
    
        NRF_LOG_INFO("zb_tunnel_endpoint_handler reg=%i", ZB_AF_IS_EP_REGISTERED(TUNNELING_ENDPOINT_ID));
    }
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        zb_ret_t       zb_err_code;
        zb_ieee_addr_t ieee_addr;
    
        /* Initialize timer, logging system and GPIOs. */
        timer_init();
        log_init();
        leds_buttons_init();
    
        /* 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("led_bulb");
    
        /* Set device address to the value read from FICR registers. */
        zb_osif_get_ieee_eui64(ieee_addr);
        zb_set_long_address(ieee_addr);
    
        /* Set static long IEEE address. */
        zb_set_network_coordinator_role(IEEE_CHANNEL_MASK);
        //zb_set_network_router_role(IEEE_CHANNEL_MASK);
        zb_set_max_children(MAX_CHILDREN);
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
        zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
    
        /* Initialize application context structure. */
        UNUSED_RETURN_VALUE(ZB_MEMSET(&m_dev_ctx, 0, sizeof(m_dev_ctx)));
    
        /* Register callback for handling ZCL commands. */
        ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);
    
        /* Register dimmer switch device context (endpoints). */
        ZB_AF_REGISTER_DEVICE_CTX(&dimmable_light_ctx);
    
        bulb_clusters_attr_init();
    
        init_setunnel();
    
        /** Start Zigbee Stack. */
        zb_err_code = zboss_start_no_autostart();
        ZB_ERROR_CHECK(zb_err_code);
    
        while(1)
        {
            zboss_main_loop_iteration();
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        }
    }
    
    
    /**
     * @}
     */
    
    /**
     * Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     *
     * @defgroup zigbee_examples_light_switch main.c
     * @{
     * @ingroup zigbee_examples
     * @brief Dimmer switch for HA profile implementation.
     */
    
    #include "zboss_api.h"
    #include "zb_mem_config_custom.h"
    #include "zb_error_handler.h"
    #include "zigbee_helpers.h"
    
    #include "app_timer.h"
    #include "bsp.h"
    #include "boards.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #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 MATCH_DESC_REQ_TIMEOUT              (5 * ZB_TIME_ONE_SECOND)            /**< Timeout for finding procedure. */
    #define MATCH_DESC_REQ_ROLE                 ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE    /**< Find only non-sleepy device. */
    #define ERASE_PERSISTENT_CONFIG             ZB_TRUE                            /**< 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 ZIGBEE_NETWORK_STATE_LED            BSP_BOARD_LED_2                     /**< LED indicating that light switch successfully joind Zigbee network. */
    #define BULB_FOUND_LED                      BSP_BOARD_LED_1                     /**< LED indicating that light witch found a light bulb to control. */
    
    #if !defined ZB_ED_ROLE
    #error Define ZB_ED_ROLE to compile light switch (End Device) source code.
    #endif
    
    
    typedef struct light_switch_bulb_params_s
    {
      zb_uint8_t  endpoint;
      zb_uint16_t short_addr;
    } light_switch_bulb_params_t;
    
    typedef struct light_switch_ctx_s
    {
      light_switch_bulb_params_t bulb_params;
    } light_switch_ctx_t;
    
    
    static zb_void_t find_light_bulb_timeout(zb_bufid_t bufid);
    
    static light_switch_ctx_t m_device_ctx;
    static zb_uint8_t         m_attr_zcl_version   = ZB_ZCL_VERSION;
    static zb_uint8_t         m_attr_power_source  = ZB_ZCL_BASIC_POWER_SOURCE_UNKNOWN;
    static zb_uint16_t        m_attr_identify_time = 0;
    
    /* Declare attribute list for Basic cluster. */
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
    
    /* Declare attribute list for Identify cluster. */
    ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
    
    /* Declare application's device context (list of registered endpoints) for Dimmer Switch device. */
    #define TUNNELING_ENDPOINT_ID 11
    #define TUNNELING_PROFILE_ID ZB_AF_HA_PROFILE_ID
    #define TUNNELING_DEVICE_ID 0x508 // Remote Communications Device
    #define TUNNELING_PROTOCOL_ID 200
    #define TUNNELING_MANUF_CODE 3910
    zb_zcl_cluster_desc_t tunneling_clusters[]={
            ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_TUNNELING,
                    0, NULL,
                    ZB_ZCL_CLUSTER_CLIENT_ROLE,
                    TUNNELING_MANUF_CODE)
    };
    zb_af_simple_desc_1_1_t simple_desc_tunnel={
            TUNNELING_ENDPOINT_ID,
            TUNNELING_PROFILE_ID,
            TUNNELING_DEVICE_ID,
            1, 0,
            0, 1,
            { ZB_ZCL_CLUSTER_ID_TUNNELING }
    };
    ZB_AF_DECLARE_ENDPOINT_DESC(tunneling_ep, TUNNELING_ENDPOINT_ID,
            TUNNELING_PROFILE_ID, 0, NULL,
            ZB_ZCL_ARRAY_SIZE(tunneling_clusters, zb_zcl_cluster_desc_t), tunneling_clusters,
            &simple_desc_tunnel,
            0, NULL, 0, NULL);
    ZBOSS_DECLARE_DEVICE_CTX_1_EP(dimmer_switch_ctx, tunneling_ep);
    
    /**@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 Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    static void tunnel_request_cb(zb_bufid_t bufid)
    {
        NRF_LOG_INFO("tunnel_request_cb: %d", bufid);
        zb_buf_free(bufid);
    }
    
    static void tunnel_request(zb_bufid_t bufid)
    {
        ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL(bufid,
                m_device_ctx.bulb_params.short_addr,
                ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                TUNNELING_ENDPOINT_ID,
    			TUNNELING_ENDPOINT_ID,
                TUNNELING_PROFILE_ID,
                ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
                tunnel_request_cb,
                TUNNELING_PROTOCOL_ID,
                TUNNELING_MANUF_CODE,
                ZB_FALSE,
                100);
        NRF_LOG_INFO("tunnel_request: %d", bufid);
    }
    
    static zb_uint16_t tunnel_id;
    
    static void tunnel_close_cb(zb_bufid_t bufid)
    {
        NRF_LOG_INFO("tunnel_close_cb: %d", bufid);
        zb_buf_free(bufid);
    }
    
    static void tunnel_close(zb_bufid_t bufid)
    {
        ZB_ZCL_TUNNELING_SEND_CLOSE_TUNNEL(bufid,
                m_device_ctx.bulb_params.short_addr,
                ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                TUNNELING_ENDPOINT_ID,
                TUNNELING_ENDPOINT_ID,
                TUNNELING_PROFILE_ID,
                ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
                tunnel_close_cb,
                tunnel_id);
        NRF_LOG_INFO("tunnel_close: %d", bufid);
    }
    
    /**@brief Callback function receiving finding procedure results.
     *
     * @param[in]   bufid   Reference to Zigbee stack buffer used to pass received data.
     */
    static zb_void_t find_light_bulb_cb(zb_bufid_t bufid)
    {
        zb_zdo_match_desc_resp_t   * p_resp = (zb_zdo_match_desc_resp_t *) zb_buf_begin(bufid);    // Get the beginning of the response
        zb_apsde_data_indication_t * p_ind  = ZB_BUF_GET_PARAM(bufid, 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) && (m_device_ctx.bulb_params.short_addr == 0xFFFF))
        {
            /* Match EP list follows right after response header */
            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.bulb_params.endpoint   = *p_match_ep;
            m_device_ctx.bulb_params.short_addr = p_ind->src_addr;
    
            NRF_LOG_INFO("Found bulb addr: %d ep: %d", m_device_ctx.bulb_params.short_addr, m_device_ctx.bulb_params.endpoint);
    
            zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(find_light_bulb_timeout, ZB_ALARM_ANY_PARAM);
            ZB_ERROR_CHECK(zb_err_code);
    
            bsp_board_led_on(BULB_FOUND_LED);
        }
    
        if (bufid)
        {
            zb_buf_free(bufid);
        }
    }
    
    /**@brief Function for sending ON/OFF and Level Control find request.
     *
     * @param[in]   bufid   Non-zero reference to Zigbee stack buffer that will be used to construct find request.
     */
    static zb_void_t find_light_bulb(zb_bufid_t bufid)
    {
        zb_zdo_match_desc_param_t * p_req;
    
        /* Initialize pointers inside buffer and reserve space for zb_zdo_match_desc_param_t request */
        p_req = zb_buf_initial_alloc(bufid, sizeof(zb_zdo_match_desc_param_t) + (1) * sizeof(zb_uint16_t));
    
        p_req->nwk_addr         = MATCH_DESC_REQ_ROLE;              // Send to devices specified by MATCH_DESC_REQ_ROLE
        p_req->addr_of_interest = MATCH_DESC_REQ_ROLE;              // Get responses from devices specified by MATCH_DESC_REQ_ROLE
    
        // Nur Tunnelprofil:
        p_req->profile_id       = TUNNELING_PROFILE_ID;
        p_req->num_in_clusters  = 1;
        p_req->cluster_list[0]  = ZB_ZCL_CLUSTER_ID_TUNNELING;
    
        /*lint -restore */
        m_device_ctx.bulb_params.short_addr = 0xFFFF; // Set 0xFFFF to reset short address in order to parse only one response.
        UNUSED_RETURN_VALUE(zb_zdo_match_desc_req(bufid, find_light_bulb_cb));
    }
    
    /**@brief Finding procedure timeout handler.
     *
     * @param[in]   bufid   Reference to Zigbee stack buffer that will be used to construct find request.
     */
    static zb_void_t find_light_bulb_timeout(zb_bufid_t bufid)
    {
        zb_ret_t zb_err_code;
    
        if (bufid)
        {
            NRF_LOG_INFO("Bulb not found, try again");
            zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb, bufid, MATCH_DESC_REQ_START_DELAY);
            ZB_ERROR_CHECK(zb_err_code);
            zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
            ZB_ERROR_CHECK(zb_err_code);
        }
        else
        {
            zb_err_code = zb_buf_get_out_delayed(find_light_bulb_timeout);
            ZB_ERROR_CHECK(zb_err_code);
        }
    }
    
    /**@brief Callback for button events.
     *
     * @param[in]   evt      Incoming event from the BSP subsystem.
     */
    static void buttons_handler(bsp_event_t evt)
    {
        zb_ret_t zb_err_code;
    
        /* Inform default signal handler about user input at the device. */
        user_input_indicate();
    
        if (m_device_ctx.bulb_params.short_addr == 0xFFFF)
        {
            /* No bulb found yet. */
            return;
        }
    
        switch(evt)
        {
            case BSP_EVENT_KEY_0:
                {
                	NRF_LOG_INFO("ON/tunnel request");
    				zb_bufid_t bufid=zb_buf_get_out_func();
    			    zb_err_code=ZB_SCHEDULE_APP_ALARM(tunnel_request, bufid, 3*ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            case BSP_EVENT_KEY_1:
                {
                	NRF_LOG_INFO("OFF/tunnel close");
                    zb_bufid_t bufid=zb_buf_get_out_func();
                    zb_err_code=ZB_SCHEDULE_APP_ALARM(tunnel_close, bufid, 1*ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
                return;
        }
    }
    
    /**@brief Function for initializing LEDs and buttons.
     */
    static zb_void_t leds_buttons_init(void)
    {
        ret_code_t error_code;
    
        /* Initialize LEDs and buttons - use BSP to control them. */
        error_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
        APP_ERROR_CHECK(error_code);
        /* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
    
        bsp_board_leds_off();
    }
    
    /**@brief Zigbee stack event handler.
     *
     * @param[in]   bufid   Reference to the Zigbee stack buffer used to pass signal.
     */
    void zboss_signal_handler(zb_bufid_t bufid)
    {
        zb_zdo_app_signal_hdr_t      * p_sg_p = NULL;
        zb_zdo_app_signal_type_t       sig    = zb_get_app_signal(bufid, &p_sg_p);
        zb_ret_t                       status = ZB_GET_APP_SIGNAL_STATUS(bufid);
        zb_ret_t                       zb_err_code;
    
        /* Update network status LED */
        zigbee_led_status_update(bufid, ZIGBEE_NETWORK_STATE_LED);
        NRF_LOG_INFO("zboss_signal_handler: %i", sig);
    
        switch(sig)
        {
            case ZB_BDB_SIGNAL_DEVICE_REBOOT:
                /* fall-through */
            case ZB_BDB_SIGNAL_STEERING:
                /* Call default signal handler. */
                ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
                if (status == RET_OK)
                {
                    /* Check the light device address */
                    if (m_device_ctx.bulb_params.short_addr == 0xFFFF)
                    {
                        zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb, bufid, MATCH_DESC_REQ_START_DELAY);
                        ZB_ERROR_CHECK(zb_err_code);
                        zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
                        ZB_ERROR_CHECK(zb_err_code);
                        bufid = 0; // Do not free buffer - it will be reused by find_light_bulb callback
                    }
                }
                break;
    
            default:
                /* Call default signal handler. */
                ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
                break;
        }
    
        if (bufid)
        {
            zb_buf_free(bufid);
        }
    }
    
    static void tunnel_send_transfer_data_cb(zb_bufid_t bufid)
    {
        NRF_LOG_INFO("tunnel_send_transfer_data_cb: %d", bufid);
        zb_buf_free(bufid);
    }
    
    static void tunnel_send_transfer_data(zb_bufid_t bufid)
    {
    	zb_uint8_t *data=(zb_uint8_t*)"client data";
    	NRF_LOG_INFO("Transfer data: %d/%d", tunnel_id, strlen((char*)data));
    	zb_ret_t zb_err_code=ZB_ZCL_TUNNELING_CLIENT_SEND_TRANSFER_DATA(bufid, TUNNELING_ENDPOINT_ID, TUNNELING_PROFILE_ID,
    			ZB_ZCL_DISABLE_DEFAULT_RESPONSE, tunnel_send_transfer_data_cb,
    			tunnel_id, strlen((char*)data), data);
        ZB_ERROR_CHECK(zb_err_code);
    }
    
    static zb_uint8_t zb_tunnel_endpoint_handler(zb_bufid_t bufid)
    {
    	zb_zcl_parsed_hdr_t * header = ZB_BUF_GET_PARAM(bufid, zb_zcl_parsed_hdr_t);
        NRF_LOG_INFO("zb_tunnel_endpoint_handler: %i", header->cmd_id);
    
    	switch(header->cmd_id)
    	{
    		case ZB_ZCL_TUNNELING_SRV_CMD_REQUEST_TUNNEL_RESPONSE:
    		{
    			zb_zcl_tunneling_request_tunnel_response_t tun;
    			zb_zcl_parse_status_t status;
    
    			ZB_ZCL_TUNNELING_GET_REQUEST_TUNNEL_RESPONSE(&tun, bufid, status);
    			NRF_LOG_INFO("Tunneling request response: %d/%d/%d", tun.tunnel_id, tun.tunnel_status, status);
    			if (status==ZB_ZCL_PARSE_STATUS_SUCCESS &&
    				tun.tunnel_status==ZB_ZCL_TUNNELING_STATUS_SUCCESS)
    			{
    				tunnel_id=tun.tunnel_id;
    				zb_bufid_t buf=zb_buf_get_out_func();
    				zb_ret_t zb_err_code=ZB_SCHEDULE_APP_ALARM(tunnel_send_transfer_data, buf, 2*ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
    			}
    			zb_buf_free(bufid);
    			return ZB_TRUE;
    		}
            case ZB_ZCL_TUNNELING_SRV_CMD_TUNNEL_CLOSURE_NOTIFICATION:
            {
                NRF_LOG_INFO("Tunnel closed/timeout");
                break;
            }
            case ZB_ZCL_TUNNELING_SRV_CMD_TRANSFER_DATA:
            {
                zb_zcl_tunneling_transfer_data_payload_t data;
                zb_zcl_parse_status_t status;
    
                ZB_ZCL_TUNNELING_GET_TRANSFER_DATA(&data, bufid, status);
                NRF_LOG_INFO("Transfer data: %d/%d", data.data_size, status);
                if (status==ZB_ZCL_PARSE_STATUS_SUCCESS)
                {
                    NRF_LOG_INFO("%s", data.tun_data);
                }
                zb_buf_free(bufid);
                return ZB_TRUE;
            }
    	}
    
        return ZB_FALSE;
    }
    
    static void init_setunnel()
    {
        ZB_ZCL_CLUSTER_ID_TUNNELING_CLIENT_ROLE_INIT();
        ZB_AF_SET_ENDPOINT_HANDLER(TUNNELING_ENDPOINT_ID, zb_tunnel_endpoint_handler);
    }
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        zb_ret_t       zb_err_code;
        zb_ieee_addr_t ieee_addr;
    
        /* Initialize timers, loging system and GPIOs. */
        timers_init();
        log_init();
        leds_buttons_init();
    
        /* 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("Tunnel client");
    
        /* Set device address to the value read from FICR registers. */
        zb_osif_get_ieee_eui64(ieee_addr);
        zb_set_long_address(ieee_addr);
    
        zb_set_network_ed_role(IEEE_CHANNEL_MASK);
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
    
        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(light_switch_ctx_t)));
    
        /* Set default bulb short_addr. */
        m_device_ctx.bulb_params.short_addr = 0xFFFF;
    
        /* Register dimmer switch device context (endpoints). */
        ZB_AF_REGISTER_DEVICE_CTX(&dimmer_switch_ctx);
    
        init_setunnel();
    
        /** Start Zigbee Stack. */
        zb_err_code = zboss_start_no_autostart();
        ZB_ERROR_CHECK(zb_err_code);
    
        while(1)
        {
            zboss_main_loop_iteration();
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        }
    }
    
    
    /**
     * @}
     */
    

    I stripped down the example project to use the tunnel endpoint only.


    Execution:
    - On client press button BSP_BUTTON_0:
      - Tunnel request (buttons_handler/tunnel_request)
      - 2s after tunnel request response (zb_tunnel_endpoint_handler), transfer data (tunnel_send_transfer_data)
    - On server:
      - 5s after tunnel request (zb_tunnel_endpoint_handler), transfer data (tunnel_send_transfer_data)
    - On client press button BSP_BUTTON_1:
      - Tunnel close (buttons_handler/tunnel_close)

    Actual problems are:
    - Profile ID seems to have to be ZB_AF_HA_PROFILE_ID, with other values ZB server won't even get its tunnel endpoint handler called (zb_tunnel_endpoint_handler)
    - ZB_ZCL_TUNNELING_CLIENT_SEND_TRANSFER_DATA and ZB_ZCL_TUNNELING_SERVER_SEND_TRANSFER_DATA both return RET_ERROR, though their connection seems established
    - Tunnel timeout never seems to be raised (ZB_ZCL_TUNNELING_SRV_CMD_TUNNEL_CLOSURE_NOTIFICATION), though tunnel timeout is configured (close_tunnel_timeout=60s)

Reply
  • /**
     * Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     *
     * @defgroup zigbee_examples_light_bulb main.c
     * @{
     * @ingroup zigbee_examples
     * @brief Dimmable light sample (HA profile)
     */
    
    #include "sdk_config.h"
    #include "zboss_api.h"
    #include "zboss_api_addons.h"
    #include "zb_mem_config_med.h"
    #include "zb_error_handler.h"
    #include "zb_nrf52_internal.h"
    #include "zigbee_helpers.h"
    
    #include "bsp.h"
    #include "boards.h"
    #include "app_pwm.h"
    #include "app_timer.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #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 ERASE_PERSISTENT_CONFIG           ZB_TRUE                              /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. */
    
    /* Basic cluster attributes initial values. */
    #define BULB_INIT_BASIC_APP_VERSION       01                                    /**< Version of the application software (1 byte). */
    #define BULB_INIT_BASIC_STACK_VERSION     10                                    /**< Version of the implementation of the Zigbee stack (1 byte). */
    #define BULB_INIT_BASIC_HW_VERSION        11                                    /**< Version of the hardware of the device (1 byte). */
    #define BULB_INIT_BASIC_MANUF_NAME        "Nordic"                              /**< Manufacturer name (32 bytes). */
    #define BULB_INIT_BASIC_MODEL_ID          "Tunnel server"                  /**< Model number assigned by manufacturer (32-bytes long string). */
    #define BULB_INIT_BASIC_DATE_CODE         "20180416"                            /**< First 8 bytes specify the date of manufacturer of the device in ISO 8601 format (YYYYMMDD). The rest (8 bytes) are manufacturer specific. */
    #define BULB_INIT_BASIC_POWER_SOURCE      ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE   /**< Type of power sources available for the device. For possible values see section 3.2.2.2.8 of ZCL specification. */
    #define BULB_INIT_BASIC_LOCATION_DESC     "Office desk"                         /**< Describes the physical location of the device (16 bytes). May be modified during commisioning process. */
    #define BULB_INIT_BASIC_PH_ENV            ZB_ZCL_BASIC_ENV_UNSPECIFIED          /**< Describes the type of physical environment. For possible values see section 3.2.2.2.10 of ZCL specification. */
    
    #define IDENTIFY_MODE_BSP_EVT             BSP_EVENT_KEY_0                       /**< Button event used to enter the Bulb into the Identify mode. */
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_0                       /**< LED indicating that light switch successfully joind Zigbee network. */
    #define BULB_LED                          LED_RGB_RED                       /**< LED immitaing dimmable light bulb. */
    
    #if !defined ZB_ROUTER_ROLE
    #error Define ZB_ROUTER_ROLE to compile light bulb (Router) source code.
    #endif
    
    /* Main application customizable context. Stores all settings and static values. */
    typedef struct
    {
        zb_zcl_basic_attrs_ext_t         basic_attr;
        zb_zcl_tunneling_attrs_t         tunneling_attr;
    } bulb_device_ctx_t;
    
    static bulb_device_ctx_t m_dev_ctx;
    
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(basic_attr_list,
                                         &m_dev_ctx.basic_attr.zcl_version,
                                         &m_dev_ctx.basic_attr.app_version,
                                         &m_dev_ctx.basic_attr.stack_version,
                                         &m_dev_ctx.basic_attr.hw_version,
                                         m_dev_ctx.basic_attr.mf_name,
                                         m_dev_ctx.basic_attr.model_id,
                                         m_dev_ctx.basic_attr.date_code,
                                         &m_dev_ctx.basic_attr.power_source,
                                         m_dev_ctx.basic_attr.location_id,
                                         &m_dev_ctx.basic_attr.ph_env,
                                         m_dev_ctx.basic_attr.sw_ver);
    
    #define TUNNELING_ENDPOINT_ID 11
    #define TUNNELING_PROFILE_ID ZB_AF_HA_PROFILE_ID
    #define TUNNELING_DEVICE_ID 0x508 // Remote Communications Device
    #define TUNNELING_PROTOCOL_ID 200
    #define TUNNELING_MANUF_CODE 3910
    ZB_ZCL_DECLARE_TUNNELING_ATTRIB_LIST(tunneling_attr_list, &m_dev_ctx.tunneling_attr.close_tunnel_timeout);
    zb_zcl_cluster_desc_t tunneling_clusters[]={
            ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_BASIC,
                    ZB_ZCL_ARRAY_SIZE(basic_attr_list, zb_zcl_attr_t),
                    basic_attr_list,
                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                    ZB_ZCL_MANUF_CODE_INVALID),
            ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_TUNNELING,
                    ZB_ZCL_ARRAY_SIZE(tunneling_attr_list, zb_zcl_attr_t),
                    tunneling_attr_list,
                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                    TUNNELING_MANUF_CODE)
    };
    zb_af_simple_desc_1_1_t simple_desc_tunnel={
            TUNNELING_ENDPOINT_ID,
            TUNNELING_PROFILE_ID,
            TUNNELING_DEVICE_ID,
            1, 0,
            2, 0,
            { ZB_ZCL_CLUSTER_ID_BASIC, ZB_ZCL_CLUSTER_ID_TUNNELING }
    };
    ZB_AF_DECLARE_ENDPOINT_DESC(tunneling_ep, TUNNELING_ENDPOINT_ID,
            TUNNELING_PROFILE_ID, 0, NULL,
            ZB_ZCL_ARRAY_SIZE(tunneling_clusters, zb_zcl_cluster_desc_t), tunneling_clusters,
            &simple_desc_tunnel,
            0, NULL, 0, NULL);
    ZBOSS_DECLARE_DEVICE_CTX_1_EP(dimmable_light_ctx, tunneling_ep);
    
    /**@brief Function for initializing the application timer.
     */
    static void timer_init(void)
    {
        uint32_t error_code = app_timer_init();
        APP_ERROR_CHECK(error_code);
    }
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    /**@brief Callback for button events.
     *
     * @param[in]   evt      Incoming event from the BSP subsystem.
     */
    static void buttons_handler(bsp_event_t evt)
    {
        switch(evt)
        {
            case IDENTIFY_MODE_BSP_EVT:
                break;
    
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
                break;
        }
    }
    
    
    /**@brief Function for initializing LEDs and a single PWM channel.
     */
    static void leds_buttons_init(void)
    {
        ret_code_t       err_code;
    
        /* Initialize all LEDs and buttons. */
        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. */
        nrf_gpio_cfg_input(BSP_SW1, NRF_GPIO_PIN_PULLUP);
    }
    
    /**@brief Function for initializing all clusters attributes.
     */
    static void bulb_clusters_attr_init(void)
    {
        /* Basic cluster attributes data */
        m_dev_ctx.basic_attr.zcl_version   = ZB_ZCL_VERSION;
        m_dev_ctx.basic_attr.app_version   = BULB_INIT_BASIC_APP_VERSION;
        m_dev_ctx.basic_attr.stack_version = BULB_INIT_BASIC_STACK_VERSION;
        m_dev_ctx.basic_attr.hw_version    = BULB_INIT_BASIC_HW_VERSION;
    
        /* Use ZB_ZCL_SET_STRING_VAL to set strings, because the first byte should
         * contain string length without trailing zero.
         *
         * For example "test" string wil be encoded as:
         *   [(0x4), 't', 'e', 's', 't']
         */
        ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.mf_name,
                              BULB_INIT_BASIC_MANUF_NAME,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MANUF_NAME));
    
        ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.model_id,
                              BULB_INIT_BASIC_MODEL_ID,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MODEL_ID));
    
        ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.date_code,
                              BULB_INIT_BASIC_DATE_CODE,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_DATE_CODE));
    
        m_dev_ctx.basic_attr.power_source = BULB_INIT_BASIC_POWER_SOURCE;
    
        ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.location_id,
                              BULB_INIT_BASIC_LOCATION_DESC,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_LOCATION_DESC));
    
    
        m_dev_ctx.basic_attr.ph_env = BULB_INIT_BASIC_PH_ENV;
    
        m_dev_ctx.tunneling_attr.close_tunnel_timeout=60;//ZB_ZCL_TUNNELING_CLOSE_TUNNEL_TIMEOUT_DEFAULT_VALUE;
    }
    
    /**@brief Function which tries to sleep down the MCU 
     *
     * Function which sleeps the MCU on the non-sleepy End Devices to optimize the power saving.
     * The weak definition inside the OSIF layer provides some minimal working template
     */
    zb_void_t zb_osif_go_idle(zb_void_t)
    {
        //TODO: implement your own logic if needed
        zb_osif_wait_for_event();
    }
    
    /**@brief Callback function for handling ZCL commands.
     *
     * @param[in]   bufid   Reference to Zigbee stack buffer used to pass received data.
     */
    static zb_void_t zcl_device_cb(zb_bufid_t bufid)
    {
        zb_zcl_device_callback_param_t * p_device_cb_param = ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
    
        NRF_LOG_INFO("zcl_device_cb id %hd", p_device_cb_param->device_cb_id);
    
        /* Set default response value. */
        p_device_cb_param->status = RET_OK;
    
        switch (p_device_cb_param->device_cb_id)
        {
            default:
                p_device_cb_param->status = RET_ERROR;
                break;
        }
    
        NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
    }
    
    /**@brief Zigbee stack event handler.
     *
     * @param[in]   bufid   Reference to the Zigbee stack buffer used to pass signal.
     */
    void zboss_signal_handler(zb_bufid_t bufid)
    {
        /* Update network status LED */
        zigbee_led_status_update(bufid, ZIGBEE_NETWORK_STATE_LED);
    
        zb_zdo_app_signal_hdr_t      * p_sg_p = NULL;
        zb_zdo_app_signal_type_t       sig    = zb_get_app_signal(bufid, &p_sg_p);
    
        NRF_LOG_INFO("zboss_signal_handler: %i", sig);
    
        switch(sig)
        {
            default:
    		/* No application-specific behavior is required. Call default signal handler. */
    		ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
        }
    
        if (bufid)
        {
            zb_buf_free(bufid);
        }
    }
    
    static zb_zcl_parsed_hdr_t tunnel_header;
    static zb_uint16_t max_incoming_transfer_size;
    static const zb_uint16_t tunnel_id=72;
    
    static void request_tunnel_response(zb_bufid_t bufid)
    {
    	NRF_LOG_INFO("Tunneling request response");
        ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL_RESPONSE(bufid, tunnel_header.addr_data.common_data.source.u,
        		tunnel_header.addr_data.common_data.source.addr_type == ZB_ZCL_ADDR_TYPE_SHORT ? ZB_APS_ADDR_MODE_16_ENDP_PRESENT : ZB_APS_ADDR_MODE_64_ENDP_PRESENT,
    					TUNNELING_ENDPOINT_ID, TUNNELING_ENDPOINT_ID, ZB_AF_HA_PROFILE_ID,
    					ZB_ZCL_DISABLE_DEFAULT_RESPONSE, ZB_ZCL_GET_SEQ_NUM(),
    					NULL, tunnel_id,
    					ZB_ZCL_TUNNELING_STATUS_SUCCESS, max_incoming_transfer_size );
    }
    
    static void tunnel_send_transfer_data_cb(zb_bufid_t bufid)
    {
        NRF_LOG_INFO("tunnel_send_transfer_data_cb: %d", bufid);
        zb_buf_free(bufid);
    }
    
    static void tunnel_send_transfer_data(zb_bufid_t bufid)
    {
        zb_uint8_t *data=(zb_uint8_t*)"server data";
        NRF_LOG_INFO("Transfer data: %d/%d", tunnel_id, strlen((char*)data));
        zb_ret_t zb_err_code=ZB_ZCL_TUNNELING_SERVER_SEND_TRANSFER_DATA(bufid, TUNNELING_ENDPOINT_ID, TUNNELING_PROFILE_ID,
                ZB_ZCL_DISABLE_DEFAULT_RESPONSE, tunnel_send_transfer_data_cb,
                tunnel_id, strlen((char*)data), data);
        ZB_ERROR_CHECK(zb_err_code);
    }
    
    static zb_uint8_t zb_tunnel_endpoint_handler(zb_bufid_t bufid)
    {
    	zb_zcl_parsed_hdr_t * header = ZB_BUF_GET_PARAM(bufid, zb_zcl_parsed_hdr_t);
        NRF_LOG_INFO("zb_tunnel_endpoint_handler: %i", header->cmd_id);
    
    	switch(header->cmd_id)
    	{
    		case ZB_ZCL_TUNNELING_CLI_CMD_REQUEST_TUNNEL:
    		{
    			zb_zcl_tunneling_request_tunnel_t tun;
    			zb_zcl_parse_status_t status;
    
    			ZB_ZCL_TUNNELING_GET_REQUEST_TUNNEL(&tun, bufid, status);
    			NRF_LOG_INFO("Tunneling request: %d/%d/%d", tun.protocol_id, tun.manufacturer_code, status);
    			if (status==ZB_ZCL_PARSE_STATUS_SUCCESS &&
    				tun.protocol_id==TUNNELING_PROTOCOL_ID &&
    				tun.manufacturer_code==TUNNELING_MANUF_CODE)
    			{
    				zb_bufid_t buf_resp = zb_buf_get_out();
    				tunnel_header=*header;
    				max_incoming_transfer_size=tun.max_incoming_transfer_size;
    				zb_ret_t zb_err_code=ZB_SCHEDULE_APP_ALARM(request_tunnel_response, buf_resp, ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
    
                    zb_bufid_t buf_resp2 = zb_buf_get_out();
                    zb_err_code=ZB_SCHEDULE_APP_ALARM(tunnel_send_transfer_data, buf_resp2, 5*ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
    			}
                zb_buf_free(bufid);
    		    return ZB_TRUE;
    		}
    		case ZB_ZCL_TUNNELING_CLI_CMD_TRANSFER_DATA:
    		{
    			zb_zcl_tunneling_transfer_data_payload_t data;
    			zb_zcl_parse_status_t status;
    
    			ZB_ZCL_TUNNELING_GET_TRANSFER_DATA(&data, bufid, status);
    			NRF_LOG_INFO("Transfer data: %d/%d", data.data_size, status);
    			if (status==ZB_ZCL_PARSE_STATUS_SUCCESS)
    			{
    				NRF_LOG_INFO("%s", data.tun_data);
    			}
                zb_buf_free(bufid);
    		    return ZB_TRUE;
    		}
    		case ZB_ZCL_TUNNELING_CLI_CMD_CLOSE_TUNNEL:
            {
                zb_zcl_tunneling_close_tunnel_t tun;
                zb_zcl_parse_status_t status;
    
                ZB_ZCL_TUNNELING_GET_CLOSE_TUNNEL(&tun, bufid, status);
                NRF_LOG_INFO("Tunnel close: %d/%d", tun.tunnel_id, status);
                zb_buf_free(bufid);
                return ZB_TRUE;
            }
            case ZB_ZCL_TUNNELING_SRV_CMD_TUNNEL_CLOSURE_NOTIFICATION:
            {
                NRF_LOG_INFO("Tunnel closed/timeout");
                break;
            }
    	}
    
        return ZB_FALSE;
    }
    
    static void init_setunnel()
    {
        ZB_ZCL_CLUSTER_ID_TUNNELING_SERVER_ROLE_INIT();
        ZB_AF_SET_ENDPOINT_HANDLER(TUNNELING_ENDPOINT_ID, zb_tunnel_endpoint_handler);
    
        NRF_LOG_INFO("zb_tunnel_endpoint_handler reg=%i", ZB_AF_IS_EP_REGISTERED(TUNNELING_ENDPOINT_ID));
    }
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        zb_ret_t       zb_err_code;
        zb_ieee_addr_t ieee_addr;
    
        /* Initialize timer, logging system and GPIOs. */
        timer_init();
        log_init();
        leds_buttons_init();
    
        /* 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("led_bulb");
    
        /* Set device address to the value read from FICR registers. */
        zb_osif_get_ieee_eui64(ieee_addr);
        zb_set_long_address(ieee_addr);
    
        /* Set static long IEEE address. */
        zb_set_network_coordinator_role(IEEE_CHANNEL_MASK);
        //zb_set_network_router_role(IEEE_CHANNEL_MASK);
        zb_set_max_children(MAX_CHILDREN);
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
        zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
    
        /* Initialize application context structure. */
        UNUSED_RETURN_VALUE(ZB_MEMSET(&m_dev_ctx, 0, sizeof(m_dev_ctx)));
    
        /* Register callback for handling ZCL commands. */
        ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);
    
        /* Register dimmer switch device context (endpoints). */
        ZB_AF_REGISTER_DEVICE_CTX(&dimmable_light_ctx);
    
        bulb_clusters_attr_init();
    
        init_setunnel();
    
        /** Start Zigbee Stack. */
        zb_err_code = zboss_start_no_autostart();
        ZB_ERROR_CHECK(zb_err_code);
    
        while(1)
        {
            zboss_main_loop_iteration();
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        }
    }
    
    
    /**
     * @}
     */
    
    /**
     * Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     *
     * @defgroup zigbee_examples_light_switch main.c
     * @{
     * @ingroup zigbee_examples
     * @brief Dimmer switch for HA profile implementation.
     */
    
    #include "zboss_api.h"
    #include "zb_mem_config_custom.h"
    #include "zb_error_handler.h"
    #include "zigbee_helpers.h"
    
    #include "app_timer.h"
    #include "bsp.h"
    #include "boards.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #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 MATCH_DESC_REQ_TIMEOUT              (5 * ZB_TIME_ONE_SECOND)            /**< Timeout for finding procedure. */
    #define MATCH_DESC_REQ_ROLE                 ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE    /**< Find only non-sleepy device. */
    #define ERASE_PERSISTENT_CONFIG             ZB_TRUE                            /**< 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 ZIGBEE_NETWORK_STATE_LED            BSP_BOARD_LED_2                     /**< LED indicating that light switch successfully joind Zigbee network. */
    #define BULB_FOUND_LED                      BSP_BOARD_LED_1                     /**< LED indicating that light witch found a light bulb to control. */
    
    #if !defined ZB_ED_ROLE
    #error Define ZB_ED_ROLE to compile light switch (End Device) source code.
    #endif
    
    
    typedef struct light_switch_bulb_params_s
    {
      zb_uint8_t  endpoint;
      zb_uint16_t short_addr;
    } light_switch_bulb_params_t;
    
    typedef struct light_switch_ctx_s
    {
      light_switch_bulb_params_t bulb_params;
    } light_switch_ctx_t;
    
    
    static zb_void_t find_light_bulb_timeout(zb_bufid_t bufid);
    
    static light_switch_ctx_t m_device_ctx;
    static zb_uint8_t         m_attr_zcl_version   = ZB_ZCL_VERSION;
    static zb_uint8_t         m_attr_power_source  = ZB_ZCL_BASIC_POWER_SOURCE_UNKNOWN;
    static zb_uint16_t        m_attr_identify_time = 0;
    
    /* Declare attribute list for Basic cluster. */
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
    
    /* Declare attribute list for Identify cluster. */
    ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
    
    /* Declare application's device context (list of registered endpoints) for Dimmer Switch device. */
    #define TUNNELING_ENDPOINT_ID 11
    #define TUNNELING_PROFILE_ID ZB_AF_HA_PROFILE_ID
    #define TUNNELING_DEVICE_ID 0x508 // Remote Communications Device
    #define TUNNELING_PROTOCOL_ID 200
    #define TUNNELING_MANUF_CODE 3910
    zb_zcl_cluster_desc_t tunneling_clusters[]={
            ZB_ZCL_CLUSTER_DESC(ZB_ZCL_CLUSTER_ID_TUNNELING,
                    0, NULL,
                    ZB_ZCL_CLUSTER_CLIENT_ROLE,
                    TUNNELING_MANUF_CODE)
    };
    zb_af_simple_desc_1_1_t simple_desc_tunnel={
            TUNNELING_ENDPOINT_ID,
            TUNNELING_PROFILE_ID,
            TUNNELING_DEVICE_ID,
            1, 0,
            0, 1,
            { ZB_ZCL_CLUSTER_ID_TUNNELING }
    };
    ZB_AF_DECLARE_ENDPOINT_DESC(tunneling_ep, TUNNELING_ENDPOINT_ID,
            TUNNELING_PROFILE_ID, 0, NULL,
            ZB_ZCL_ARRAY_SIZE(tunneling_clusters, zb_zcl_cluster_desc_t), tunneling_clusters,
            &simple_desc_tunnel,
            0, NULL, 0, NULL);
    ZBOSS_DECLARE_DEVICE_CTX_1_EP(dimmer_switch_ctx, tunneling_ep);
    
    /**@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 Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    static void tunnel_request_cb(zb_bufid_t bufid)
    {
        NRF_LOG_INFO("tunnel_request_cb: %d", bufid);
        zb_buf_free(bufid);
    }
    
    static void tunnel_request(zb_bufid_t bufid)
    {
        ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL(bufid,
                m_device_ctx.bulb_params.short_addr,
                ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                TUNNELING_ENDPOINT_ID,
    			TUNNELING_ENDPOINT_ID,
                TUNNELING_PROFILE_ID,
                ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
                tunnel_request_cb,
                TUNNELING_PROTOCOL_ID,
                TUNNELING_MANUF_CODE,
                ZB_FALSE,
                100);
        NRF_LOG_INFO("tunnel_request: %d", bufid);
    }
    
    static zb_uint16_t tunnel_id;
    
    static void tunnel_close_cb(zb_bufid_t bufid)
    {
        NRF_LOG_INFO("tunnel_close_cb: %d", bufid);
        zb_buf_free(bufid);
    }
    
    static void tunnel_close(zb_bufid_t bufid)
    {
        ZB_ZCL_TUNNELING_SEND_CLOSE_TUNNEL(bufid,
                m_device_ctx.bulb_params.short_addr,
                ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                TUNNELING_ENDPOINT_ID,
                TUNNELING_ENDPOINT_ID,
                TUNNELING_PROFILE_ID,
                ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
                tunnel_close_cb,
                tunnel_id);
        NRF_LOG_INFO("tunnel_close: %d", bufid);
    }
    
    /**@brief Callback function receiving finding procedure results.
     *
     * @param[in]   bufid   Reference to Zigbee stack buffer used to pass received data.
     */
    static zb_void_t find_light_bulb_cb(zb_bufid_t bufid)
    {
        zb_zdo_match_desc_resp_t   * p_resp = (zb_zdo_match_desc_resp_t *) zb_buf_begin(bufid);    // Get the beginning of the response
        zb_apsde_data_indication_t * p_ind  = ZB_BUF_GET_PARAM(bufid, 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) && (m_device_ctx.bulb_params.short_addr == 0xFFFF))
        {
            /* Match EP list follows right after response header */
            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.bulb_params.endpoint   = *p_match_ep;
            m_device_ctx.bulb_params.short_addr = p_ind->src_addr;
    
            NRF_LOG_INFO("Found bulb addr: %d ep: %d", m_device_ctx.bulb_params.short_addr, m_device_ctx.bulb_params.endpoint);
    
            zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(find_light_bulb_timeout, ZB_ALARM_ANY_PARAM);
            ZB_ERROR_CHECK(zb_err_code);
    
            bsp_board_led_on(BULB_FOUND_LED);
        }
    
        if (bufid)
        {
            zb_buf_free(bufid);
        }
    }
    
    /**@brief Function for sending ON/OFF and Level Control find request.
     *
     * @param[in]   bufid   Non-zero reference to Zigbee stack buffer that will be used to construct find request.
     */
    static zb_void_t find_light_bulb(zb_bufid_t bufid)
    {
        zb_zdo_match_desc_param_t * p_req;
    
        /* Initialize pointers inside buffer and reserve space for zb_zdo_match_desc_param_t request */
        p_req = zb_buf_initial_alloc(bufid, sizeof(zb_zdo_match_desc_param_t) + (1) * sizeof(zb_uint16_t));
    
        p_req->nwk_addr         = MATCH_DESC_REQ_ROLE;              // Send to devices specified by MATCH_DESC_REQ_ROLE
        p_req->addr_of_interest = MATCH_DESC_REQ_ROLE;              // Get responses from devices specified by MATCH_DESC_REQ_ROLE
    
        // Nur Tunnelprofil:
        p_req->profile_id       = TUNNELING_PROFILE_ID;
        p_req->num_in_clusters  = 1;
        p_req->cluster_list[0]  = ZB_ZCL_CLUSTER_ID_TUNNELING;
    
        /*lint -restore */
        m_device_ctx.bulb_params.short_addr = 0xFFFF; // Set 0xFFFF to reset short address in order to parse only one response.
        UNUSED_RETURN_VALUE(zb_zdo_match_desc_req(bufid, find_light_bulb_cb));
    }
    
    /**@brief Finding procedure timeout handler.
     *
     * @param[in]   bufid   Reference to Zigbee stack buffer that will be used to construct find request.
     */
    static zb_void_t find_light_bulb_timeout(zb_bufid_t bufid)
    {
        zb_ret_t zb_err_code;
    
        if (bufid)
        {
            NRF_LOG_INFO("Bulb not found, try again");
            zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb, bufid, MATCH_DESC_REQ_START_DELAY);
            ZB_ERROR_CHECK(zb_err_code);
            zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
            ZB_ERROR_CHECK(zb_err_code);
        }
        else
        {
            zb_err_code = zb_buf_get_out_delayed(find_light_bulb_timeout);
            ZB_ERROR_CHECK(zb_err_code);
        }
    }
    
    /**@brief Callback for button events.
     *
     * @param[in]   evt      Incoming event from the BSP subsystem.
     */
    static void buttons_handler(bsp_event_t evt)
    {
        zb_ret_t zb_err_code;
    
        /* Inform default signal handler about user input at the device. */
        user_input_indicate();
    
        if (m_device_ctx.bulb_params.short_addr == 0xFFFF)
        {
            /* No bulb found yet. */
            return;
        }
    
        switch(evt)
        {
            case BSP_EVENT_KEY_0:
                {
                	NRF_LOG_INFO("ON/tunnel request");
    				zb_bufid_t bufid=zb_buf_get_out_func();
    			    zb_err_code=ZB_SCHEDULE_APP_ALARM(tunnel_request, bufid, 3*ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            case BSP_EVENT_KEY_1:
                {
                	NRF_LOG_INFO("OFF/tunnel close");
                    zb_bufid_t bufid=zb_buf_get_out_func();
                    zb_err_code=ZB_SCHEDULE_APP_ALARM(tunnel_close, bufid, 1*ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
                return;
        }
    }
    
    /**@brief Function for initializing LEDs and buttons.
     */
    static zb_void_t leds_buttons_init(void)
    {
        ret_code_t error_code;
    
        /* Initialize LEDs and buttons - use BSP to control them. */
        error_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
        APP_ERROR_CHECK(error_code);
        /* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
    
        bsp_board_leds_off();
    }
    
    /**@brief Zigbee stack event handler.
     *
     * @param[in]   bufid   Reference to the Zigbee stack buffer used to pass signal.
     */
    void zboss_signal_handler(zb_bufid_t bufid)
    {
        zb_zdo_app_signal_hdr_t      * p_sg_p = NULL;
        zb_zdo_app_signal_type_t       sig    = zb_get_app_signal(bufid, &p_sg_p);
        zb_ret_t                       status = ZB_GET_APP_SIGNAL_STATUS(bufid);
        zb_ret_t                       zb_err_code;
    
        /* Update network status LED */
        zigbee_led_status_update(bufid, ZIGBEE_NETWORK_STATE_LED);
        NRF_LOG_INFO("zboss_signal_handler: %i", sig);
    
        switch(sig)
        {
            case ZB_BDB_SIGNAL_DEVICE_REBOOT:
                /* fall-through */
            case ZB_BDB_SIGNAL_STEERING:
                /* Call default signal handler. */
                ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
                if (status == RET_OK)
                {
                    /* Check the light device address */
                    if (m_device_ctx.bulb_params.short_addr == 0xFFFF)
                    {
                        zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb, bufid, MATCH_DESC_REQ_START_DELAY);
                        ZB_ERROR_CHECK(zb_err_code);
                        zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
                        ZB_ERROR_CHECK(zb_err_code);
                        bufid = 0; // Do not free buffer - it will be reused by find_light_bulb callback
                    }
                }
                break;
    
            default:
                /* Call default signal handler. */
                ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
                break;
        }
    
        if (bufid)
        {
            zb_buf_free(bufid);
        }
    }
    
    static void tunnel_send_transfer_data_cb(zb_bufid_t bufid)
    {
        NRF_LOG_INFO("tunnel_send_transfer_data_cb: %d", bufid);
        zb_buf_free(bufid);
    }
    
    static void tunnel_send_transfer_data(zb_bufid_t bufid)
    {
    	zb_uint8_t *data=(zb_uint8_t*)"client data";
    	NRF_LOG_INFO("Transfer data: %d/%d", tunnel_id, strlen((char*)data));
    	zb_ret_t zb_err_code=ZB_ZCL_TUNNELING_CLIENT_SEND_TRANSFER_DATA(bufid, TUNNELING_ENDPOINT_ID, TUNNELING_PROFILE_ID,
    			ZB_ZCL_DISABLE_DEFAULT_RESPONSE, tunnel_send_transfer_data_cb,
    			tunnel_id, strlen((char*)data), data);
        ZB_ERROR_CHECK(zb_err_code);
    }
    
    static zb_uint8_t zb_tunnel_endpoint_handler(zb_bufid_t bufid)
    {
    	zb_zcl_parsed_hdr_t * header = ZB_BUF_GET_PARAM(bufid, zb_zcl_parsed_hdr_t);
        NRF_LOG_INFO("zb_tunnel_endpoint_handler: %i", header->cmd_id);
    
    	switch(header->cmd_id)
    	{
    		case ZB_ZCL_TUNNELING_SRV_CMD_REQUEST_TUNNEL_RESPONSE:
    		{
    			zb_zcl_tunneling_request_tunnel_response_t tun;
    			zb_zcl_parse_status_t status;
    
    			ZB_ZCL_TUNNELING_GET_REQUEST_TUNNEL_RESPONSE(&tun, bufid, status);
    			NRF_LOG_INFO("Tunneling request response: %d/%d/%d", tun.tunnel_id, tun.tunnel_status, status);
    			if (status==ZB_ZCL_PARSE_STATUS_SUCCESS &&
    				tun.tunnel_status==ZB_ZCL_TUNNELING_STATUS_SUCCESS)
    			{
    				tunnel_id=tun.tunnel_id;
    				zb_bufid_t buf=zb_buf_get_out_func();
    				zb_ret_t zb_err_code=ZB_SCHEDULE_APP_ALARM(tunnel_send_transfer_data, buf, 2*ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
    			}
    			zb_buf_free(bufid);
    			return ZB_TRUE;
    		}
            case ZB_ZCL_TUNNELING_SRV_CMD_TUNNEL_CLOSURE_NOTIFICATION:
            {
                NRF_LOG_INFO("Tunnel closed/timeout");
                break;
            }
            case ZB_ZCL_TUNNELING_SRV_CMD_TRANSFER_DATA:
            {
                zb_zcl_tunneling_transfer_data_payload_t data;
                zb_zcl_parse_status_t status;
    
                ZB_ZCL_TUNNELING_GET_TRANSFER_DATA(&data, bufid, status);
                NRF_LOG_INFO("Transfer data: %d/%d", data.data_size, status);
                if (status==ZB_ZCL_PARSE_STATUS_SUCCESS)
                {
                    NRF_LOG_INFO("%s", data.tun_data);
                }
                zb_buf_free(bufid);
                return ZB_TRUE;
            }
    	}
    
        return ZB_FALSE;
    }
    
    static void init_setunnel()
    {
        ZB_ZCL_CLUSTER_ID_TUNNELING_CLIENT_ROLE_INIT();
        ZB_AF_SET_ENDPOINT_HANDLER(TUNNELING_ENDPOINT_ID, zb_tunnel_endpoint_handler);
    }
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        zb_ret_t       zb_err_code;
        zb_ieee_addr_t ieee_addr;
    
        /* Initialize timers, loging system and GPIOs. */
        timers_init();
        log_init();
        leds_buttons_init();
    
        /* 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("Tunnel client");
    
        /* Set device address to the value read from FICR registers. */
        zb_osif_get_ieee_eui64(ieee_addr);
        zb_set_long_address(ieee_addr);
    
        zb_set_network_ed_role(IEEE_CHANNEL_MASK);
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
    
        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(light_switch_ctx_t)));
    
        /* Set default bulb short_addr. */
        m_device_ctx.bulb_params.short_addr = 0xFFFF;
    
        /* Register dimmer switch device context (endpoints). */
        ZB_AF_REGISTER_DEVICE_CTX(&dimmer_switch_ctx);
    
        init_setunnel();
    
        /** Start Zigbee Stack. */
        zb_err_code = zboss_start_no_autostart();
        ZB_ERROR_CHECK(zb_err_code);
    
        while(1)
        {
            zboss_main_loop_iteration();
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        }
    }
    
    
    /**
     * @}
     */
    

    I stripped down the example project to use the tunnel endpoint only.


    Execution:
    - On client press button BSP_BUTTON_0:
      - Tunnel request (buttons_handler/tunnel_request)
      - 2s after tunnel request response (zb_tunnel_endpoint_handler), transfer data (tunnel_send_transfer_data)
    - On server:
      - 5s after tunnel request (zb_tunnel_endpoint_handler), transfer data (tunnel_send_transfer_data)
    - On client press button BSP_BUTTON_1:
      - Tunnel close (buttons_handler/tunnel_close)

    Actual problems are:
    - Profile ID seems to have to be ZB_AF_HA_PROFILE_ID, with other values ZB server won't even get its tunnel endpoint handler called (zb_tunnel_endpoint_handler)
    - ZB_ZCL_TUNNELING_CLIENT_SEND_TRANSFER_DATA and ZB_ZCL_TUNNELING_SERVER_SEND_TRANSFER_DATA both return RET_ERROR, though their connection seems established
    - Tunnel timeout never seems to be raised (ZB_ZCL_TUNNELING_SRV_CMD_TUNNEL_CLOSURE_NOTIFICATION), though tunnel timeout is configured (close_tunnel_timeout=60s)

Children
No Data
Related