BLEScanner

The Bluefruit nRF52 BSP codebase is undergoing active development based on customer feedback and testing. As such, the class documentation here is incomplete, and you should consult the Github repo for the latest code and API developments: https://goo.gl/LdEx62
This documentation is based on BSP 0.7.0 and higher. Please make sure you have an up to date version before using the code below.

The BLEScanner class is used in Central Mode, and facilitates scanning for BLE peripherals in range and parsing the advertising data that is being sent out by the peripherals.

The BLEScanner class is normally accessed via the Bluefruit class (instantiated at startup), as shown below:

Download: file
/* Start Central Scanning
 * - Enable auto scan if disconnected
 * - Filter for devices with a min RSSI of -80 dBm
 * - Interval = 100 ms, window = 50 ms
 * - Use active scan (requests the optional scan response packet)
 * - Start(0) = will scan forever since no timeout is given
 */
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.restartOnDisconnect(true);
Bluefruit.Scanner.filterRssi(-80);            // Only invoke callback when RSSI >= -80 dBm
Bluefruit.Scanner.setInterval(160, 80);       // in units of 0.625 ms
Bluefruit.Scanner.useActiveScan(true);        // Request scan response data
Bluefruit.Scanner.start(0);                   // 0 = Don't stop scanning after n seconds

API

BLEScanner has the following public API:

Download: file
typedef void (*rx_callback_t) (ble_gap_evt_adv_report_t*);
typedef void (*stop_callback_t) (void);

BLEScanner(void);

ble_gap_scan_params_t* getParams(void);
bool isRunning(void);

void useActiveScan(bool enable);
void setInterval(uint16_t interval, uint16_t window);
void setIntervalMS(uint16_t interval, uint16_t window);
void restartOnDisconnect(bool enable);

void filterRssi(int8_t min_rssi);
void filterMSD(uint16_t manuf_id);

void filterUuid(BLEUuid ble_uuid);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3, BLEUuid ble_uuid4);
void filterUuid(BLEUuid ble_uuid[], uint8_t count);

void clearFilters(void);

bool start(uint16_t timeout = 0);
bool stop(void);

/*------------- Callbacks -------------*/
void setRxCallback(rx_callback_t fp);
void setStopCallback(stop_callback_t fp);

/*------------- Data Parser -------------*/
uint8_t parseReportByType(const uint8_t* scandata, uint8_t scanlen, uint8_t type, uint8_t* buf, uint8_t bufsize = 0);
uint8_t parseReportByType(const ble_gap_evt_adv_report_t* report, uint8_t type, uint8_t* buf, uint8_t bufsize = 0);

bool    checkReportForUuid(const ble_gap_evt_adv_report_t* report, BLEUuid ble_uuid);
bool    checkReportForService(const ble_gap_evt_adv_report_t* report, BLEClientService svc);
bool    checkReportForService(const ble_gap_evt_adv_report_t* report, BLEService svc);

setRxCallback(rx_callback_t fp)

Whenever a valid advertising packet is detected (based on any optional filters that are applied in the BLEScanner class), a dedicated callback function (see rx_callback_t) will be called.

The callback function has the following signature:

NOTE: ble_gap_evt_adv_report_t is part of the Nordic nRF52 SD and is defined in ble_gap.h

