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

ZB ZCL Tunneling - no data send

Hi, this is my first post here, so please forgive if category/description is not complete.

I'm trying to do a quick proof of concept using ZB ZCL Tunneling. ZED is a client side that opens a tunnel and sends some data and ZC is a server side receiving that data and sends something back to the client. Just for testing I'm doing it with ZB_AF_HA_PROFILE_ID & ZB_ZCL_CLUSTER_ID_TUNNELING.

On ZED I'm trying to request tunnel in the following way:

static void tunneling_request_tunnel(zb_bufid_t bufid)
{
    zb_ret_t zb_err_code;
    zb_uint16_t short_addr = 0x0000;

    if (bufid)
    {
    	NRF_LOG_INFO("%s", __FUNCTION__);
    	ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL(bufid, 							\
    										 short_addr,						\
											 ZB_APS_ADDR_MODE_16_ENDP_PRESENT,	\
											 TUNNEL_CLI_ENDPOINT,				\
											 TUNNEL_CLI_ENDPOINT,				\
											 ZB_AF_HA_PROFILE_ID, 				\
											 ZB_ZCL_DISABLE_DEFAULT_RESPONSE,	\
											 NULL,								\
											 200, 								\
											 0xDEAD, 							\
											 ZB_FALSE,							\
											 16);
    }
    else
    {
        zb_err_code = zb_buf_get_out_delayed(tunneling_request_tunnel);
        ZB_ERROR_CHECK(zb_err_code);
    }
}

On ZC I have a tunnel endpoint handler:

zb_uint8_t tunnel_ep_handler(zb_bufid_t bufid)
{
	static zb_bool_t tunnel_opened = ZB_FALSE;
	zb_zcl_parsed_hdr_t * header = ZB_BUF_GET_PARAM(bufid, zb_zcl_parsed_hdr_t);

	if(ZB_ZCL_CLUSTER_ID_TUNNELING != header->cluster_id)
	{
		return ZB_FALSE;
	}

	if(ZB_AF_HA_PROFILE_ID != header->profile_id)
	{
		return ZB_FALSE;
	}

	switch(header->cmd_id)
	{
		case ZB_ZCL_TUNNELING_CLI_CMD_REQUEST_TUNNEL:
		{
			zb_zcl_tunneling_request_tunnel_t tunnel_req;
			zb_zcl_parse_status_t status;
			zb_bufid_t buf_resp = zb_buf_get_out();

			ZB_ZCL_TUNNELING_GET_REQUEST_TUNNEL(&tunnel_req, bufid, status);

			(void)status;

			if(ZB_TRUE == tunnel_opened)
			{
				ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL_RESPONSE(buf_resp, header->addr_data.common_data.source.u, 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, TUNNEL_SRV_ENDPOINT, TUNNEL_SRV_ENDPOINT, ZB_AF_HA_PROFILE_ID, ZB_ZCL_DISABLE_DEFAULT_RESPONSE, ZB_ZCL_GET_SEQ_NUM(), NULL, 0x0, ZB_ZCL_TUNNELING_STATUS_NO_MORE_IDS, tunnel_req.max_incoming_transfer_size );
			}
			else
			{
				tunnel_opened = ZB_TRUE;
				ZB_ZCL_TUNNELING_SEND_REQUEST_TUNNEL_RESPONSE(buf_resp, header->addr_data.common_data.source.u, 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, TUNNEL_SRV_ENDPOINT, TUNNEL_SRV_ENDPOINT, ZB_AF_HA_PROFILE_ID, ZB_ZCL_DISABLE_DEFAULT_RESPONSE, ZB_ZCL_GET_SEQ_NUM(), NULL, tunnel_id, ZB_ZCL_TUNNELING_STATUS_SUCCESS, tunnel_req.max_incoming_transfer_size );
			}

		    return ZB_TRUE;
		}

		case ZB_ZCL_TUNNELING_CLI_CMD_TRANSFER_DATA:
		{
			zb_zcl_tunneling_transfer_data_payload_t data_payload;
			zb_zcl_parse_status_t status;
			zb_bufid_t buf_data = zb_buf_get_out();

			ZB_ZCL_TUNNELING_GET_TRANSFER_DATA(&data_payload, bufid, status);

		    NRF_LOG_INFO("Data received.");

			tunnel_out_buf[0] = 'O';
			tunnel_out_buf[1] = 'K';

			zb_zcl_tunneling_server_send_transfer_data(buf_data, TUNNEL_SRV_ENDPOINT, ZB_AF_HA_PROFILE_ID, ZB_ZCL_DISABLE_DEFAULT_RESPONSE, NULL, tunnel_id, 2, tunnel_out_buf);

			(void)status;

		    return ZB_TRUE;
		}

		case ZB_ZCL_TUNNELING_CLI_CMD_CLOSE_TUNNEL:
		{
			zb_zcl_tunneling_close_tunnel_t tunnel_close;
			zb_zcl_parse_status_t status;

			ZB_ZCL_TUNNELING_GET_CLOSE_TUNNEL(&tunnel_close, bufid, status);

			(void)status;

			if(ZB_FALSE == tunnel_opened)
			{
				// TBD
			}
			else
			{
				tunnel_opened = ZB_FALSE;
			}

		    return ZB_TRUE;
		}

		default:
			break;
	}

	return ZB_FALSE;
}

