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?

Parents
  • Hi Justianas, 

    If you have a look at section 3.4.2.1 Vol 3 Part F in Bluetooth Core Spec v5.0 you can find that (Exchange MTU Request)"shall only be sent once during a connection by the client. The Client Rx MTU parameter shall be set to the maximum size of the attribute protocol PDU that the client can receive" And this is stated in our documentation as well: NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once.

    att_mtu_desired_periph is what you set when you init gatt for all connections, .att_mtu_desired is used internally inside nrf_ble_gatt.c to pass the value of att_mtu_desired_periph, I don't think you need to touch it. 

    Regarding the effective result of MTU exchange and DLE, I think the implementation of gatt_evt_handler() could be wrong, I will double check it. 

    You should only print out the efective value when you receive the NRF_BLE_GATT_EVT_ATT_MTU_UPDATED event and NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED, instead of the desired values.  

    It's pretty long thread, could you summarize the question you still have ? 

Reply
  • Hi Justianas, 

    If you have a look at section 3.4.2.1 Vol 3 Part F in Bluetooth Core Spec v5.0 you can find that (Exchange MTU Request)"shall only be sent once during a connection by the client. The Client Rx MTU parameter shall be set to the maximum size of the attribute protocol PDU that the client can receive" And this is stated in our documentation as well: NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once.

    att_mtu_desired_periph is what you set when you init gatt for all connections, .att_mtu_desired is used internally inside nrf_ble_gatt.c to pass the value of att_mtu_desired_periph, I don't think you need to touch it. 

    Regarding the effective result of MTU exchange and DLE, I think the implementation of gatt_evt_handler() could be wrong, I will double check it. 

    You should only print out the efective value when you receive the NRF_BLE_GATT_EVT_ATT_MTU_UPDATED event and NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED, instead of the desired values.  

    It's pretty long thread, could you summarize the question you still have ? 

Children
Related