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 Reply Children
  • How many instances of the DB discovery module have you registered? Could you be using the same for all connections? Check: BLE_DB_DISCOVERY_ARRAY_DEF(m_db_discovery, 2);                      /**< Database discovery module instances. */

    The ble_app_hrs_rscs_relay example has code that shows how to start multiple instances. See the on_ble_central_evt handler in the BLE_GAP_EVT_CONNECTED event.

    If this doesn't help is it possible for you to share your project so I can see what you are doing?

  • Hi,

    I have 4 discovery module instances, 1 relay instance and 3 rfid instance.

    I use "ble_db_discovery_start()" on one instance of the discovery module "&m_db_disc[p_gap_evt->conn_handle]" in the BLE event handler in case BLE_GAP_EVT_CONNECTED (line313).

    This is the main.c of my central :

     

    #include <stdint.h>
    #include <stdio.h>
    #include <string.h>
    #include "nordic_common.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "app_timer.h"
    #include "bsp_btn_ble.h"
    #include "ble.h"
    #include "ble_hci.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "ble_db_discovery.h"
    #include "ble_conn_state.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_pwr_mgmt.h"
    
    #include "peer_manager.h"
    #include "fds.h"
    
    #include "rfid_c.h"
    #include "relay_c.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    
    #define APP_BLE_CONN_CFG_TAG      1                                     /**< A tag that refers to the BLE stack configuration we set with @ref sd_ble_cfg_set. Default tag is @ref APP_BLE_CONN_CFG_TAG. */
    #define APP_BLE_OBSERVER_PRIO     3                                     /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    
    #define SEC_PARAM_BOND              1                                   /**< Perform bonding. */
    #define SEC_PARAM_MITM              0                                   /**< Man In The Middle protection not required. */
    #define SEC_PARAM_LESC              0                                   /**< LE Secure Connections not enabled. */
    #define SEC_PARAM_KEYPRESS          0                                   /**< Keypress notifications not enabled. */
    #define SEC_PARAM_IO_CAPABILITIES   BLE_GAP_IO_CAPS_NONE                /**< No I/O capabilities. */
    #define SEC_PARAM_OOB               0                                   /**< Out Of Band data not available. */
    #define SEC_PARAM_MIN_KEY_SIZE      7                                   /**< Minimum encryption key size in octets. */
    #define SEC_PARAM_MAX_KEY_SIZE      16                                  /**< Maximum encryption key size in octets. */
    
    #define CENTRAL_SCANNING_LED      BSP_BOARD_LED_0
    #define CENTRAL_CONNECTED_LED     BSP_BOARD_LED_1
    #define LEDBUTTON_LED             BSP_BOARD_LED_2                       /**< LED to indicate a change of state of the the Button characteristic on the peer. */
    
    #define MEASURE_REQUEST_1_BUTTON     BSP_BUTTON_0//we will not need these buttons for the final version
    #define MEASURE_REQUEST_2_BUTTON     BSP_BUTTON_1
    #define MEASURE_REQUEST_3_BUTTON     BSP_BUTTON_2
    
    #define LEDBUTTON_BUTTON          BSP_BUTTON_0                          /**< Button that will write to the LED characteristic of the peer. */
    #define BUTTON_DETECTION_DELAY    APP_TIMER_TICKS(50)                   /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */
    
    #define SCAN_INTERVAL             0x00A0                                /**< Determines scan interval in units of 0.625 millisecond. */
    #define SCAN_WINDOW               0x00A0                                /**< Determines scan window in units of 0.625 millisecond. */
    #define SCAN_DURATION             0x0000                                /**< Duration of the scanning in units of 10 milliseconds. If set to 0x0000, scanning will continue until it is explicitly disabled. */
    
    #define MIN_CONNECTION_INTERVAL   MSEC_TO_UNITS(99, UNIT_1_25_MS)       /**< Determines minimum connection interval in milliseconds. */
    #define MAX_CONNECTION_INTERVAL   MSEC_TO_UNITS(100, UNIT_1_25_MS)      /**< Determines maximum connection interval in milliseconds. */
    #define SLAVE_LATENCY             0                                     /**< Determines slave latency in terms of connection events. */
    #define SUPERVISION_TIMEOUT       MSEC_TO_UNITS(4000, UNIT_10_MS)       /**< Determines supervision time-out in units of 10 milliseconds. */
    
    #define RFID_COUNT                3                                     //number of relay clients
    #define RELAY_COUNT               1                                     //number of RFID clients
    #define DB_DISC_COUNT             4                                     //number of discovery module, 1 for each peripheral
    
    NRF_BLE_GATT_DEF(m_gatt);                                               /**< GATT module instance. */
    RFID_C_ARRAY_DEF(m_rfid_c, RFID_COUNT);                                 /**< RFID service client instances. */
    RELAY_C_ARRAY_DEF(m_relay_c, RELAY_COUNT);                              /**< RELAY service client instance. */
    BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, DB_DISC_COUNT);                   /**< Database discovery module instances. */ 
    
    /**< Name of the devices we try to connect to. These names are searched for in the scan report data*/
    static char const m_target_periph_RFID_name[] = "RFID";             
    static char const m_target_IHMI_relay_name[] = "RELAY";
    
    static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; /**< buffer where advertising reports will be stored by the SoftDevice. */
    
    uint8_t cptButtonEvent=0;
    uint8_t measure_request[2]={0xFF,0xFF};
    
    //Pour les UUID custom, faire bien attetntion au quel on a déclaré en premier pour savoir si il s'agit de BEGIN ou BEGIN+1
    ble_uuid_t rfid_uuid = {RFID_UUID, BLE_UUID_TYPE_VENDOR_BEGIN};
    ble_uuid_t relay_uuid = {RELAY_UUID, BLE_UUID_TYPE_VENDOR_BEGIN+1};
    
    /**@brief Pointer to the buffer where advertising reports will be stored by the SoftDevice. */
    static ble_data_t m_scan_buffer =
    {
        m_scan_buffer_data,
        BLE_GAP_SCAN_BUFFER_MIN
    };
    
    /**@brief Scan parameters requested for scanning and connection. */
    static ble_gap_scan_params_t const m_scan_params =
    {
        .active   = 0,
        .interval = SCAN_INTERVAL,
        .window   = SCAN_WINDOW,
    
        .timeout           = SCAN_DURATION,
        .scan_phys         = BLE_GAP_PHY_1MBPS,
        .filter_policy     = BLE_GAP_SCAN_FP_ACCEPT_ALL,
    
    };
    
    /**@brief Connection parameters requested for connection. */
    static ble_gap_conn_params_t const m_connection_param =
    {
        (uint16_t)MIN_CONNECTION_INTERVAL,
        (uint16_t)MAX_CONNECTION_INTERVAL,
        (uint16_t)SLAVE_LATENCY,
        (uint16_t)SUPERVISION_TIMEOUT
    };
    
    static void scan_start(void);
    
    /**@brief Function to handle asserts in the SoftDevice.
     *
     * @details This function will be called in case of an assert in the SoftDevice.
     *
     * @warning This handler is an example only and does not fit a final product. You need to analyze
     *          how your product is supposed to react in case of Assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num     Line number of the failing ASSERT call.
     * @param[in] p_file_name  File name of the failing ASSERT call.
     */
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(0xDEADBEEF, line_num, p_file_name);
    }
    
    
    /**@brief Function for handling database discovery events.
     *
     * @details This function is callback function to handle events from the database discovery module.
     *          Depending on the UUIDs that are discovered, this function should forward the events
     *          to their respective services.
     *
     * @param[in] p_event  Pointer to the database discovery event.
     */
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        NRF_LOG_INFO("Discovery handler for conn_handle 0x%x\tp_evt->evt-type : %d", p_evt->conn_handle, p_evt->evt_type);
        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);
    }
    
    
    /**@brief Function for handling Peer Manager events.
     *
     * @param[in] p_evt  Peer Manager event.
     */
    /*
    static void pm_evt_handler(pm_evt_t const * p_evt)
    {
        ret_code_t err_code;
    
        switch (p_evt->evt_id)
        {
            case PM_EVT_BONDED_PEER_CONNECTED:
            {
                NRF_LOG_INFO("Connected to a previously bonded device.");
            } break;
    
            case PM_EVT_CONN_SEC_SUCCEEDED:
            {
                NRF_LOG_INFO("Connection secured: role: %d, conn_handle: 0x%x, procedure: %d.",
                             ble_conn_state_role(p_evt->conn_handle),
                             p_evt->conn_handle,
                             p_evt->params.conn_sec_succeeded.procedure);
            } break;
    
            case PM_EVT_CONN_SEC_FAILED:
            {
    */
                /* Often, when securing fails, it shouldn't be restarted, for security reasons.
                 * Other times, it can be restarted directly.
                 * Sometimes it can be restarted, but only after changing some Security Parameters.
                 * Sometimes, it cannot be restarted until the link is disconnected and reconnected.
                 * Sometimes it is impossible, to secure the link, or the peer device does not support it.
                 * How to handle this error is highly application dependent. */
    /*
            } break;
    
            case PM_EVT_CONN_SEC_CONFIG_REQ:
            {
                // Reject pairing request from an already bonded peer.
                pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
                pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
            } break;
    
            case PM_EVT_STORAGE_FULL:
            {
                // Run garbage collection on the flash.
                err_code = fds_gc();
                if (err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
                {
                    // Retry.
                }
                else
                {
                    APP_ERROR_CHECK(err_code);
                }
            } break;
    
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
            {
                // Bonds are deleted. Start scanning.
                scan_start();
            } break;
    
            case PM_EVT_PEER_DATA_UPDATE_FAILED:
            {
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peer_data_update_failed.error);
            } break;
    
            case PM_EVT_PEER_DELETE_FAILED:
            {
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error);
            } break;
    
            case PM_EVT_PEERS_DELETE_FAILED:
            {
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error);
            } break;
    
            case PM_EVT_ERROR_UNEXPECTED:
            {
                // Assert.
                APP_ERROR_CHECK(p_evt->params.error_unexpected.error);
            } break;
    
            case PM_EVT_CONN_SEC_START:
            case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
            case PM_EVT_PEER_DELETE_SUCCEEDED:
            case PM_EVT_LOCAL_DB_CACHE_APPLIED:
            case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
                // This can happen when the local DB has changed.
            case PM_EVT_SERVICE_CHANGED_IND_SENT:
            case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
            default:
                break;
        }
    }
    */
    
    
    /**@brief Function for handling the advertising report BLE event.
     *
     * @param[in] p_adv_report  Advertising report from the SoftDevice.
     */
    static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
    {
        ret_code_t err_code;
        
        if (ble_advdata_name_find(p_adv_report->data.p_data, p_adv_report->data.len, m_target_periph_RFID_name)&&ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &rfid_uuid))
        {//name found
            if(ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &rfid_uuid))
            {//custom uuid found
                NRF_LOG_INFO("RFID peripheral found");
                err_code = sd_ble_gap_connect(&p_adv_report->peer_addr, &m_scan_params, &m_connection_param,APP_BLE_CONN_CFG_TAG);
                if (err_code != NRF_SUCCESS)
                {
                    NRF_LOG_ERROR("Connection Request Failed, reason %d", err_code);
                }
            }
        }
        else if(ble_advdata_name_find(p_adv_report->data.p_data, p_adv_report->data.len, m_target_IHMI_relay_name)&&ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &relay_uuid))
        {//name found
            if(ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &relay_uuid))
            {//custom uuid found
                NRF_LOG_INFO("IHMI relay found");
                err_code = sd_ble_gap_connect(&p_adv_report->peer_addr, &m_scan_params, &m_connection_param,APP_BLE_CONN_CFG_TAG);
                if (err_code != NRF_SUCCESS)
                {
                    NRF_LOG_ERROR("Connection Request Failed, reason %d", err_code);
                }
            }
        }
        else
        {
            //NRF_LOG_INFO("No connection established, scan starts again");
            err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    
    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code;
    
        // For readability.
        ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    
        switch (p_ble_evt->header.evt_id)
        {
            // Upon connection, check which peripheral has connected, initiate DB
            // discovery, update LEDs status and resume scanning if necessary.
            case BLE_GAP_EVT_CONNECTED:
            {
                NRF_LOG_INFO("\tConnection 0x%x established, starting DB discovery.", p_gap_evt->conn_handle);
    
                APP_ERROR_CHECK_BOOL(p_gap_evt->conn_handle < NRF_SDH_BLE_CENTRAL_LINK_COUNT);
    
                err_code = ble_db_discovery_start(&m_db_disc[p_gap_evt->conn_handle], p_gap_evt->conn_handle);
                APP_ERROR_CHECK(err_code);
                if (err_code != NRF_ERROR_BUSY)
                {
                    APP_ERROR_CHECK(err_code);
                }
    
                // Update LEDs status, and check if we should be looking for more
                // peripherals to connect to.
                bsp_board_led_on(CENTRAL_CONNECTED_LED);
    
                /*//il faut attendre que le service soit découvert avant de relancer le start
                if (ble_conn_state_central_conn_count() == NRF_SDH_BLE_CENTRAL_LINK_COUNT)
                {
                    bsp_board_led_off(CENTRAL_SCANNING_LED);
                }
                else
                {
                    // Resume scanning.
                    bsp_board_led_on(CENTRAL_SCANNING_LED);
                    scan_start();
                }
                */
            } break; // BLE_GAP_EVT_CONNECTED
    
            // Upon disconnection, reset the connection handle of the peer which disconnected, update
            // the LEDs status and start scanning again.
            case BLE_GAP_EVT_DISCONNECTED:
            {
                NRF_LOG_INFO("Central link 0x%x disconnected (reason: 0x%x)",
                             p_gap_evt->conn_handle,
                             p_gap_evt->params.disconnected.reason);
    
                if (ble_conn_state_central_conn_count() == 0)
                {
                    // Turn off connection indication LED
                    bsp_board_led_off(CENTRAL_CONNECTED_LED);
                }
    
                // Start scanning
                scan_start();
    
                // Turn on LED for indicating scanning
                bsp_board_led_on(CENTRAL_SCANNING_LED);
    
            } break;
    
            case BLE_GAP_EVT_ADV_REPORT:
                on_adv_report(&p_gap_evt->params.adv_report);
                break;
    
            case BLE_GAP_EVT_TIMEOUT:
            {
                // We have not specified a timeout for scanning, so only connection attemps can timeout.
                if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
                {
                    NRF_LOG_INFO("Connection request timed out.");
                }
            } break;
    
            case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
            {
                NRF_LOG_INFO("BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST.");
                // Accept parameters requested by peer.
                err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
                                            &p_gap_evt->params.conn_param_update_request.conn_params);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_INFO("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTC_EVT_TIMEOUT:
            {
                // Disconnect on GATT Client timeout event.
                NRF_LOG_INFO("GATT Client Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTS_EVT_TIMEOUT:
            {
                // Disconnect on GATT Server timeout event.
                NRF_LOG_INFO("GATT Server Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
            } break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupts.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    
    /**@brief Function for the Peer Manager initialization.
     */
    /*
    static void peer_manager_init(void)
    {
        ble_gap_sec_params_t sec_param;
        ret_code_t err_code;
    
        err_code = pm_init();
        APP_ERROR_CHECK(err_code);
    
        memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
    
        // Security parameters to be used for all security procedures.
        sec_param.bond           = SEC_PARAM_BOND;
        sec_param.mitm           = SEC_PARAM_MITM;
        sec_param.lesc           = SEC_PARAM_LESC;
        sec_param.keypress       = SEC_PARAM_KEYPRESS;
        sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;
        sec_param.oob            = SEC_PARAM_OOB;
        sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
        sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
        sec_param.kdist_own.enc  = 1;
        sec_param.kdist_own.id   = 1;
        sec_param.kdist_peer.enc = 1;
        sec_param.kdist_peer.id  = 1;
    
        err_code = pm_sec_params_set(&sec_param);
        APP_ERROR_CHECK(err_code);
    
        err_code = pm_register(pm_evt_handler);
        APP_ERROR_CHECK(err_code);
    }
    */
    
    
    /** @brief Clear bonding information from persistent storage
     */
    /*
    static void delete_bonds(void)
    {
        ret_code_t err_code;
    
        NRF_LOG_INFO("Erase bonds!");
    
        err_code = pm_peers_delete();
        APP_ERROR_CHECK(err_code);
    }
    */
    
    
    /**@brief Handles events coming from the RFID central module.
     */
    static void rfid_c_evt_handler(rfid_c_t * p_rfid_c, rfid_c_evt_t * p_rfid_c_evt)
    {
        switch (p_rfid_c_evt->evt_type)
        {
            case RFID_C_EVT_DISCOVERY_COMPLETE:
            {
                ret_code_t err_code;
    
                NRF_LOG_INFO("\t\tRFID SERVICE DISCOVERED on conn_handle 0x%x", p_rfid_c_evt->conn_handle);
                
                err_code = rfid_c_handles_assign( p_rfid_c, p_rfid_c_evt->conn_handle, &p_rfid_c_evt->params.peer_db);
                APP_ERROR_CHECK(err_code);
    
                // Initiate bonding.
                /*
                err_code = pm_conn_secure(p_bas_c_evt->conn_handle, false);
                */
              
                //RFID service discovered. Enable notification of sensors_frame.
                err_code = rfid_c_sensors_frame_notif_and_indic_enable(p_rfid_c);
                APP_ERROR_CHECK(err_code);
    
                ///
                if (ble_conn_state_central_conn_count() == NRF_SDH_BLE_CENTRAL_LINK_COUNT)
                {
                    bsp_board_led_off(CENTRAL_SCANNING_LED);
                }
                else
                {
                    // Resume scanning.
                    bsp_board_led_on(CENTRAL_SCANNING_LED);
                    scan_start();
                }
                ///
            
            } break; // BLE_LBS_C_EVT_DISCOVERY_COMPLETE
    
            case RFID_C_EVT_SENSORS_FRAME_RECEIVED:
            {
                //we have to send sensors_frame to the relay
                //it's here that we put functions to execute in case of receiving notifications, not in
                //rfic_c -> BLE_GATTC-EVT_HVX because it can come from another ble service
                      
            } break; // RFID_C_EVT_SENSORS_FRAME_RECEIVED
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief Handles events coming from the RELAY central module.
     */
    static void relay_c_evt_handler(relay_c_t * p_relay_c, relay_c_evt_t * p_relay_c_evt)
    {
        switch (p_relay_c_evt->evt_type)
        {
            case RELAY_C_EVT_DISCOVERY_COMPLETE:
            {
                ret_code_t err_code;
    
                NRF_LOG_INFO("\t\tRELAY SERVICE DISCOVERED on conn_handle 0x%x", p_relay_c_evt->conn_handle);
    
                err_code = relay_c_handles_assign( p_relay_c, p_relay_c_evt->conn_handle, &p_relay_c_evt->params.peer_db);
                APP_ERROR_CHECK(err_code);
    
                // Initiate bonding.
                /*
                err_code = pm_conn_secure(p_bas_c_evt->conn_handle, false);
                */
                
                //RELAY service discovered. Enable notification of blacklist.
                err_code = relay_c_blacklist_notif_and_indic_enable(p_relay_c);
                APP_ERROR_CHECK(err_code);
    
                ///
                if (ble_conn_state_central_conn_count() == NRF_SDH_BLE_CENTRAL_LINK_COUNT)
                {
                    bsp_board_led_off(CENTRAL_SCANNING_LED);
                }
                else
                {
                    // Resume scanning.
                    bsp_board_led_on(CENTRAL_SCANNING_LED);
                    scan_start();
                }
                ///
    
            } break; // RELAY_C_EVT_DISCOVERY_COMPLETE
    
            case RELAY_C_EVT_BLACKLIST_RECEIVED:
            {
                //we have to save the blacklist
                      
            } break; // RELAY_C_EVT_BLACKLIST_RECEIVED
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief rfid client initialization.
     */
    static void main_rfid_c_init(void)
    {
        ret_code_t       err_code;
        rfid_c_init_t rfid_c_init_obj;
    
        rfid_c_init_obj.evt_handler = rfid_c_evt_handler;
    
        for (uint32_t i = 0; i < RFID_COUNT; i++)
        {
          err_code = rfid_c_init(&m_rfid_c[i], &rfid_c_init_obj);
          APP_ERROR_CHECK(err_code);
        }
    }
    
    
    /**@brief relay client initialization.
     */
    static void main_relay_c_init(void)
    {
        ret_code_t       err_code;
        relay_c_init_t relay_c_init_obj;
    
        relay_c_init_obj.evt_handler = relay_c_evt_handler;
    
        for (uint32_t i = 0; i < RELAY_COUNT; i++)
        {
            err_code = relay_c_init(&m_relay_c[i], &relay_c_init_obj);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    
    /** @brief Database discovery initialization.
     */
    static void db_discovery_init(void)
    {
        ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function to start scanning. */
    static void scan_start(void)
    {
        ret_code_t ret;
    
        (void) sd_ble_gap_scan_stop();
    
        NRF_LOG_INFO("Scanning for %s and %s peripherals.", (uint32_t)m_target_periph_RFID_name,(uint32_t)m_target_IHMI_relay_name);
        ret = sd_ble_gap_scan_start(&m_scan_params, &m_scan_buffer);
        APP_ERROR_CHECK(ret);
        // Turn on the LED to signal scanning.
        bsp_board_led_on(CENTRAL_SCANNING_LED);
    }
    
    
    /**@brief Function for initializing power management.
     */
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the idle state (main loop).
     *
     * @details Handle any pending log operation(s), then sleep until the next event occurs.
     */
    static void idle_state_handle(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    /**@brief Function for handling events from the button handler module.
     *
     * @param[in] pin_no        The pin that the event applies to.
     * @param[in] button_action The button action (press/release).
     */
    static void button_event_handler(uint8_t pin_no, uint8_t button_action)
    {
        ret_code_t err_code;
    
        switch (pin_no)
        {
            case MEASURE_REQUEST_1_BUTTON:
                cptButtonEvent++;
                if(cptButtonEvent==2)
                {
                  uint8_t measure_request[]={0x1,0x1};
                  for (uint32_t i = 0; i< NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
                  {
                      //NRF_LOG_INFO("m_rfid_c[%d].conn_handle : 0x%x",i,m_rfid_c[i].conn_handle);
                      if(m_rfid_c[i].conn_handle != BLE_CONN_HANDLE_INVALID)
                      {
                          write_measure_request(&m_rfid_c[i], measure_request);
                      }
                  }
                  cptButtonEvent=0;
                }
                break;
    
            case MEASURE_REQUEST_2_BUTTON:
                cptButtonEvent++;
                if(cptButtonEvent==2)
                {
                  uint8_t measure_request[]={0x1,0x2};
                  for (uint32_t i = 0; i< NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
                  {
                      if(m_rfid_c[i].conn_handle != BLE_CONN_HANDLE_INVALID)
                      {
                          write_measure_request(&m_rfid_c[i], measure_request);
                      }
                  }
                  cptButtonEvent=0;
                }
                break;
    
            case MEASURE_REQUEST_3_BUTTON:
                cptButtonEvent++;
                if(cptButtonEvent==2)
                {
                  uint8_t measure_request[]={0x1,0x3};
                  for (uint32_t i = 0; i< NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
                  {
                      if(m_rfid_c[i].conn_handle != BLE_CONN_HANDLE_INVALID)
                      {
                          write_measure_request(&m_rfid_c[i], measure_request);
                      }
                  }
                  cptButtonEvent=0;
                }
                break;
    
            default:
                APP_ERROR_HANDLER(pin_no);
                break;
        }
    }
    
    
    /**@brief Function for initializing the button handler module.
     */
    static void buttons_init(void)
    {
        ret_code_t err_code;
    
        //The array must be static because a pointer to it will be saved in the button handler module.
        static app_button_cfg_t buttons[] =
        {
            {MEASURE_REQUEST_1_BUTTON, false, BUTTON_PULL, button_event_handler},
            {MEASURE_REQUEST_2_BUTTON, false, BUTTON_PULL, button_event_handler},
            {MEASURE_REQUEST_3_BUTTON, false, BUTTON_PULL, button_event_handler}
        };
    
        err_code = app_button_init(buttons, ARRAY_SIZE(buttons),
                                   BUTTON_DETECTION_DELAY);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for the LEDs initialization.
     *
     * @details Initializes all LEDs used by the application.
     */
    static void leds_init(void)
    {
        bsp_board_init(BSP_INIT_LEDS);
    }
    
    
    /** @brief Function for initializing the log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /** @brief Function for initializing the timer.
     */
    static void timer_init(void)
    {
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the GATT module.
     */
    static void gatt_init(void)
    {
        ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for starting a scan, or instead trigger it from peer manager (after
     *        deleting bonds).
     *
     * @param[in] p_erase_bonds Pointer to a bool to determine if bonds will be deleted before scanning.
     */
    /*
    void scanning_start(bool * p_erase_bonds)
    {
        // Start scanning for peripherals and initiate connection
        // with devices that advertise GATT Service UUID.
        if (*p_erase_bonds == true)
        {
            // Scan is started by the PM_EVT_PEERS_DELETE_SUCCEEDED event.
            delete_bonds();
        }
        else
        {
            scan_start();
        }
    }
    */
    
    
    int main(void)
    {
        ret_code_t err_code;
        bool erase_bonds;
    
        // Initialize.
        log_init();
        NRF_LOG_INFO("------------------------------------------------------------------------------------------");
        NRF_LOG_INFO("-------------------------------------Concentrator-----------------------------------------");
        NRF_LOG_INFO("------------------------------------------------------------------------------------------");
    
        NRF_LOG_INFO("Event types for the discovery :")
        NRF_LOG_INFO("\t%d : BLE_DB_DISCOVERY_COMPLETE",BLE_DB_DISCOVERY_COMPLETE);             
        NRF_LOG_INFO("\t%d : BLE_DB_DISCOVERY_ERROR",BLE_DB_DISCOVERY_ERROR);                   
        NRF_LOG_INFO("\t%d : BLE_DB_DISCOVERY_SRV_NOT_FOUND",BLE_DB_DISCOVERY_SRV_NOT_FOUND);   
        NRF_LOG_INFO("\t%d : BLE_DB_DISCOVERY_AVAILABLE",BLE_DB_DISCOVERY_AVAILABLE);           
    
        timer_init();
        buttons_init();
        leds_init();
        power_management_init();
        ble_stack_init();
        gatt_init();
        db_discovery_init();
        main_rfid_c_init();
        main_relay_c_init();
        ble_conn_state_init();
    
        err_code = app_button_enable();
        APP_ERROR_CHECK(err_code);
    
        //scanning_start(&erase_bonds);
        scan_start();
    
        // Enter main loop.
        for (;;)
        {
           idle_state_handle();
        }
    }

    How can I send you my whole project?

  • Hi,

    Sorry for the late answer. You can create a private ticket and upload your project there.

    Edit: I am afraid I cannot really see what you are doing wrong based on main.c. Have you tried to compare your solution against the nRF5_SDK_15.3.0_59ac345\examples\ble_central_and_peripheral\experimental\ble_app_hrs_rscs_relay example? this example is a client to both HRS and RSCS so it should handle discovery in the same way you application has to do it.

  • Hi, I just created a private ticket with a link to download the whole project.

    I'm going to look at ble_app_hrs_rscs_relay, thank you for the advice.

  • I looked at the ble_app_hrs_rscs_relay exemple but for SDK 15.0 beacause it is the SDK I was using for my project. The service discovery look similar to my projects.

    I used this project with the ble_app_hrs and ble_app_rscs examples to test the following scenario : 

    Peripherals           Relay (central)
    +----------+            +-------------+
    | Heart    |              | Heart      | 
    | Rate     |   ----->   | Rate       |
    | Sensor |              | Collector | 
    +----------+            +-------------+ 
                                 | Running  |
    +-----------+            | Speed     |
    | Running|   ------>| Collector | 
    | Speed   |            +-------------+
    | Sensor  |
    +-----------+

    I found that there are some case with this example where it don't work neither. It is less frequent but sometimes the relay does not discover the HRS or the RSCS service.

    For example, in this case the relay discovered only the HRS service : 

    Edit : I tried with the example ble_app_hrs_rcsc_relay of the SDK 15.3 too and I found the same problem. Sometimes one service is not discovered during the service discovery, did you found this too? Do you have other suggestions? Did you saw my private ticket?

Related