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

THE EVENT NRF_BLE_SCAN_EVT_WHITELIST_REQUEST DOES NOT OCCUR

Good morning,

I am developing an application that needs to match a central with a specific peripheral.
For this, the first time they connect, the address must be saved and from now on it will only be possible to connect with that peripheral.
I have preferred to use the whitelist for possible future changes.
After using the treatment that the application "ble_app_hrs_c" does with the whitelist, I have not been able to make my application work.
Using a filter by name and without the whitelist, it does work. The problem seems to be that there is no way to get the event "NRF_BLE_SCAN_EVT_WHITELIST_REQUEST" to occur, since the message "Whitelist Request." does not appear.
However in the application "ble_app_hrs_c", it does.

I've been trying for many hours to make it work but it has been impossible.
I enclose part of the application related to the aforementioned.
TaskMain() is where scan_start() and idle_state_handle() are called depending on certain conditions.
I also send a screenshot of the debugger.
I'm using:

- nRF5 SDK v17.0.2
- nRF52832
- S132 SoftDevice

Please, can you help me with this problem?
Thanks in advance.



#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 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. */

NRF_BLE_SCAN_DEF(m_scan);                                       /**< Scanning module instance. */
BLE_LBS_C_DEF(m_ble_lbs_c);                                     /**< Main structure used by the LBS client module. */
NRF_BLE_GATT_DEF(m_gatt);                                       /**< GATT module instance. */
BLE_DB_DISCOVERY_DEF(m_db_disc);                                /**< DB discovery module instance. */
NRF_BLE_GQ_DEF(m_ble_gatt_queue,                                /**< BLE GATT Queue instance. */
               NRF_SDH_BLE_CENTRAL_LINK_COUNT,
               NRF_BLE_GQ_QUEUE_SIZE);

static bool     m_whitelist_enabled;                            /**< False if whitelist has been temporarily disabled. */
static bool     m_memory_access_in_progress;                    /**< Flag to keep track of ongoing operations on persistent memory. */
static INT8U    statusBLE = INIT;
static INT8U    taskMotor = 0;
static INT8U    input = 0xff;
static INT16U   timeFlush = 0;
static INT16U   degreeFlush = 0;

// POSIBILIDADES DE SCANNIG
static char const m_target_periph_name[] = DEVICE_NAME;         /**< Name of the device we try to connect to. This name is searched in the scan report data*/
//static char const m_target_periph_name[] = "";		/**< If you want to connect to a peripheral using a given advertising name, type its name here. */

static bool is_connect_per_addr = false;			/**< If you want to connect to a peripheral with a given address, set this to true and put the correct address in the variable below. */
static ble_gap_addr_t const m_target_periph_addr =		/**< ** IMPORTANT ** modify NRF_BLE_SCAN_ADDRESS_CNT = 1 (as example) in sdk_config.h. ** IMPORTANT ** Set it to 0 if don't use it*/
{
    /* Possible values for addr_type:
       BLE_GAP_ADDR_TYPE_PUBLIC,
       BLE_GAP_ADDR_TYPE_RANDOM_STATIC,
       BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE,
       BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */
    .addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC,
    //.addr      = {0x8D, 0xFE, 0x23, 0x86, 0x77, 0xD9}
    //.addr      = {0xF1, 0x09, 0x50, 0x03, 0xEA, 0xDE}
    .addr      = {0x64, 0x97, 0xDC, 0x18, 0x75, 0xD7}
};

static bool is_connect_per_uuid = false;			/**< If you want to connect to a peripheral with UUID, set this to true and put the correct UUID data in the variable below. */
#define TARGET_UUID         BLE_UUID_HEART_RATE_SERVICE         /**< Target device uuid that application is looking for. */
ble_uuid_t uuid =
{ 
    .uuid = TARGET_UUID,
    /* Possible values for Types of UUID:
       BLE_UUID_TYPE_UNKNOWN,	    Invalid UUID type
       BLE_UUID_TYPE_BLE,	    Bluetooth SIG UUID (16-bit)
       BLE_UUID_TYPE_VENDOR_BEGIN   Vendor UUID types start at this index (128-bit)*/
    .type = BLE_UUID_TYPE_BLE,
};


// Function to start scanning.
static void scan_start (void)
{
    ret_code_t err_code;

    if (nrf_fstorage_is_busy(NULL)) {
        m_memory_access_in_progress = true;
        return;
    }

    NRF_LOG_INFO("Starting scan.");

    err_code = nrf_ble_scan_start(&m_scan);         // A partir de aqui se producira un NRF_BLE_SCAN_EVT_WHITELIST_REQUEST
    APP_ERROR_CHECK(err_code);

    statusBLE = SCANNING;
}

