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

What is the difference between "data length" and MTU?

I want to use BLE 4.2 Data length extension to stuff more data into one packet. I am looking at the "ble_app_att_mtu_throughput" example and am getting confused because there is both a NRF_BLE_GATT_EVT_ATT_MTU_UPDATED event and a NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED event.

/**@brief Function for handling events from the GATT library. */
static void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
    switch (p_evt->evt_id)
    {
        case NRF_BLE_GATT_EVT_ATT_MTU_UPDATED:
        {
            m_mtu_exchanged = true;
            NRF_LOG_INFO("ATT MTU exchange completed. MTU set to %u bytes.",
                         p_evt->params.att_mtu_effective);
        } break;

        case NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED:
        {
            m_data_length_updated = true;
            NRF_LOG_INFO("Data length updated to %u bytes.", p_evt->params.data_length);
        } break;
    }

    nrf_ble_amts_on_gatt_evt(&m_amts, p_evt);
}

I thought "data length" = MTU - 3. If so, then why are there two event types, and why is there a voided function "nrf_ble_gatt_data_length_set" here? 

void data_len_ext_set(bool status)
{
    m_test_params.data_len_ext_enabled = status;

    uint8_t data_length = status ? (247 + L2CAP_HDR_LEN) : (23 + L2CAP_HDR_LEN);
    (void) nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, data_length);
}

Especially confusing is this line in amts.c, which suggests data length = MTU - 3

void nrf_ble_amts_on_gatt_evt(nrf_ble_amts_t * p_ctx, nrf_ble_gatt_evt_t const * p_gatt_evt)
{
    if (p_gatt_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)
    {
        p_ctx->max_payload_len =
            p_gatt_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
    }
}

My current project outputs this. MTU = 140. Does that mean I can assume my data length is 140 - 3  = 137? 

<debug> ble_gatt: Data length updated to 27 on connection 0x0.
<debug> ble_gatt: max_rx_octets: 27
<debug> ble_gatt: max_tx_octets: 27
<debug> ble_gatt: max_rx_time: 328
<debug> ble_gatt: max_tx_time: 328
<info> app: Data length updated to 27 bytes.
<info> app: Bonding...
<info> app: Connection secured: role: 1, conn_handle: 0x0, procedure: 0.
<debug> ble_gatt: ATT MTU updated to 140 bytes on connection 0x0 (response).
<info> app: ATT MTU exchange completed. MTU set to 140 bytes.

SDK 14.0.0

Softdevice S132 5.0.0

Parents
  • Hi Andrew, 

    the ATT MTU is the maximum transmission unit for the the ATT protocol which encapsulated inside the Data Channel PDU and the data length is the the size of the Data Channel PDU, see this illustration. 

    So if the ATT MTU is increased to 140, but the Data length is 27, then the ATT data will be segmented into 27byte chunks. Hence, if you want to fit the entire ATT MTU within the Data Channel PDU(i.e. one BLE data packet), then the Data length must be set higher than the ATT MTU size. 

    From the log output it still appers that the Data length is 27 bytes. 

    What have you set the following macros to in sdk_config?

    NRF_SDH_BLE_GAP_DATA_LENGTH

    NRF_SDH_BLE_GATT_MAX_MTU_SIZE

  • So the "data length" is the lower level number. Wow. What's the point of having an ATT MTU AND a data length? Why not just have a "data length"? 

    This must be why BLE 4.2 has the feature called "Data length extension" 

    My defines are set like this:

    #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 140
    NRF_SDH_BLE_GAP_DATA_LENGTH is nowhere in my project. Was that introduced in SDK 15.0.0? Since that is not defined, do I change the data length with nrf_ble_gatt_data_length_set()? For some reason, that function has a (void) prepended to it in the example. Why? 
  • What is DATA_LEN_MAX set to? Does nrf_ble_gatt_data_length_set return a non-zero error code?

  • #define DATA_LEN_MAX 251

    i run APP_ERROR_CHECK on nrf_ble_gatt_data_length_set and it never complains. I'm assuming this means no errors. 

  • Hmm, that is weird. Do you see the data length increasing if you set to a value below NRF_SDH_BLE_GATT_MAX_MTU_SIZE, i.e. 140? If not could you capture a sniffer trace with a BLE protocol analyzer or the nRF Sniffer? It would help to see if a request to increase the data length is sent or not. 

  • No, the data length does not increase when I set DATA_LEN_MAX to 130. Data length stays at 27. 

    I am using microBits as sniffers but they do not pick up my connection, so I don't have a sniffer trace to show. 

  • Actually, I just did a manual check and it reports that my data length is 140! I never get the NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED event, but it looks like the data length changed anyway!  I'm going to test it now. 

    void data_len_set(uint8_t value)
    {
        ret_code_t err_code;
        err_code = nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, value);
        APP_ERROR_CHECK(err_code);
    
        uint8_t future_data_length = 0;
        nrf_ble_gatt_data_length_get(&m_gatt, BLE_CONN_HANDLE_INVALID, &future_data_length);
        NRF_LOG_INFO("Next data length set to %u bytes.", future_data_length);
    }
    
    /**@brief Function for handling events from the GATT library. */
    static void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
    {
        (void) p_gatt; //UNUSED 
    
        switch (p_evt->evt_id)
        {
            case NRF_BLE_GATT_EVT_ATT_MTU_UPDATED:
            {
    
                NRF_LOG_INFO("ATT MTU exchange completed. MTU set to %u bytes.",
                             p_evt->params.att_mtu_effective);
    
                NRF_LOG_INFO("Data length is %u bytes.", p_evt->params.data_length);
            } break;
    
            case NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED:
            {
                NRF_LOG_INFO("Data length updated to %u bytes.", p_evt->params.data_length);
            } break;
        }
    }

    <info> app: Next data length set to 144 bytes.
    <info> app: Slow advertising.
    <info> app: Connected to a previously bonded device.
    <debug> ble_gatt: Requesting to update ATT MTU to 140 bytes on connection 0x0.
    <debug> ble_gatt: Requesting to update data length to 144 on connection 0x0.
    <info> app: Reset challenge status on conn_handle 0x0
    <info> app: Connected
    <info> app: connection interval: min 24, max: 24
    <debug> ble_gatt: Data length updated to 27 on connection 0x0.
    <debug> ble_gatt: max_rx_octets: 27
    <debug> ble_gatt: max_tx_octets: 27
    <debug> ble_gatt: max_rx_time: 328
    <debug> ble_gatt: max_tx_time: 328
    <info> app: Data length updated to 27 bytes.
    <info> app: Bonding...
    <info> app: Connection secured: role: 1, conn_handle: 0x0, procedure: 0.
    <debug> ble_gatt: ATT MTU updated to 140 bytes on connection 0x0 (response).
    <info> app: ATT MTU exchange completed. MTU set to 140 bytes.
    <info> app: Data length is 140 bytes.
    <info> app: Peer data updated.
    <info> app: Peer data updated.

    These results confuse me. It says "Requesting to update data length to 144", then it says "data length updated to 27 bytes". The number 27 is nowhere in my code. THEN it says "Data length IS 140". I'm just going to assume the data length is 140 now. Time to test. 

