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

Changing and verifying mtu and data_lenght after connection event

Hi,

So I am working on NRF52832 with S132 6.1.0 and SDK 15.2.0 mtu and data lenght testings. During that time I was unable to change mtu multiple times while connected (BLE 5 specs should allow that).

1. First thing first, in documentation GATTC ATT_MTU Exchange is somehow related with event "connected". I noticed that both examples related with mtu in sdk 15.2.0 (ble_app_att_mtu_throughput and ble_app_uart) sets mtu just after connection event. If I try to change it as in ble_app_att_mtu_throughput and set it while device is connected, commands nrf_ble_gatt_att_mtu_periph_set and nrf_ble_gatt_att_mtu_central_set only sets desired_mtu for peripheral or central and nothing more. So actual change is initiated only after another connection, just after event "connected" is received.

So I tried to mimic the same procedure just like  in nrf_ble_gatt.c where the actual mtu changes are happening after connection event  by using function bellow. It is not setting new value unless I add "m_gatt.links[m_conn_handle].att_mtu_desired=att_mtu;" . What is the relation between att_mtu_desired_periph (set with mtu_periph_set) and att_mtu_desired?

void gatt_mtu_set(uint16_t att_mtu)
{
	if (connected==true){
        ret_code_t err_code;
        m_test_params.att_mtu = att_mtu;
		m_gatt.links[m_conn_handle].att_mtu_desired=att_mtu; //for some reason I need to set this att_mtu_desired in links[] structure
        err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, att_mtu);
        APP_ERROR_CHECK(err_code);
		err_code = nrf_ble_gatt_att_mtu_central_set(&m_gatt, att_mtu);
		APP_ERROR_CHECK(err_code);
		err_code=sd_ble_gattc_exchange_mtu_request(m_conn_handle, att_mtu);
		if (err_code == NRF_SUCCESS)
        {
            m_gatt.links[m_conn_handle].att_mtu_exchange_requested = true;
        }
        else if (err_code == NRF_ERROR_BUSY)
        {
            m_gatt.links[m_conn_handle].att_mtu_exchange_pending = true;
            NRF_LOG_DEBUG("sd_ble_gattc_exchange_mtu_request()"
                          " on connection 0x%x returned busy, will retry.", m_conn_handle);
        }
        else
        {
            NRF_LOG_ERROR("sd_ble_gattc_exchange_mtu_request() returned %s.",
                          nrf_strerror_get(err_code));
        }
		
		if (err_code==NRF_SUCCESS){
			printf("Sucessfully upadted mtu length\r\n");
		}else{
			printf("Failed to upadte mtu length\r\n" );
		}
		printf("Pending %d, requested %d\r\n",m_gatt.links[m_conn_handle].att_mtu_exchange_pending,m_gatt.links[m_conn_handle].att_mtu_exchange_requested  );
		
	}else{
		printf("Cannot apply mtu length: not connected\r\n" );
	}

}

So anyway this command works the first time even after connection event.  All the other times after this successful update that I am getting "NRF_ERROR_INVALID_STATE" with any mtu_value possible. I tired to check flags att_mtu_exchange_requested and att_mtu_exchange_pending and both were false before doing the mtu update. Function returning this state is not visible and I cannot find any clues in documentation. It seems to me like only one mtu update is available after connection event and softdevice is blocking all the others even though BLE 5 specs should allow that.

I also noticed that in ble_app_att_mtu_throughput example main.c file lines 773: (void) nrf_ble_gatt_data_length_get(&m_gatt, BLE_CONN_HANDLE_INVALID, &dl) and 961:

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);

    m_test_params.data_len = value;
}

You are using BLE_CONN_HANDLE_INVALID instead of current connection handle for setting and getting data_length. It is  because these two board are disconnected while "test" is not running, even though it is not necessary to disconnected these two boards at all if all BLE 5 specs are implemented. So it seems that you are avoiding to mess with data_lenght and mtu size while connection is active and this example is manipulating around this issue.

2. The verification process of successful mtu and data_lenght update is very unclear. 

In documentation structure nrf_ble_gatt_link_t contains variables att_mtu_desired, att_mtu_effective and data_length_desired and data_length_effective. So I thought effective values of both parameters should be the ones accepted and confirmed by central and I can verify changes by looking at them. But in documentation data_length_effective for some reason is requested data length meanwhile  data_length_desired is desired data length. So what is the difference between requested and desired data length? At the same time att_mtu_effective is just an effective value and att_mtu_desired is requested value as it should be.

In ble_app_uart example you are saying that "ATT MTU exchange completed" after updating just desired values event though effective values remains the same (as I found out in question above). So the user is misguided that current connection contains this mtu size, but these variables changes absolutely nothing during the current connection.

/**@brief Function for handling events from the GATT library. */
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
    if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
    {
        m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
        NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
    }
    NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
                  p_gatt->att_mtu_desired_central,
                  p_gatt->att_mtu_desired_periph);
}

Meanwhile in ble_app_att_mtu_throughput example you are saying that the current mtu value is att_mtu_effective as I was thinking, but the current data length is not effective value but "p_evt->params.data_length".

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);
}

So what I am missing, how to properly verify current mtu and data lenght while connected?

Related