/** @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 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 erase_bonds)
{
    // Start scanning for peripherals and initiate connection
    // with devices that advertise GATT Service UUID.
    if (erase_bonds == true) {
        // Scan is started by the PM_EVT_PEERS_DELETE_SUCCEEDED event.
        delete_bonds();
    } else {
        scan_start();
    }
}


/**@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)
{
    pm_handler_on_pm_evt(p_evt);
    pm_handler_flash_clean(p_evt);

    NRF_LOG_INFO("Peer event");
    switch (p_evt->evt_id) {
        case PM_EVT_CONN_SEC_SUCCEEDED:
            //m_peer_id = p_evt->peer_id;
            break;
        case PM_EVT_PEERS_DELETE_SUCCEEDED:
            // Bonds are deleted. Start scanning.
            NRF_LOG_INFO("Peers Deleted Succeeded");
            scan_start();
            break;
 /*       case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
            if (p_evt->params.peer_data_update_succeeded.flash_changed
                 && (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_BONDING))
            {
                NRF_LOG_INFO("New Bond, add the peer to the whitelist if possible");
                // Note: You should check on what kind of white list policy your application should use.

                whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
            }
            break;
*/
        default:
            break;
    }
}


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);

    NRF_LOG_INFO("Peer Manager Init");
}


// Function for handling Scaning events.
// param[in]   p_scan_evt   Scanning event.
static void scan_evt_handler (scan_evt_t const * p_scan_evt)
{
    ret_code_t err_code;

    NRF_LOG_INFO("Scan event");
    switch(p_scan_evt->scan_evt_id) {
        case NRF_BLE_SCAN_EVT_CONNECTING_ERROR:
            NRF_LOG_INFO("Connecting Error");
            err_code = p_scan_evt->params.connecting_err.err_code;
            APP_ERROR_CHECK(err_code);
            break;
        case NRF_BLE_SCAN_EVT_WHITELIST_REQUEST:
            NRF_LOG_INFO("Whitelist Request.");
            on_whitelist_req();
            m_whitelist_enabled = true;
            break;
         case NRF_BLE_SCAN_EVT_WHITELIST_ADV_REPORT:
            NRF_LOG_INFO("Whitelist Adv Report.");
            //sd_ble_gap_connect(....);             // No porque connect_if_match = true. Lo hace automaticamente
            break;
        case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
            NRF_LOG_INFO("Scan timed out.");
            scan_start();
            break;
        case NRF_BLE_SCAN_EVT_FILTER_MATCH:
            break;
        default:
            break;
    }
}


// Function to set scanning parameters
static void scan_init (void)
{
    ret_code_t		    err_code;
    nrf_ble_scan_init_t	    init_scan;
    ble_gap_scan_params_t   * p_scan_param; // BLE GAP scan parameters required to initialize the module. Can be initialized as NULL. 
					    // If NULL, the parameters required to initialize the module are loaded from the static configuration
    // Setting parameters for scanning.
    p_scan_param->active	= 1;
    p_scan_param->interval	= SCAN_INTERVAL;    //default = NRF_BLE_SCAN_SCAN_INTERVAL;
    p_scan_param->window	= SCAN_WINDOW;	    //default = NRF_BLE_SCAN_SCAN_WINDOW;
    p_scan_param->filter_policy = BLE_GAP_SCAN_FP_WHITELIST; 
    p_scan_param->timeout	= 3000;                 //SCAN_DURATION;    //default = NRF_BLE_SCAN_SCAN_DURATION;
    p_scan_param->scan_phys	= BLE_GAP_PHY_1MBPS;

    // Save memory for scanning parameters
    memset(&init_scan, 0, sizeof(init_scan));

    init_scan.connect_if_match	= true;             // Conecta automaticamente si filter o whitelist coinciden
    init_scan.conn_cfg_tag	= APP_BLE_CONN_CFG_TAG;
    init_scan.p_scan_param	= p_scan_param;

    //m_scan.scan_params.filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL;
    //m_scan.scan_params.active = false;

    // Setting other parameters for scanning.
    err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
    APP_ERROR_CHECK(err_code);

    if (is_connect_per_uuid) {
        err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &uuid);
        if (err_code != NRF_SUCCESS)
            NRF_LOG_INFO("Scan Filter Set Error");
        APP_ERROR_CHECK(err_code);
    }

    if (strlen(m_target_periph_name) != 0) {
        err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_target_periph_name);
        APP_ERROR_CHECK(err_code);
    }

    if (is_connect_per_addr) {
       err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_ADDR_FILTER, m_target_periph_addr.addr);
       APP_ERROR_CHECK(err_code);
    }

    // Setting filters for scanning by name and other.
    err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_ALL_FILTER, false);
    APP_ERROR_CHECK(err_code);
}

