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?

  • 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!

  • 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. 

Related