BLE Scanning with Whitelist

This blog is to describe how to use the whitelist in order to improve the connection successful rate between central and peripheral at nRF52 series.

The topic is covered as below:

  • Describe about the nrf_ble_scan module
  • Describe how to add the manufacturer specific filter inside the nrf_ble_scan module
  • How whitelist works with nrf_ble_scan module

SCANNING MODULE (nrf_ble_scan)

The scanning module was introduced since Nordic NRF5 SDK 15.2 or later.

The Scanning Module handles the BLE scanning for your application. You can use it to find an advertising device and establish a connection with it. The scan can be narrowed down to the device of a specific type by using filters and the whitelist. The module can be used for most of the SDK BLE examples.

https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.3.0/lib_ble_scan.html

The Scanning Module can work in one of the following modes:

  • simple mode without using filters and the whitelist, or
  • advanced mode that allows you to use advanced filters or the whitelist.

The module can automatically establish a connection after a filter match or successful identification of a device from the whitelist.

Usage

ActionDescription
InitializationThe module must be initialized with nrf_ble_scan_init that can be called without event handler and initialization structure. When initialization structure is passed as NULL, the default static configuration is used. This configuration is also used when you use an initialization structure with NULL pointers to scan parameters and connection parameters. Event handler also can be initialized as NULL, but then the application does not get events that inform about a filter or whitelist match, or about a connection error during the automatic connection.
Starting scanningWhen initialization completes, you can start scanning with nrf_ble_scan_start. In the simplest mode when you do not using event handler, the connection can be established when BLE_GAP_EVT_ADV_REPORT occurs.
Changing parametersCall the function nrf_ble_scan_params_set to change parameters.
Stopping scanningCall the function nrf_ble_scan_stop to stop scanning.
Resuming scanningThe Scanning Module resumes scanning after receiving advertising reports. Scanning stops if the module established the connection automatically, or if the application calls nrf_ble_scan_stop or sd_ble_gap_connect.

Initialization

The Scanning Module can be initialized with a simple or an advanced method. Both correspond to some extent to the respective Scanning Module modes.

Simple initialization

You can use the simple initialization with the default scanning parameters when you want the Scanning Module to work in the simple mode without filtering and the whitelist.

ret_code_t err_code;
err_code = nrf_ble_scan_init(&m_scan, NULL, NULL);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_scan_start(&m_scan);
APP_ERROR_CHECK(err_code);

Advanced initialization

You can use the advanced initialization when you want the Scanning Module to work in either the simple mode without filtering and the whitelist or the advanced mode that uses advanced filters. You can configure this initialization to your needs, for example by disabling the whitelist and enabling the automatic connection establishing.

/**< Scan parameters requested for scanning and connection. */
static ble_gap_scan_params_t const m_scan_param =
{
    .active        = 0x01,
    .interval      = NRF_BLE_SCAN_SCAN_INTERVAL,
    .window        = NRF_BLE_SCAN_SCAN_WINDOW,
    .filter_policy = BLE_GAP_SCAN_FP_WHITELIST,
    .timeout       = SCAN_DURATION_WHITELIST,
    .scan_phys     = BLE_GAP_PHY_1MBPS,
    .extended      = true,
};
    ret_code_t err_code;
    nrf_ble_scan_init_t scan_init;
    memset(&scan_init, 0, sizeof(scan_init));
    scan_init.p_scan_param     = &m_scan_param;
    scan_init.connect_if_match = true;
    scan_init.conn_cfg_tag     = APP_BLE_CONN_CFG_TAG;
    err_code = nrf_ble_scan_init(&m_scan, &scan_init, scan_evt_handler);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_ble_scan_start(&m_scan);
    APP_ERROR_CHECK(err_code);

If you want to use filters or the whitelist, you can configure the module during initialization to connect automatically after a filter match or successful identification of a device from the whitelist.

When setting connection-specific configurations with sd_ble_cfg_set, you must create a tag for each configuration. If your application uses the Scanning Module with automatic connection, this tag must be provided when calling sd_ble_gap_scan_start() and sd_ble_gap_connect().

Whitelist

