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

I give up; how do I do a service changed?

The documentation is VERY difficult to search. A search only goes over the chapter. I get different results depending upon which one I am in .... aarrg! And there are SOOO many.

So I want to do something very basic; 

On my peripheral I want to expose the service changed characteristic. That appears to be done by default because I see it on my central. But now I try to enable indications from the central and it fails. Well of course it does! I need to handle the BLE_GATTS_EVT_WRITE event!

So I do and come across a MAJOR difficulty. I need to have the handle of the Service Changed Characteristic. But there is no way to get it; or at least I cannot find a way to get it.

So how can I get the handle of the service changed characteristic so I can deal with it in the BLE_GATTS_EVT_WRITE event?

Parents
  • Hi Brian, 

    We have two examples in the SDK : ble_app_gatts_c and ble_app_gatts. Have you tried to test them ? 

    They are not exactly the same as you wanted (server on peripheral and client on central) however, you can use them as the referral. 

    Basically, on the server, you need to enable service changed, and send the indication. This is already handled by gatt_cache_manager.c and you just need to call pm_local_database_has_changed() to send the indication. ( it's inside bsp_event_handler() in ble_app_gatts)

    On the client, you need to do service discovery and write to the CCCD to enable indication. This is already handled by nrf_ble_gatts.c and the ble_db_discovery.c modules. Please have a look in gatts_evt_handler in main.c in ble_app_gatts_c. 

  • Thanks for the response. I understand that a client can support services; its just in practice (out in the field) I have never seen it ... except perhaps for a CTS.

    In any case, I am using the pc-ble-driver so I must use sd_* calls myself. Even so, it looks like it should be easy. Basically, as far as I can tell the GATT service is already set up and the service changed characteristic exists. Now I have an Android application that will attempt to enable indications on the service changed characteristic if it finds one. It works fine for peripheral devices out in the field.

    I also have no sd_* APIs in the pc-ble-driver that allow me to get the handle of the GATT services, characteristics, or descriptors. Looked for answers on that, too. I did see some post which suggests the handle is 0x0B but that may even be another platform, so I don't know if that is even right. Found no documentation on it though.

    So that's where I am at. What config step am I missing? Where can I find documentation on how to do this?

    UPDATE: It appears the handle I am using 0x0B for the Service Changed characteristic is wrong.

    The sd_ble_gatts_service_changed() method returns the error incorrect handle. But I cannot get the handle.

  • Please correct me if I'm wrong. You are implementing the peripheral on the pc-ble-driver ? And on this you have the GATT server ? 

    I would suggest to use nRF Connect on PC (you would need one extra dongle/dk) to do service discovery on the device and check if the service changed characteristic is available in the GATT server. You can try to write to the CCCD to enable indication. 

    Note that Android won't enable indication of service changed characteristic if there is no bond. When there is no bond, the client is not expected to store the service discovery database. 

    I haven't tried myself but if you don't see the service changed characteristic in the GATT table, you most likely need to enable in the nRF52 code which is at this folder: \examples\connectivity\ble_connectivity

  • The bottom line is I need the handle of the Service Changed characteristic on the nrf52380 dongle. There are no sp_* APIs in the pc-ble-driver to obtain that value.

    I need to invoke the method 

    sd_ble_gatts_service_changed(adapter_t *adapter, uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle));

    and I need the start handle. I use the 0xFFFF for the end handle.

    Some help with these 

    uint8_t* p_sys_attr_data;
    uint16_t p_len = 0;
    sd_ble_gatts_sys_attr_get(m_adapter, m_connection_handle, NULL, &p_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
    p_sys_attr_data = calloc(1, p_len);
    sd_ble_gatts_sys_attr_get(m_adapter, m_connection_handle, p_sys_attr_data, &p_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
    sd_ble_gatts_sys_attr_set(m_adapter, m_connection_handle, p_sys_attr_data, p_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);

    would also be nice. The table generated is kind of useless as it has no UUID so you have no idea what attribute it is talking about. The docs say to use this method to get the start handle in the service changed call. Arrg.

    I already asked what a system attribute was. After seeing the table I am more confused. Why is there only one entry? Does this table contain only descriptors? None of this makes too much sense, but somebody must know the relation between the handles and UUIDs!

Reply
  • The bottom line is I need the handle of the Service Changed characteristic on the nrf52380 dongle. There are no sp_* APIs in the pc-ble-driver to obtain that value.

    I need to invoke the method 

    sd_ble_gatts_service_changed(adapter_t *adapter, uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle));

    and I need the start handle. I use the 0xFFFF for the end handle.

    Some help with these 

    uint8_t* p_sys_attr_data;
    uint16_t p_len = 0;
    sd_ble_gatts_sys_attr_get(m_adapter, m_connection_handle, NULL, &p_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
    p_sys_attr_data = calloc(1, p_len);
    sd_ble_gatts_sys_attr_get(m_adapter, m_connection_handle, p_sys_attr_data, &p_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
    sd_ble_gatts_sys_attr_set(m_adapter, m_connection_handle, p_sys_attr_data, p_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);

    would also be nice. The table generated is kind of useless as it has no UUID so you have no idea what attribute it is talking about. The docs say to use this method to get the start handle in the service changed call. Arrg.

    I already asked what a system attribute was. After seeing the table I am more confused. Why is there only one entry? Does this table contain only descriptors? None of this makes too much sense, but somebody must know the relation between the handles and UUIDs!

Children
  • Have you really looked into the examples we provide? 

    You can find in function gscm_service_changed_ind_send() we use sd_ble_gatts_initial_user_handle_get() to get the start_handle for the sd_ble_gatts_service_changed() call (you can also use 0 AFAIK)

    The handle of the service change characteristic is not related to the start_handle. You only need the handle of service changed characteristic on the client side. This I assume is handled by the Android phone. 

  • The 'get' function gives me a value of 0xD.

    So I tried both 0 and the value provided by the table from the 'get()' method.. Both gave me the same error 0x3003

    'INVALID ATTRIBUTE HANDLE'

    There must be something more missing. For example, the restoration of the of the 'system attributes' from the previous connection. However that doesn't happen because I never get a 

    BLE_GATTS_EVT_SYS_ATTR_MISSING

    event. So maybe that's the problem.

  • Could you try follow our code in gscm_service_changed_ind_send () in gatts_cache_manager ? 


    do
        {
            err_code = sd_ble_gatts_service_changed(conn_handle, start_handle, end_handle);
            if (err_code == BLE_ERROR_INVALID_ATTR_HANDLE)
            {
                start_handle += 1;
            }
        } while (err_code == BLE_ERROR_INVALID_ATTR_HANDLE);

    I'm not 100% sure why we need to do the "trial and error" method like this, may need to check with the developer. But you don't need to do this all the time, if you find the value you can hardcode it I believe. 

  • Then I better start from 0 and not what I get from the 'get' method. I am still suspicious that it has something to do with the fact I cannot restore the system attributes because I do not get signaled the ..._SYS_ATTR_MISSING event

    Since my \examples\connectivity\ble_connectivity does not have the code you reference above, I am kind of stuck with trial and error from zero ... if it even works. 

    I definitely will not hard code, as I am implementing a peripheral, running it, disconnecting, and then implementing another, one after the other. So far it all works except for the service changed and the BLE_GATTS_EVT_SYS_ATTR_MISSING event. However, my central always re-enables indications and notifications because of the misbehaving devices that do not do bonding correctly.

    Doing the 'cycle' starting with 0 I no longer get the invalid handle, instead I get 

    BLE_ERROR_GATTS_SYS_ATTR_MISSING

  • Have you enabled indication from the central side ? Please use nRFConnect to test first, before using Android. 

Related