On ZED I have a tunnel endpoint handler as well:

zb_uint8_t tunnel_ep_handler(zb_bufid_t bufid)
{
	zb_zcl_parsed_hdr_t * header = ZB_BUF_GET_PARAM(bufid, zb_zcl_parsed_hdr_t);

	(void)tunnel_opened;

	if(ZB_ZCL_CLUSTER_ID_TUNNELING != header->cluster_id)
	{
		return ZB_FALSE;
	}

	if(ZB_AF_HA_PROFILE_ID != header->profile_id)
	{
		return ZB_FALSE;
	}


    NRF_LOG_INFO("Tunnel Handler, cmd_id: %x", header->cmd_id);

	switch(header->cmd_id)
	{
		case ZB_ZCL_TUNNELING_SRV_CMD_REQUEST_TUNNEL_RESPONSE:
		{
			zb_zcl_tunneling_request_tunnel_response_t tunnel_req_resp;
			zb_zcl_parse_status_t status;

			ZB_ZCL_TUNNELING_GET_REQUEST_TUNNEL_RESPONSE(&tunnel_req_resp, bufid, status);

			(void)status;

			NRF_LOG_INFO("Tunnel status: %x", tunnel_req_resp.tunnel_status);

			if(ZB_ZCL_TUNNELING_STATUS_SUCCESS != tunnel_req_resp.tunnel_status)
			{
				return ZB_FALSE;
			}

			tunnel_id = tunnel_req_resp.tunnel_id;
			tunnel_opened = ZB_TRUE;

			tunnel_out_buf[0] = 'O';
			tunnel_out_buf[1] = 'K';

			zb_bufid_t buf_data = zb_buf_get_out();

			zb_zcl_tunneling_client_send_transfer_data(buf_data, TUNNEL_CLI_ENDPOINT, ZB_AF_HA_PROFILE_ID, ZB_ZCL_DISABLE_DEFAULT_RESPONSE, NULL, tunnel_id, 2, tunnel_out_buf);

		    return ZB_TRUE;
		}
		case ZB_ZCL_TUNNELING_SRV_CMD_TUNNEL_CLOSURE_NOTIFICATION:
		{
			tunnel_opened = ZB_FALSE;
			return ZB_TRUE;
		}
		default:
			break;
	}

	return ZB_FALSE;
}

On Wireshark I can see proper flow - ZED requests tunnel and ZC sends request tunnel response with status success. So I expect then ZED to call zb_zcl_tunneling_client_send_transfer_data and send data, but zb_zcl_tunneling_client_send_transfer_data returns with code -1.

By accident I found a workaround - ZC must first send request tunnel response with error status followed by the second one reponse with success - then I'm getting transfer data from client to server, but still server to client transfer data request (zb_zcl_tunneling_server_send_transfer_data) returns -1.

Could you please give me a hint what I'm doing wrong?

Related