[Zigbee] ZCL Tunneling cluster / APS Fragmentation

Setup:

nrf52840DK (Zigbee Cordinator based on Zigbee Coordinator sample)

nrf52840DK (ZED)

NCS v2.4.1

Hi,

I am working on Tunneling cluster handling as that one is not implemented in the SDK.

I have encountered weird problem with adding data to allocated buffer.

As Tunneling cluster supports APS fragmentation I would like to send eg. 1kB of data and use the APS layer for fragmentation handling.

Take a look on following snippet (simplified): 

static void test(zb_bufid_t bufid, zb_uint16_t cb_param)
{
    ARG_UNUSED(cb_param);
    LOG_INF("Allocated max buffer size: %u", zb_buf_get_max_size(bufid));   // Prints: 1136
    uint8_t *ptr = ZB_ZCL_START_PACKET(bufid);
    LOG_INF("pointer start:%p", (void *)ptr);                               // Prints: start address
    ZB_ZCL_PACKET_PUT_DATA_N(ptr, data, 260);                               
    LOG_INF("pointer end:%p", (void *)ptr);                                 // Prints: end address
    LOG_INF("BYTES written:%u", ZB_ZCL_GET_BYTES_WRITTEN(bufid, ptr));      // Prints: 4
    zb_buf_free(bufid);
    // end_address - start_address == 260
    
{

void send_test(void)
{
    /* all necessary initalizations */
    zigbee_get_out_buf_delayed_ext(test, 0, 1024);
}

It seems like there is no way to put to the buffer more than 255 bytes. 

If len of data is below 256 everything is handled properly. All data is added to the buffer, ZCL:Tunneling:TransferData is being sent, APS Fragmentation works dividing the data into 5 chunks.

When size exceeds 255 then the snippet of code above produces weird values.
Number of bytes written then is LEN - UINT8_T_MAX and that number of bytes is then sent in the ZCL:Tunneling:TransferData

I have verified the start and end address and their substraction is equal to 260

I was also using ZB_ZCL_GET_BYTES_AVAILABLE_WITH_FRAGMENTATION macro to check how many bytes are supported and it is something around 1617 bytes if I am not mistaken.

I could not find any information about size limitations regarding Tunneling cluster.

The only hint I have found is following snippet of code (zb_zcl_tunneling.h): 

typedef ZB_PACKED_PRE struct zb_zcl_tunneling_transfer_data_payload_s {

  /** @ref zb_zcl_tunneling_transfer_data_hdr_t
   */
  zb_zcl_tunneling_transfer_data_hdr_t hdr;

  /** Size of @ref tun_data */
  zb_uint8_t data_size;

  /** @brief Octet containing the data to be transferred through the tunnel in
   * the format of the communication protocol for which the tunnel has been
   * requested and opened. The payload contains the assembled data exactly as it
   * was sent by the client. Theoretically, its length is solely limited through
   * the fragmentation algorithm and the RX/TX transfer buffer sizes within the
   * communication partners. The content of the payload is up to the application
   * sending the data. It is neither guaranteed, that it contains a complete PDU
   * nor is any other assumption on its internal format made. This is left up to
   * the implementer of the specific protocol tunnel behavior.
   */
  zb_uint8_t *tun_data;
} ZB_PACKED_STRUCT zb_zcl_tunneling_transfer_data_payload_t;

Structure contains data_size variable of zb_uint8_t type which seems a little bit suspicious (but I am not using this structure in my code). Simply because the zb_zcl_tunneling.h API

has got following declaration of function which should be used for data sending: 

zb_ret_t zb_zcl_tunneling_client_send_transfer_data(
    zb_uint8_t param, zb_uint8_t ep, zb_uint16_t prfl_id, zb_uint8_t def_resp,
    zb_callback_t cb, zb_uint16_t tunnel_id, zb_uint16_t data_size,
    zb_uint8_t *image_data);

Here the size is given as zb_uint16_t suggesting that payload above UINT8_T_MAX is allowed.

Could you elaborate on that topic ? 

Am I missing something ?

Best regards,

Pawel

Parents
  • Hi, 
    I would like to share my newest findings. 
    It seems that APS fragmentation does not work properly -> more than 58bytes. 
    I was thinking that it works well, but after more long term tests it seems to be different. 

    Even if sending the ZCL Command returns RET_OK, the APS callback returns RET_NO_MEMORY and command is not being sent at all (I verify it under Wireshark).


    zb_ret_t zb_zcl_tunneling_server_send_transfer_data(zb_uint8_t param, zb_uint8_t ep, zb_uint16_t prfl_id,
                                                        zb_uint8_t def_resp, zb_callback_t cb, zb_uint16_t tunnel_id,
                                                        zb_uint16_t data_size, zb_uint8_t *image_data) {
        ARG_UNUSED(def_resp);
        ARG_UNUSED(ep);
        ARG_UNUSED(prfl_id);
    
        if (!data_size || !image_data) {
            zb_buf_free(param);
            return RET_EMPTY;
        }
    
        tunnel_session_t *tunnel = find_session_by_tunnel_id(tunnel_id);
        if (!tunnel) {
            zb_buf_free(param);
            return RET_EMPTY;
        }
    
        zb_addr_u addr = {.addr_short = tunnel->session_data.dst.short_addr};
        uint8_t *ptr = ZB_ZCL_START_PACKET(param);
        ZB_ZCL_CONSTRUCT_SPECIFIC_COMMAND_RES_FRAME_CONTROL(ptr);
        ZB_ZCL_CONSTRUCT_COMMAND_HEADER(ptr, ZB_ZCL_GET_SEQ_NUM(), ZB_ZCL_TUNNELING_SRV_CMD_TRANSFER_DATA);
        ZB_ZCL_PACKET_PUT_DATA16(ptr, &tunnel_id);
        ZB_ZCL_PACKET_PUT_DATA_N(ptr, image_data, data_size);
        return zb_zcl_finish_and_send_packet_new(
            param, ptr, &addr, ZB_APS_ADDR_MODE_16_ENDP_PRESENT, tunnel->session_data.dst.ep, CONFIG_ZB_DEVICE_ENDPOINT,
            CONFIG_ZB_DEVICE_PROFILE_ID, ZB_ZCL_CLUSTER_ID_TUNNELING, cb, false, false, 0);
    }


    static void transfer_ams_data_aps_ack_cb(zb_bufid_t bufid) {
        zb_zcl_command_send_status_t *cmd_send_status = ZB_BUF_GET_PARAM(bufid, zb_zcl_command_send_status_t);
        if (cmd_send_status) {
            if (cmd_send_status->status != RET_OK) {
                LOG_ERR("APS CB stat: %d", cmd_send_status->status);
            }
        }
    
        k_mutex_lock(&tunnel_ctx_mtx, K_FOREVER);
        tunnel_session_t *tunnel = &tunnel_sessions[AMS_IDX];
        /* Stop the timer if started by UART RX thread as we are going to call send_tunnel_data from here */
        k_timer_stop(&tunnel->timer);
        zb_buf_free(bufid);
        zigbee_get_out_buf_delayed_ext(send_tunnel_data, tunnel->tunnel_id, MIN_REQUIRED_BUFFER_SIZE);
        k_mutex_unlock(&tunnel_ctx_mtx);
    }
    

    When MaxIncomingPacketSize is limited to 52bytes everything works very well :) but I would like to have slightly better throughput 

Reply
  • Hi, 
    I would like to share my newest findings. 
    It seems that APS fragmentation does not work properly -> more than 58bytes. 
    I was thinking that it works well, but after more long term tests it seems to be different. 

    Even if sending the ZCL Command returns RET_OK, the APS callback returns RET_NO_MEMORY and command is not being sent at all (I verify it under Wireshark).


    zb_ret_t zb_zcl_tunneling_server_send_transfer_data(zb_uint8_t param, zb_uint8_t ep, zb_uint16_t prfl_id,
                                                        zb_uint8_t def_resp, zb_callback_t cb, zb_uint16_t tunnel_id,
                                                        zb_uint16_t data_size, zb_uint8_t *image_data) {
        ARG_UNUSED(def_resp);
        ARG_UNUSED(ep);
        ARG_UNUSED(prfl_id);
    
        if (!data_size || !image_data) {
            zb_buf_free(param);
            return RET_EMPTY;
        }
    
        tunnel_session_t *tunnel = find_session_by_tunnel_id(tunnel_id);
        if (!tunnel) {
            zb_buf_free(param);
            return RET_EMPTY;
        }
    
        zb_addr_u addr = {.addr_short = tunnel->session_data.dst.short_addr};
        uint8_t *ptr = ZB_ZCL_START_PACKET(param);
        ZB_ZCL_CONSTRUCT_SPECIFIC_COMMAND_RES_FRAME_CONTROL(ptr);
        ZB_ZCL_CONSTRUCT_COMMAND_HEADER(ptr, ZB_ZCL_GET_SEQ_NUM(), ZB_ZCL_TUNNELING_SRV_CMD_TRANSFER_DATA);
        ZB_ZCL_PACKET_PUT_DATA16(ptr, &tunnel_id);
        ZB_ZCL_PACKET_PUT_DATA_N(ptr, image_data, data_size);
        return zb_zcl_finish_and_send_packet_new(
            param, ptr, &addr, ZB_APS_ADDR_MODE_16_ENDP_PRESENT, tunnel->session_data.dst.ep, CONFIG_ZB_DEVICE_ENDPOINT,
            CONFIG_ZB_DEVICE_PROFILE_ID, ZB_ZCL_CLUSTER_ID_TUNNELING, cb, false, false, 0);
    }


    static void transfer_ams_data_aps_ack_cb(zb_bufid_t bufid) {
        zb_zcl_command_send_status_t *cmd_send_status = ZB_BUF_GET_PARAM(bufid, zb_zcl_command_send_status_t);
        if (cmd_send_status) {
            if (cmd_send_status->status != RET_OK) {
                LOG_ERR("APS CB stat: %d", cmd_send_status->status);
            }
        }
    
        k_mutex_lock(&tunnel_ctx_mtx, K_FOREVER);
        tunnel_session_t *tunnel = &tunnel_sessions[AMS_IDX];
        /* Stop the timer if started by UART RX thread as we are going to call send_tunnel_data from here */
        k_timer_stop(&tunnel->timer);
        zb_buf_free(bufid);
        zigbee_get_out_buf_delayed_ext(send_tunnel_data, tunnel->tunnel_id, MIN_REQUIRED_BUFFER_SIZE);
        k_mutex_unlock(&tunnel_ctx_mtx);
    }
    

    When MaxIncomingPacketSize is limited to 52bytes everything works very well :) but I would like to have slightly better throughput 

Children
Related