/****************************************************************************************
*    MAIN FUNCTION
*****************************************************************************************/
int main (void)
{
    INT32U err_code;

    // Initialize.
    log_init();

    initDrivers();

    gpio_init();
    power_management_init();
    ble_stack_init();

    gatt_init();
    peer_manager_init();
    db_discovery_init();
    lbs_c_init();

    scan_init();                 // Scan-Init 

    // Start execution.
    NRF_LOG_INFO("CentralMotor started.");

    // Enter main loop.
    for (;;) {
        taskMain();
    }
}

 
Parents
  • Hi,

    I notice this part of your code especially:

        ble_gap_scan_params_t   * p_scan_param; // BLE GAP scan parameters required to initialize the module. Can be initialized as NULL. 
    					    // If NULL, the parameters required to initialize the module are loaded from the static configuration
        // Setting parameters for scanning.
        p_scan_param->active	= 1;
        p_scan_param->interval	= SCAN_INTERVAL;    //default = NRF_BLE_SCAN_SCAN_INTERVAL;
        ...

    This is certainly a problem your p_scan_param pointer is not initialized, so it will point to random memory and you use it. So basically anything could happen. This needs to be fixed so that you write to an actualy struct and then point to that struct in init_scan.p_scan_param. It could be as simple as this instead:

    static void scan_init (void)
    {
        ret_code_t		    err_code;
        nrf_ble_scan_init_t	    init_scan;
        static ble_gap_scan_params_t   scan_param = {}; // BLE GAP scan parameters required to initialize the module. Can be initialized as NULL. 
    					    // If NULL, the parameters required to initialize the module are loaded from the static configuration
        // Setting parameters for scanning.
        scan_param.active	= 1;
        scan_param.interval	= SCAN_INTERVAL;    //default = NRF_BLE_SCAN_SCAN_INTERVAL;
        scan_param.window	= SCAN_WINDOW;	    //default = NRF_BLE_SCAN_SCAN_WINDOW;
        scan_param.filter_policy = BLE_GAP_SCAN_FP_WHITELIST; 
        scan_param.timeout	= 3000;                 //SCAN_DURATION;    //default = NRF_BLE_SCAN_SCAN_DURATION;
        scan_param.scan_phys	= BLE_GAP_PHY_1MBPS;
    
        // Save memory for scanning parameters
        memset(&init_scan, 0, sizeof(init_scan));
    
        init_scan.connect_if_match	= true;             // Conecta automaticamente si filter o whitelist coinciden
        init_scan.conn_cfg_tag	= APP_BLE_CONN_CFG_TAG;
        init_scan.p_scan_param	= &scan_param;
    ...

  • Thanks. The event problem has been resolved.
    But the central doesn't work the way I would like it to.
    I would like the central to start up for the first time, accept the first device address received filtered by a specific name.
    From then on, just use the whitelist that will carry only the address of that first device.

    Now it is detecting all devices that have the given name and I only want the first one that it detected when booting the first time
    I can't see in the program why it doesn't work like that.
    Please, can you help me?

    Thanks in advance
Reply
  • Thanks. The event problem has been resolved.
    But the central doesn't work the way I would like it to.
    I would like the central to start up for the first time, accept the first device address received filtered by a specific name.
    From then on, just use the whitelist that will carry only the address of that first device.

    Now it is detecting all devices that have the given name and I only want the first one that it detected when booting the first time
    I can't see in the program why it doesn't work like that.
    Please, can you help me?

    Thanks in advance
Children
  • Hi,

    I do not see enough of your code to say exactly what the problem is. How do you populate the whitelist? Typically you would populate it with the address of existing peers, as is sown in for instance the ble_app_gatts example (examples\ble_central\ble_app_gatts\main.c). Is that how you do it?

  • Hi,
    Yes. It is the same as the ble_app_gatts application. I made some modifications to make it identical. The only difference is that the filter used initially is only made by name. I have observed that in the routine on_whitelist_req() it always comes out with addr_cnt=0 and irk_cnt=0. It seems as if the addresses are not stored in memory. I understand that once peer_manager is configured, the API automatically takes care of saving the connected addresses in flash memory, right?
  • Hi,

    Yes, the SDK examples will populate the whitelist using the peer manager, which handled pairing/bonding. So unless bonded, the list will be empty. You can use your own approach without it where you populate the list yourself based on the mac address of a peer you have previously been connected to if you want to do that without bonding. This will not work well with devices that use privacy, including any modern mobile phone. In that case you need to whitelist using the IRK, which you get when pairing/bonding.

Related