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

Problems while discovering services on a multilink central

Hi,

I developped a multilink central based on the example code ble_app_multilink_central.

I want to connect to several peripherals with two different custom services as shown in the following schematic.

The connection work but I have problems while discovering the services.

Sometimes the central discover all the services but often some services are not discovered and I don't understand why.

The discovery handler executes many times for each connection and the event type is often BLE_DB_DISCOVERY_ERROR.

Here is my discovery handler :

Here is an example of what can happen during a connection with 2 RFID and 1 Relay :

Here we can see that we have the relay on conn_handle 0x0 and the RFIDs on conn_handle 0x1 and 0x2.

We can see that the RFID service is not discovered on the conn_handle 0x1.

My questions are :

-When does the discovery handler execute for each connection?

-How to obtain the event BLE_DB_DISCOVERY_COMPLETE?

-Why does the discovery handler execute several time on each connection? And why is it not executed again while the service is not discovered?

Parents
  • If I remember correctly there is a limitation with the discovery module. so you should only do service discovery on one peer at the time. Can you try to add a check so you do not start service discovery on the new device if the process is already ongoing?

  • Do you have any other suggestions to improve my service discovery please run_ar?

  • Hi Hung Bui,

    Thank you for your help.

    For the ble_app_hrs_rscs_relay example :

    I have tried to start scanning after the discovery is complete and it works. I can’t find the issue anymore.

    For my code :

     

    The two custom services have the same 16 bits UUID but not the same base UUID. 

    I was thinking it was possible to do this but maybe it’s a misunderstanding?

     

    This is the definition of the UUIDs for my custom service “RELAY” :

    This is the definition of the UUIDs for my custom service “RFID” :

    These are the structures I use in my main.c :

    This is in my sdk_config.h :

    I added NRF_LOG_DEBUG() in discovery_complete_evt_trigger() :

    /**@brief     Function for triggering a Discovery Complete or Service Not Found event to the
     *            application.
     *
     * @details   This function will fetch the event handler based on the UUID of the service being
     *            discovered. (The event handler is registered by the application beforehand).
     *            It then triggers an event indicating the completion of the service discovery.
     *            If no event handler was found, then this function will do nothing.
     *
     * @param[in] p_db_discovery Pointer to the DB discovery structure.
     * @param[in] is_srv_found   Variable to indicate if the service was found at the peer.
     * @param[in] conn_handle    Connection Handle.
     */
    static void discovery_complete_evt_trigger(ble_db_discovery_t * p_db_discovery,
                                               bool                 is_srv_found,
                                               uint16_t             conn_handle)
    {
        ble_db_discovery_evt_handler_t   p_evt_handler;
        ble_gatt_db_srv_t              * p_srv_being_discovered;
    
        p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
    
        NRF_LOG_DEBUG("m_num_of_handlers_reg = %d",m_num_of_handlers_reg);
        NRF_LOG_DEBUG("m_pending_usr_evt_index = %d",m_pending_usr_evt_index);
    
        p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));
    
        if (p_evt_handler != NULL)
        {
            if (m_pending_usr_evt_index < DB_DISCOVERY_MAX_USERS)
            {
                // Insert an event into the pending event list.
                m_pending_user_evts[m_pending_usr_evt_index].evt.conn_handle = conn_handle;
                m_pending_user_evts[m_pending_usr_evt_index].evt.params.discovered_db =
                    *p_srv_being_discovered;
    
                if (is_srv_found)
                {
                    m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
                        BLE_DB_DISCOVERY_COMPLETE;
                }
                else
                {
                    m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
                        BLE_DB_DISCOVERY_SRV_NOT_FOUND;
                }
    
                m_pending_user_evts[m_pending_usr_evt_index].evt_handler = p_evt_handler;
                m_pending_usr_evt_index++;
    
                NRF_LOG_DEBUG("m_pending_usr_evt_index = %d",m_pending_usr_evt_index);
    
                if (m_pending_usr_evt_index == m_num_of_handlers_reg)
                {
                    // All registered modules have pending events. Send all pending events to the user
                    // modules.
                    pending_user_evts_send();
                }
                else
                {
                    // Too many events pending. Do nothing. (Ideally this should not happen.)
                }
            }
        }
    }

    Now we will see m_num_of_handlers_reg and m_pending_usr_evt_index in the logs.

    I observed that even for the last service discovery which don't work, m_num_of_handlers_reg is equal to m_pending_usr_evt_index so the function pending_user_evts_send() should be called.

    I added NRF_LOG_DEBUG() in pending_user_evts_send() to see which event type is passed to the event handler :

    /**@brief Function for sending all pending discovery events to the corresponding user modules.
     */
    static void pending_user_evts_send(void)
    {
        for (uint32_t i = 0; i < m_num_of_handlers_reg; i++)
        {
            
            NRF_LOG_DEBUG("m_pending_user_evts[i].evt = %d",m_pending_user_evts[i].evt.evt_type);
    
            // Pass the event to the corresponding event handler.
            m_pending_user_evts[i].evt_handler(&(m_pending_user_evts[i].evt));
        }
    
        m_pending_usr_evt_index = 0;
    }

    Here is an example of the logs when I don't get the event EVT_DISCOVERY_COMPLETE :

    <info> app: ------------------------------------------------------------------------------------------
    <info> app: -------------------------------------Concentrator-----------------------------------------
    <info> app: ------------------------------------------------------------------------------------------
    <info> app: Scanning for RFID and RELAY.
    <info> app: >>>>>RFID found<<<<<
    <info> app: Connection 0x0 established, attempt to find RFID or RELAY
    <debug> ble_db_disc: Starting discovery of service with UUID 0x1 on connection handle 0x0.
    <debug> ble_db_disc: Found service UUID 0x1.
    <debug> ble_db_disc: Discovery of service with UUID 0x1 completed with success on connection handle 0x0.
    <debug> ble_db_disc: m_num_of_handlers_reg = 2
    <debug> ble_db_disc: m_pending_usr_evt_index = 0
    <debug> ble_db_disc: m_pending_usr_evt_index = 1
    <debug> ble_db_disc: Starting discovery of service with UUID 0x1 on connection handle 0x0.
    <debug> ble_db_disc: Service UUID 0x1 not found.
    <debug> ble_db_disc: m_num_of_handlers_reg = 2
    <debug> ble_db_disc: m_pending_usr_evt_index = 1
    <debug> ble_db_disc: m_pending_usr_evt_index = 2
    <debug> ble_db_disc: m_pending_user_evts[i].evt.evt_type = 0
    <info> app: **********RFID service discovered on conn_handle 0x0**********
    <info> app: Scanning for RFID and RELAY.
    <debug> ble_db_disc: m_pending_user_evts[i].evt.evt_type = 2
    <info> app: >>>>>RFID found<<<<<
    <info> app: Connection 0x1 established, attempt to find RFID or RELAY
    <debug> ble_db_disc: Starting discovery of service with UUID 0x1 on connection handle 0x1.
    <debug> ble_db_disc: Found service UUID 0x1.
    <debug> ble_db_disc: Discovery of service with UUID 0x1 completed with success on connection handle 0x1.
    <debug> ble_db_disc: m_num_of_handlers_reg = 2
    <debug> ble_db_disc: m_pending_usr_evt_index = 0
    <debug> ble_db_disc: m_pending_usr_evt_index = 1
    <debug> ble_db_disc: Starting discovery of service with UUID 0x1 on connection handle 0x1.
    <debug> ble_db_disc: Service UUID 0x1 not found.
    <debug> ble_db_disc: m_num_of_handlers_reg = 2
    <debug> ble_db_disc: m_pending_usr_evt_index = 1
    <debug> ble_db_disc: m_pending_usr_evt_index = 2
    <debug> ble_db_disc: m_pending_user_evts[i].evt.evt_type = 0
    <info> app: **********RFID service discovered on conn_handle 0x1**********
    <info> app: Scanning for RFID and RELAY.
    <debug> ble_db_disc: m_pending_user_evts[i].evt.evt_type = 2
    <info> app: >>>>>RELAY found<<<<<
    <info> app: Connection 0x2 established, attempt to find RFID or RELAY
    <debug> ble_db_disc: Starting discovery of service with UUID 0x1 on connection handle 0x2.
    <debug> ble_db_disc: Service UUID 0x1 not found.
    <debug> ble_db_disc: m_num_of_handlers_reg = 2
    <debug> ble_db_disc: m_pending_usr_evt_index = 0
    <debug> ble_db_disc: m_pending_usr_evt_index = 1
    <debug> ble_db_disc: Starting discovery of service with UUID 0x1 on connection handle 0x2.
    <debug> ble_db_disc: Found service UUID 0x1.
    <debug> ble_db_disc: Discovery of service with UUID 0x1 completed with success on connection handle 0x2.
    <debug> ble_db_disc: m_num_of_handlers_reg = 2
    <debug> ble_db_disc: m_pending_usr_evt_index = 1
    <debug> ble_db_disc: m_pending_usr_evt_index = 2
    <debug> ble_db_disc: m_pending_user_evts[i].evt.evt_type = 2
    <debug> ble_db_disc: m_pending_user_evts[i].evt.evt_type = 0

    Now, I don't really understand what is going wrong.

  • Hi Jules, 

    I think we are getting close, now the problem is around why relay_on_db_disc_evt() (or rfid_on_db_disc_evt() ) wouldn't detect when there is an UUID match (evt_type = 0 ). 

    There is a following check: 

    if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
    p_evt->params.discovered_db.srv_uuid.uuid == RELAY_UUID &&
    p_evt->params.discovered_db.srv_uuid.type == p_relay_c->uuid_type)

    I suspect it could be something wrong with the uuid_type. If you can print out those values in the log, we may be able to find why the function is called but not executing anything. 

    We can try to test here and debug your application as well. But it doesn't built here. There is some absolute path you set (P:\Nordic\)

    If possible please send the latest source code. Are you still on SDK v15.0 or you moved to SDK v15.3 ? 

  • Hi Hung Bui,

    I added logs so we can see the parameters inside the checks in rfid_on_db_disc_evt() and in relay_on_db_disc_evt() when the event is BLE_DB_DISCOVERY_COMPLETE :

    void rfid_on_db_disc_evt(rfid_c_t * p_rfid_c, ble_db_discovery_evt_t const * p_evt)
    {
        if(p_evt->evt_type == 0)
        {
            NRF_LOG_INFO("rfid_on_db_disc_evt :");
            NRF_LOG_INFO("\tp_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE : %d",p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE);
            NRF_LOG_INFO("\tp_evt->params.discovered_db.srv_uuid.uuid == RFID_UUID : %d",p_evt->params.discovered_db.srv_uuid.uuid == RFID_UUID);
            NRF_LOG_INFO("\tp_evt->params.discovered_db.srv_uuid.type : %d\t\t\tp_rfid_c->uuid_type : %d",p_evt->params.discovered_db.srv_uuid.type,p_rfid_c->uuid_type);
        } 
    
        // Check if the Led Button Service was discovered.
        if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
            p_evt->params.discovered_db.srv_uuid.uuid == RFID_UUID &&
            p_evt->params.discovered_db.srv_uuid.type == p_rfid_c->uuid_type)
        {
            rfid_c_evt_t evt;
    
            evt.evt_type    = RFID_C_EVT_DISCOVERY_COMPLETE;
            evt.conn_handle = p_evt->conn_handle;
    
            for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
            {
                //NRF_LOG_INFO("Discovering characteristics.");
                const ble_gatt_db_char_t * p_char = &(p_evt->params.discovered_db.charateristics[i]);
                switch (p_char->characteristic.uuid.uuid)
                {
                    case SENSORS_FRAME_CHAR_UUID:
                        evt.params.peer_db.sensors_frame_handle      = p_char->characteristic.handle_value;
                        evt.params.peer_db.sensors_frame_cccd_handle = p_char->cccd_handle;
                        break;
                    
                    case MEASURE_REQUEST_CHAR_UUID:
                        evt.params.peer_db.measure_request_handle     = p_char->characteristic.handle_value;
                        break;
    
                    default:
                        break;
                }
            }
    
            //NRF_LOG_INFO("RFID Service discovered at peer.");
            //If the instance has been assigned prior to db_discovery, assign the db_handles
            if (p_rfid_c->conn_handle != BLE_CONN_HANDLE_INVALID)
            {
                if ((p_rfid_c->peer_rfid_db.sensors_frame_handle      == BLE_GATT_HANDLE_INVALID)&&
                    (p_rfid_c->peer_rfid_db.sensors_frame_cccd_handle == BLE_GATT_HANDLE_INVALID))
                {
                    p_rfid_c->peer_rfid_db = evt.params.peer_db;
                }
            }
    
            p_rfid_c->evt_handler(p_rfid_c, &evt);
    
        }
    }
    void relay_on_db_disc_evt(relay_c_t * p_relay_c, ble_db_discovery_evt_t const * p_evt)
    {
        if(p_evt->evt_type == 0)
        {
            NRF_LOG_INFO("relay_on_db_disc_evt :");
            NRF_LOG_INFO("\tp_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE : %d",p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE);
            NRF_LOG_INFO("\tp_evt->params.discovered_db.srv_uuid.uuid == RELAY_UUID : %d",p_evt->params.discovered_db.srv_uuid.uuid == RELAY_UUID);
            NRF_LOG_INFO("\tp_evt->params.discovered_db.srv_uuid.type : %d\t\t\tp_relay_c->uuid_type : %d",p_evt->params.discovered_db.srv_uuid.type,p_relay_c->uuid_type);
        }    
    
        // Check if the Led Button Service was discovered.
        if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
            p_evt->params.discovered_db.srv_uuid.uuid == RELAY_UUID &&
            p_evt->params.discovered_db.srv_uuid.type == p_relay_c->uuid_type)
        {
            relay_c_evt_t evt;
    
            evt.evt_type    = RELAY_C_EVT_DISCOVERY_COMPLETE;
            evt.conn_handle = p_evt->conn_handle;
    
            for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
            {
                //NRF_LOG_INFO("Discovering characteristics.");
                const ble_gatt_db_char_t * p_char = &(p_evt->params.discovered_db.charateristics[i]);
                switch (p_char->characteristic.uuid.uuid)
                {
                    case BLACKLIST_CHAR_UUID:
                        evt.params.peer_db.blacklist_handle      = p_char->characteristic.handle_value;
                        evt.params.peer_db.blacklist_cccd_handle = p_char->cccd_handle;
                        break;
                    case TRAME_CONCENTRATEUR_CHAR_UUID:
                        evt.params.peer_db.trame_concentrateur_handle     = p_char->characteristic.handle_value;
                        break;
                    default:
                        break;
                }
            }
            //NRF_LOG_INFO("RELAY Service discovered at peer.");
            //If the instance has been assigned prior to db_discovery, assign the db_handles
            if (p_relay_c->conn_handle != BLE_CONN_HANDLE_INVALID)
            {
                if ((p_relay_c->peer_relay_db.blacklist_handle      == BLE_GATT_HANDLE_INVALID)&&
                    (p_relay_c->peer_relay_db.blacklist_cccd_handle == BLE_GATT_HANDLE_INVALID))
                {
                    p_relay_c->peer_relay_db = evt.params.peer_db;
                }
            }
            p_relay_c->evt_handler(p_relay_c, &evt);
        }
    }

    You were right, it seems like the problem is coming from the uuid_type, I get this :

    <info> app: ------------------------------------------------------------------------------------------
    <info> app: -------------------------------------Concentrator-----------------------------------------
    <info> app: ------------------------------------------------------------------------------------------
    <info> app: Scanning for RFID and RELAY.
    <info> app: >>>>>RFID found<<<<<
    <info> app: Connection 0x0 established, attempt to find RFID or RELAY
    <info> app: rfid_on_db_disc_evt :
    <info> app: 	p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.uuid == RFID_UUID : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.type : 2			p_rfid_c->uuid_type : 2
    <info> app: **********RFID service discovered on conn_handle 0x0**********
    <info> app: Scanning for RFID and RELAY.
    <info> app: relay_on_db_disc_evt :
    <info> app: 	p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.uuid == RELAY_UUID : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.type : 2			p_relay_c->uuid_type : 3
    <info> app: >>>>>RFID found<<<<<
    <info> app: Connection 0x1 established, attempt to find RFID or RELAY
    <info> app: rfid_on_db_disc_evt :
    <info> app: 	p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.uuid == RFID_UUID : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.type : 2			p_rfid_c->uuid_type : 2
    <info> app: **********RFID service discovered on conn_handle 0x1**********
    <info> app: Scanning for RFID and RELAY.
    <info> app: relay_on_db_disc_evt :
    <info> app: 	p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.uuid == RELAY_UUID : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.type : 2			p_relay_c->uuid_type : 21
    <info> app: >>>>>RELAY found<<<<<
    <info> app: Connection 0x2 established, attempt to find RFID or RELAY
    <info> app: rfid_on_db_disc_evt :
    <info> app: 	p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.uuid == RFID_UUID : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.type : 3			p_rfid_c->uuid_type : 2
    <info> app: relay_on_db_disc_evt :
    <info> app: 	p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.uuid == RELAY_UUID : 1
    <info> app: 	p_evt->params.discovered_db.srv_uuid.type : 3			p_relay_c->uuid_type : 178
    

    I will send you my source code in a private message.

    (P:\Nordic\) was the folder where I put SDK 15 and SDK 15.3.  (Now it is C:/Dev/nordic/)

    You have to put these two SDK in the folder of your choice and replace the path by the path of the folder you choosed. 

    I use SDK 15 but there is a exception. Only for the ble_db_discovery module, I use the SDK 15.3

    I did this in my .emProject file :

    ...
    
    c_user_include_directories= "... ;C:/Dev/nordic/nRF5_SDK_15.3.0_59ac345/components/ble/ble_db_discovery; ... "
    ...
    <folder Name="nRF_BLE">
    <file file_name="C:/Dev/nordic/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.c" />
    <file file_name="C:/Dev/nordic/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.c" />
    <file file_name="C:/Dev/nordic/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.c" />
    <file file_name="C:/Dev/nordic/nRF5_SDK_15.3.0_59ac345/components/ble/ble_db_discovery/ble_db_discovery.c" />
    <file file_name="C:/Dev/nordic/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.c" />
    <file file_name="C:/Dev/nordic/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.c" />
    </folder>
    ...

  • Hi Jules, 

    I think I found something wrong here. 

    As you can see in the log, the p_relay_c->uuid_type showing quite strange value (21, 178). 

    I think it was because of this function: 

    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
      rfid_on_db_disc_evt(&m_rfid_c[p_evt->conn_handle], p_evt);
      relay_on_db_disc_evt(&m_relay_c[p_evt->conn_handle], p_evt);
    }

    In our multilink example this work because we only have one service lbs and there can be a simple match between the index of the m_lbs_c array and the index of connection handle. When it's not the case with your application. 

    You are declaring m_rfid_c array with the size of 7 and m_relay_c with size of 1. Calling a function using m_relay_c[p_evt->conn_handle] will cause trouble if the conn_handle is not equal to 0.

    And since you don't know which one will be the first one to connect you can't be sure that the conn_handle = 0 will be always be the relay. 

    So you need to define a table that keep track of the connection handle that match with the relay and the list of active RFID node in an array. And keep that table (array) up to date on each CONNECTED/DISCONNECTED event. (You can detect if a device is a relay or a RFID by the if check inside rfid_on_db_disc_evt() and    relay_on_db_disc_evt() ) 

  • Hi Hung Bui,

    I missed this and the error was due to this, thank you for your help.

    Now I have a table containing the types (RFID_TYPE our RELAY_TYPE) of devices for each conn_handle which is updated on DISCOVERY_COMPLETE and BLE_GAP_EVT_DISCONNECTED.

    I can count the RFID devices to know which instance of m_rfid_c I have to call in db_disc_handler. 

    For the relay, since I always use one relay, I define only one instance of relay client and call this one in db_disc_handler.

Reply
  • Hi Hung Bui,

    I missed this and the error was due to this, thank you for your help.

    Now I have a table containing the types (RFID_TYPE our RELAY_TYPE) of devices for each conn_handle which is updated on DISCOVERY_COMPLETE and BLE_GAP_EVT_DISCONNECTED.

    I can count the RFID devices to know which instance of m_rfid_c I have to call in db_disc_handler. 

    For the relay, since I always use one relay, I define only one instance of relay client and call this one in db_disc_handler.

Children
Related