The whitelist stores information about all the device connections and bonding. If you enable the whitelist, the application receives advertising packets only from the devices that are on the whitelist.WarningIf you use the whitelist, you must pass the event handler during the module initialization. The initial scanning with whitelist generates NRF_BLE_SCAN_EVT_WHITELIST_REQUEST to the main application. The application must react to this event by either setting up the whitelist or switching off the whitelist scan. Otherwise, an error is reported when the scan starts.

You can use nrf_ble_scan_params_set to enable or disable the whitelist scan both during and after the initialization of the module.NoteWhen you use nrf_ble_scan_params_set during the ongoing scan, scanning is stopped. To resume scanning, use nrf_ble_scan_start.

Finding an advertising package that belongs to a whitelisted device generates the NRF_BLE_SCAN_EVT_WHITELIST_ADV_REPORT event.

[ Note ] When using the whitelist, filters are inactive.

Filters

The module can set scanning filters of different type and mode. When a filter is matched, it generates NRF_BLE_SCAN_EVT_FILTER_MATCH to the main application. If the filter matching is enabled and no filter is matched, NRF_BLE_SCAN_EVT_NOT_FOUND is generated.

Filter types

The following table shows the available filter types.

Filter typeDetails
NameFilter set to the target name.
The maximum length of the name corresponds to NRF_BLE_SCAN_NAME_MAX_LEN.
The maximum number of filters of this type corresponds to NRF_BLE_SCAN_NAME_CNT.
Short nameFilter set to the short target name.
The maximum length of the name corresponds to NRF_BLE_SCAN_SHORT_NAME_MAX_LEN.
The maximum number of filters of this type corresponds to NRF_BLE_SCAN_SHORT_NAME_CNT.
AddressFilter set to the target address.
The maximum number of filters of this type corresponds to NRF_BLE_SCAN_ADDRESS_CNT.
UUIDFilter set to the target UUID.
The maximum number of filters of this type corresponds to NRF_BLE_SCAN_UUID_CNT.
AppearanceFilter set to the target appearance.
The maximum number of filters of this type corresponds to NRF_BLE_SCAN_APPEARANCE_CNT.

Filter usage

You can use filters after module initialization. You can enable filters with nrf_ble_scan_filters_enable. Filters can be activated for one filter type, or for a combination of several filter types.

// Enable the filter on the address in the normal mode.
err_code = nrf_ble_scan_filters_enable(&m_scan,
                                       NRF_BLE_SCAN_ADDR_FILTER,
                                       false);
APP_ERROR_CHECK(err_code);
// Enable the filter on the name and UUID in the normal mode.
err_code = nrf_ble_scan_filters_enable(&m_scan,
                                       NRF_BLE_SCAN_NAME_FILTER | NRF_BLE_SCAN_UUID_FILTER,
                                       false);
APP_ERROR_CHECK(err_code);
APP_ERROR_CHECK(err_code);
// Enable the multifilter mode.
err_code = nrf_ble_scan_filters_enable(&m_scan,
                                       NRF_BLE_SCAN_ALL_FILTER,
                                       true);
APP_ERROR_CHECK(err_code);

The Scanning Module handles the BLE scanning for your application. The module offers several criteria for filtering the devices available for connection, and it can also work in the simple mode without using the filtering. If an event handler is provided, your main application can react to a filter match or to the need of setting the whitelist. The module can also be configured to automatically connect after it matches a filter or a device from the whitelist.

The Scanning Module also supports applications with a multicentral link.

https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.3.0/group__nrf__ble__scan.html

Manufacturer Specific Filter

  • Add the extra criteria filter (manufacturer specific data) and then check for particular pattern inside the manufacturer specific payload.
Manufacturer Specific Data Filter set to the target manufacturer specific data payload
The maximum number of filters of this type corresponds
to NRF_BLE_SCAN_MANUFACTURER_CNT.

How to add manufacturer specific data filter inside the nrf_ble_scan module

nrf_ble_whitelist Module

  • Add the nrf_ble_whitelist module.
  • This module only works with static random address or public address.
  • Maximum number of Whitelist Address is BLE_GAP_WHITELIST_ADDR_MAX_COUNT= 8.

API

