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

How to discover services only ones?

Hello,

I'm trying to store the discovered services and characteristics only ones at first connection with an bonded device at the central. So following connection events will be faster. Currently my code for the discovery looks like this:

    case DM_EVT_CONNECTION:
    {

					m_client.handle = (*p_handle);
									
					memset(&m_client.srv_db, 0 , sizeof (m_client.srv_db));
					
					// Discover peer's services. 
					err_code = ble_db_discovery_start(&m_client.srv_db,
																						p_event->event_param.p_gap_param->conn_handle);
					APP_ERROR_CHECK(err_code);							
					
        m_peer_count++;

        if (m_peer_count < MAX_PEER_COUNT)
        {
            scan_start();
        }
					
        break;
    }

Now I want to do something to not have to do ble_db_discovery_start at each connection.

I found that you can use these functions to do this:

ret_code_t dm_application_context_set(dm_handle_t const              * p_handle,
                                    dm_application_context_t const * p_context)

ret_code_t dm_application_context_get(dm_handle_t const        * p_handle,
                                    dm_application_context_t * p_context)

But how to actually do this is never explained.

Can anyone get me on the right track to implement this.

Thanks.

  • I see that you have seen this And that you have asked about michiel's implementation. As he said he didn't implement this persistently or with the device manager. But here you ask about and implementation that is persistent and with the device manager. Could you explain a bit more about your application? What kind of peripherals are you connecting to? How many?

  • For me it doesn't really mater if it is persistently or not it thought it would be most easy to do it persistently because the Device Manager supports that. I want to bond one device at the time and the peripheral is an simple S110 device with a button. The Central is constantly scanning for it's bonded device and tries to connect with it.

    This is all working fine but to make the connection extra fast I want to save the discovered services. I tried to implement an none persistent version but I couldn't really figure out how to do that.

    Now there are these functions meant for saving the context but there is no example anywhere on how to use them. Especially how do I set the p_context pointer or what should I give to this p_context so it knows the discovered services.

  • I mentioned here:

    In ble_app_hrs_c the Database Discovery module does service discovery to find the attribute handles for the CCCD and the characterisitic value for hrs and bas. To skip this step you need to store these (persistently or not) on the first connection and then give them to ble_hrs_c and ble_bas_c on subsequent connections.

    If you don't need to store them persistenly, you actually don't need to give the handles to ble_hrs_c and ble_bas_c on subsequent connections, because the handles will be in memory.

    The current flow in ble_app_hrs_c is like this.

    1. Application receives the DM_EVT_CONNECTION event through the device_manager_event_handler and calls ble_db_discovery_start().

    2. The database discovery module will send events to hrs and bas through db_discover_evt_handler(). If the heart rate service is found hrs will send the BLE_HRS_C_EVT_DISCOVERY_COMPLETE event to main where dm_security_setup_req() and ble_hrs_c_hrm_notif_enable() will be called, triggering bonding and enabling notifications respectively. If the battery service is found bas will send the BLE_BAS_C_EVT_DISCOVERY_COMPLETE event to main where ble_bas_c_bl_notif_enable() will be called.

    (3. When security setup is complete the DM_EVT_SECURITY_SETUP_COMPLETE event is received, which for some unknown reason calls ble_hrs_c_hrm_notif_enable() again.)

    There are probably many ways to solve this, but here is my suggestion.

    Add a flag which is set to true. This is checked in the DM_EVT_CONNECTION event. So service discovery will only be done if it is true. If it is false, dm_security_setup_req() will be called. The flag is set to false on the DM_EVT_SECURITY_SETUP_COMPLETE event.

    Now service discovery is only performed on first connection.

    We also need to make sure that notifications are enabled (CCCD = 0x0001) on the peripheral, so that it is able to send notifications. When you bond with the ble_app_hrs example it should actually store the CCCDs values, and restore them on reconnection. I tested this, and it worked fine the the heart rate service, but the battery service wouldn't send notifications. I'm not sure why, but I'll try to look into this some more when I have time.

    I wanted to call ble_hrs_c_hrm_notif_enable() and ble_bas_c_bl_notif_enable() when the DM_EVT_SECURITY_SETUP_COMPLETE event is received, since this will only be received once; when bonding procedure is complete. But as I mentioned then the battery service wouldn't send notifications this way.

    So instead I call them when the DM_EVT_LINK_SECURED event is received, which will be received on every reconnection (and the first connection). This approach results in two "unnecessary" write requests on reconnection, but this is what I have for now.

    I also commented out some function calls from hrs_c_evt_handler() and bas_c_evt_handler().

    Initial tests shows that it is working, but it is given as is.

    I have attached my project, I added pemy as a codeword all the places (I think) I have made changes.

    Peripheral side: \examples\ble_peripheral\ble_app_hrs, SDK 9.0.0, S110 8.0.0.

    Central side ble_app_hrs_c_cache, SDK 9.0.0, S120 2.1.0. Should be placed in \examples\ble_central

    Here is a sniffer trace. You can see on second connection the link gets encrypted, no service discovery, two write requests, and notifications are sent.

  • Many thanks I'm going to try it. Will report back in a few days.

Related