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

 
  • Hi,
    But it always bond with the filter by name and it is not auto-populating the list.
    The first time, I activate the filter by name and they bond. Since then I activate the whitelist.
    But I see that it does the scan with
    addr_cnt=0 in on_whitelist_req().
    The peripheral is also designed here with a Nordic chip.
    I'm doing the same as ble_app_gatts application and I understand that there the list is automatically filled, right?

    Could this error be related to some peripheral parameter?

    Do I have to do anything else to fill the list?
    How can I see if it has tried to save the MAC in the flash?

    Thanks in advance.

  • I do not see the code that actually populates the whitelist in the snippet in your original question. You should use the same approach as ble_app_hrs_c, where the peer manager is used to populate the whitelist:

    static void on_whitelist_req(void)
    {
        ret_code_t err_code;
    
        // Whitelist buffers.
        ble_gap_addr_t whitelist_addrs[8];
        ble_gap_irk_t  whitelist_irks[8];
    
        memset(whitelist_addrs, 0x00, sizeof(whitelist_addrs));
        memset(whitelist_irks,  0x00, sizeof(whitelist_irks));
    
        uint32_t addr_cnt = (sizeof(whitelist_addrs) / sizeof(ble_gap_addr_t));
        uint32_t irk_cnt  = (sizeof(whitelist_irks)  / sizeof(ble_gap_irk_t));
    
        // Reload the whitelist and whitelist all peers.
        whitelist_load();
    
        // Get the whitelist previously set using pm_whitelist_set().
        err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt,
                                    whitelist_irks,  &irk_cnt);
    
        if (((addr_cnt == 0) && (irk_cnt == 0)) ||
            (m_whitelist_disabled))
        {
            // Don't use whitelist.
            err_code = nrf_ble_scan_params_set(&m_scan, NULL);
            APP_ERROR_CHECK(err_code);
        }
    }

    Is that how you do it? If now, please show your approach.

  • Hi,

    I am using the same routines of peer manager as in ble_app_hrs_c.
    The only differences I can see are:

    1) I am not using LESC
    2) The initial filter is by name
    3) I use m_whitelist_enabled instead of m_whitelist_disabled



    /**@brief Function for setting filtered whitelist.
     * @param[in] skip  Filter passed to @ref pm_peer_id_list.
     */
    static void whitelist_set (pm_peer_id_list_skip_t skip)
    {
        pm_peer_id_t peer_ids[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
        uint32_t     peer_id_count = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
        ret_code_t err_code = pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_INFO("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
                       peer_id_count + 1,
                       BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
    
        err_code = pm_whitelist_set(peer_ids, peer_id_count);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@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_disconnect_on_sec_failure(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_list_get (pm_peer_id_t * p_peers, uint32_t * p_size)
    {
        pm_peer_id_t peer_id;
        uint32_t     peers_to_copy;
    
        peers_to_copy = (*p_size < BLE_GAP_WHITELIST_ADDR_MAX_COUNT) ?
                         *p_size : BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
        peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
        *p_size = 0;
    
        while ((peer_id != PM_PEER_ID_INVALID) && (peers_to_copy--))  {
            p_peers[(*p_size)++] = peer_id;
            peer_id = pm_next_peer_id_get(peer_id);
        }
    }
    
    static void whitelist_load (void)
    {
        ret_code_t   ret;
        pm_peer_id_t peers[8];
        uint32_t     peer_cnt;
    
        memset(peers, PM_PEER_ID_INVALID, sizeof(peers));
        peer_cnt = (sizeof(peers) / sizeof(pm_peer_id_t));
    
        // Load all peers from flash and whitelist them.
        peer_list_get(peers, &peer_cnt);
    
        ret = pm_whitelist_set(peers, peer_cnt);
        APP_ERROR_CHECK(ret);
    
        // Setup the device identies list.
        // Some SoftDevices do not support this feature.
        ret = pm_device_identities_list_set(peers, peer_cnt);
        if (ret != NRF_ERROR_NOT_SUPPORTED) {
            APP_ERROR_CHECK(ret);
        }
    }
    
    static void on_whitelist_req (void)
    {
        ret_code_t err_code;
    
        // Whitelist buffers.
        ble_gap_addr_t whitelist_addrs[8];
        ble_gap_irk_t  whitelist_irks[8];
    
        memset(whitelist_addrs, 0x00, sizeof(whitelist_addrs));
        memset(whitelist_irks,  0x00, sizeof(whitelist_irks));
    
        uint32_t addr_cnt = (sizeof(whitelist_addrs) / sizeof(ble_gap_addr_t));
        uint32_t irk_cnt  = (sizeof(whitelist_irks)  / sizeof(ble_gap_irk_t));
    
        // Reload the whitelist and whitelist all peers.
        whitelist_load();
    
        // Get the whitelist previously set using pm_whitelist_set() in whitelist_load()
        err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt,
                                    whitelist_irks,  &irk_cnt);
    
        if (((addr_cnt == 0) && (irk_cnt == 0)) || (m_whitelist_enabled == false)) {
            // Don't use whitelist.
            err_code = nrf_ble_scan_params_set(&m_scan, NULL);
            APP_ERROR_CHECK(err_code);
            NRF_LOG_INFO("Starting scan without whitelist %d %d %d", addr_cnt, irk_cnt, m_whitelist_enabled ? 1 : 0);
        } else
            NRF_LOG_INFO("Starting scan with whitelist");
    }
    
    
    /**@brief Function for the Peer Manager initialization.
        (See "Software Development Kit > nRF5 SDK v17.0.2 > Libraries > BLE libraries > Peer Manager") 
     */
    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");
    }
    
    
    
  • I see, then this looks odd. Can you upload a complete project that runs on a DK so that I can test on my side?

Related