Download: file
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  /* Display the timestamp and device address */
  if (report->scan_rsp)
  {
    /* This is a Scan Response packet */
    Serial.printf("[SR%10d] Packet received from ", millis());
  }
  else
  {
    /* This is a normal advertising packet */
    Serial.printf("[ADV%9d] Packet received from ", millis());
  }
  Serial.printBuffer(report->peer_addr.addr, 6, ':');
  Serial.print("\n");

  /* Raw buffer contents */
  Serial.printf("%14s %d bytes\n", "PAYLOAD", report->dlen);
  if (report->dlen)
  {
    Serial.printf("%15s", " ");
    Serial.printBuffer(report->data, report->dlen, '-');
    Serial.println();
  }

  /* RSSI value */
  Serial.printf("%14s %d dBm\n", "RSSI", report->rssi);

  /* Adv Type */
  Serial.printf("%14s ", "ADV TYPE");
  switch (report->type)
  {
    case BLE_GAP_ADV_TYPE_ADV_IND:
      Serial.printf("Connectable undirected\n");
      break;
    case BLE_GAP_ADV_TYPE_ADV_DIRECT_IND:
      Serial.printf("Connectable directed\n");
      break;
    case BLE_GAP_ADV_TYPE_ADV_SCAN_IND:
      Serial.printf("Scannable undirected\n");
      break;
    case BLE_GAP_ADV_TYPE_ADV_NONCONN_IND:
      Serial.printf("Non-connectable undirected\n");
      break;
  }

  /* Check for BLE UART UUID */
  if ( Bluefruit.Scanner.checkReportForUuid(report, BLEUART_UUID_SERVICE) )
  {
    Serial.printf("%14s %s\n", "BLE UART", "UUID Found!");
  }

  /* Check for DIS UUID */
  if ( Bluefruit.Scanner.checkReportForUuid(report, UUID16_SVC_DEVICE_INFORMATION) )
  {
    Serial.printf("%14s %s\n", "DIS", "UUID Found!");
  }

  Serial.println();
}

void useActiveScan(bool enable);

Enabling 'Active Scan' by setting the enable parameter to 1 will cause the device to request the optional Scan Response advertising packet, which is a second 31 byte advertising packet that can be used to transmit additional information.

By default active scanning is disabled, so no Scan Response packets will be received by BLEScanner unless this function is called and set to 1 before calling Bluefruit.Scanner.start(0).

void filterRssi(int8_t min_rssi);
void filterMSD(uint16_t manuf_id);
void filterUuid(BLEUuid ble_uuid);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3, BLEUuid ble_uuid4);
void filterUuid(BLEUuid ble_uuid[], uint8_t count);

Filters can be applied to BLEScanner to narrow down the data sent to the callback handler, and make processing advertising packets easier for you.

As of BSP 0.7.0 the following three filters are present:

  • filterRssi(int8_t min_rssi): Filters advertising results to devices with at least the specified RSSI value, which allows you to ignore devices that are too far away or whose signal is too weak. The higher the number, the strong the signal so -90 is a very weak signal, and -60 is a much stronger one.
  • filterUuid(BLEUuid ble_uuid): Filters advertising results to devices that advertise themselves as having the specified service UUID. If multiple UUIDs are entered, they will be filtered with boolean OR logic, meaning any single UUID present will be considered a match.
  • void filterMSD(uint16_t manuf_id): Fitlers advertising results to devices that contain a Manufacturer Specific Data data type, and who use the specifed Bluetooth Customer ID (manuf_id). This can be useful to filter iBeacon versus Eddystone devices, for example, which both used the MSD field, or to look for custom MSD data matching your own CID.
When multiple UUIDs are added via one of the .filterUuid(...) functions, they UUIDs will be filtered using boolean 'OR' logic, meaning that the callback will fire when ANY of the specified UUIDs are detected in the advertising packet.

void clearFilters(void);

This function clears and filter values set using the functions above.

bool start(uint16_t timeout = 0);
bool stop(void);

The .start and .stop functions can be used to start and stop scanning, and should be called after all of the main parameters (timing, filters, etc.) have been set.

The .start function has a single parameter called timeout, which sets the number of seconds to scan for advertising packets. Setting this to '0' (the default value) will cause the device to scan forever.

Make sure you set any filters of BLEScanner parameters before calling .start!

void restartOnDisconnect(bool enable);

Setting this function to '1' will cause the scanning process to start again as soon as you disconnect from a peripheral device. The default behaviour is to automatically restart scanning on disconnect.

Examples

For an example that uses almost all of the BLEScanner and advertising API in Central mode, see central_scan_advanced.ino in the Central examples folder.

This example is only available in BSP 0.7.0 and higher!
This guide was first published on Mar 22, 2017. It was last updated on Mar 22, 2017. This page (BLEScanner) was last updated on Jul 20, 2019.