ret_code_t nrf_ble_whitelist_add(ble_gap_addr_t *addr, uint8_t * count);

ret_code_t nrf_ble_whitelist_enable(void);

ret_code_t nrf_ble_whitelist_reset(void);

bool nrf_ble_whitelist_is_running(void);

uint8_t nrf_ble_whitelist_cnt(void);

Example how to add the whitelist


static void set_test_whitelist(void)
{
        ble_gap_addr_t whitelist_addrs;
        uint8_t whitelist_number = 0;
        ret_code_t err_code;

        /* Gateway 1 */
        whitelist_addrs.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
        whitelist_addrs.addr_id_peer = 0x00;
        whitelist_addrs.addr[5]   = 0xcc;
        whitelist_addrs.addr[4]   = 0xcc;
        whitelist_addrs.addr[3]   = 0xcc;
        whitelist_addrs.addr[2]   = 0xcc;
        whitelist_addrs.addr[1]   = 0xcc;
        whitelist_addrs.addr[0]   = 0xcc;

        err_code = nrf_ble_whitelist_add(&whitelist_addrs, &whitelist_number);
        APP_ERROR_CHECK(err_code);
}

Scanning with Whitelist

/**< Scan parameters requested for scanning and connection. */
static ble_gap_scan_params_t m_scan_param =
{
        .active        = NRF_BLE_SCAN_ACTIVE_SCANNING,           /* Disable the acvtive scanning */
        .interval      = NRF_BLE_SCAN_SCAN_INTERVAL,
        .window        = NRF_BLE_SCAN_SCAN_WINDOW,
        .filter_policy = BLE_GAP_SCAN_FP_WHITELIST,
        .timeout       = SCAN_DURATION_WHITELIST,
        .scan_phys     = BLE_GAP_PHY_1MBPS,
};

/**@brief Function for handling Scanning Module events.
 */
static void scan_evt_handler(scan_evt_t const * p_scan_evt)
{
        ret_code_t err_code;

        switch(p_scan_evt->scan_evt_id)
        {
        case NRF_BLE_SCAN_EVT_WHITELIST_REQUEST:
        {
                on_whitelist_req();
                m_whitelist_disabled = false;
        } break;

        case NRF_BLE_SCAN_EVT_CONNECTING_ERROR:
        {
                err_code = p_scan_evt->params.connecting_err.err_code;
                APP_ERROR_CHECK(err_code);
        } break;

        case NRF_BLE_SCAN_EVT_FILTER_MATCH:
                //NRF_LOG_INFO("NRF_BLE_SCAN_EVT_FILTER_MATCH");
                //p_scan_evt->params.connected.p_connected.

                break;

        case NRF_BLE_SCAN_EVT_WHITELIST_ADV_REPORT:

                NRF_LOG_INFO("NRF_BLE_SCAN_EVT_WHITELIST_ADV_REPORT");
                //                NRF_LOG_HEXDUMP_INFO(p_scan_evt->params.p_whitelist_adv_report, sizeof(p_scan_evt->params.p_whitelist_adv_report));

                break;

        case NRF_BLE_SCAN_EVT_CONNECTED:
        {
                ble_gap_evt_connected_t const * p_connected =
                        p_scan_evt->params.connected.p_connected;
                // Scan is automatically stopped by the connection.
                NRF_LOG_INFO("Connecting to target peripheral : 0x%02x%02x%02x%02x%02x%02x",
                             p_connected->peer_addr.addr[5],
                             p_connected->peer_addr.addr[4],
                             p_connected->peer_addr.addr[3],
                             p_connected->peer_addr.addr[2],
                             p_connected->peer_addr.addr[1],
                             p_connected->peer_addr.addr[0]
                             );
        } break;

        case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
        {
                NRF_LOG_INFO("Scan timed out.");
                scan_start();
        } break;

        default:
                break;
        }
}

If the whitelist is used, do not check the filters and return in original SDK 15.3.

In order to combine the whitelist and filters, I modify this as below.

How to get all the filter devices with MAC address and RSSI without connection

If you would like to get all the match devices, it can set

All the code is placed at https://github.com/jimmywong2003/nrf52-ble-central-scanner-with-whitelist.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.