Reply
  • Actually, I just did a manual check and it reports that my data length is 140! I never get the NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED event, but it looks like the data length changed anyway!  I'm going to test it now. 

    void data_len_set(uint8_t value)
    {
        ret_code_t err_code;
        err_code = nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, value);
        APP_ERROR_CHECK(err_code);
    
        uint8_t future_data_length = 0;
        nrf_ble_gatt_data_length_get(&m_gatt, BLE_CONN_HANDLE_INVALID, &future_data_length);
        NRF_LOG_INFO("Next data length set to %u bytes.", future_data_length);
    }
    
    /**@brief Function for handling events from the GATT library. */
    static void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
    {
        (void) p_gatt; //UNUSED 
    
        switch (p_evt->evt_id)
        {
            case NRF_BLE_GATT_EVT_ATT_MTU_UPDATED:
            {
    
                NRF_LOG_INFO("ATT MTU exchange completed. MTU set to %u bytes.",
                             p_evt->params.att_mtu_effective);
    
                NRF_LOG_INFO("Data length is %u bytes.", p_evt->params.data_length);
            } break;
    
            case NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED:
            {
                NRF_LOG_INFO("Data length updated to %u bytes.", p_evt->params.data_length);
            } break;
        }
    }

    <info> app: Next data length set to 144 bytes.
    <info> app: Slow advertising.
    <info> app: Connected to a previously bonded device.
    <debug> ble_gatt: Requesting to update ATT MTU to 140 bytes on connection 0x0.
    <debug> ble_gatt: Requesting to update data length to 144 on connection 0x0.
    <info> app: Reset challenge status on conn_handle 0x0
    <info> app: Connected
    <info> app: connection interval: min 24, max: 24
    <debug> ble_gatt: Data length updated to 27 on connection 0x0.
    <debug> ble_gatt: max_rx_octets: 27
    <debug> ble_gatt: max_tx_octets: 27
    <debug> ble_gatt: max_rx_time: 328
    <debug> ble_gatt: max_tx_time: 328
    <info> app: Data length updated to 27 bytes.
    <info> app: Bonding...
    <info> app: Connection secured: role: 1, conn_handle: 0x0, procedure: 0.
    <debug> ble_gatt: ATT MTU updated to 140 bytes on connection 0x0 (response).
    <info> app: ATT MTU exchange completed. MTU set to 140 bytes.
    <info> app: Data length is 140 bytes.
    <info> app: Peer data updated.
    <info> app: Peer data updated.

    These results confuse me. It says "Requesting to update data length to 144", then it says "data length updated to 27 bytes". The number 27 is nowhere in my code. THEN it says "Data length IS 140". I'm just going to assume the data length is 140 now. Time to test. 

Children
Related