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?