mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-12-18 09:10:47 +01:00
Add extended scan features.
* Added new method `NimBLEScan::setScanPhy` to enable/disable the PHY's to scan on. * Added new method `NimBLEScan::setScanPeriod` which will allow for setting a scan restart timer in the controller. * Updated `NimBLEScan::start` to allow the command to be sent with updated parameters if already scanning. * Added extended scan example. * Removed storing and restarting of the scan on host reset as it is more appropriate to call the scanEnded callback instead.
This commit is contained in:
parent
db2fe36131
commit
3cb9adb61a
6 changed files with 168 additions and 48 deletions
7
examples/Bluetooth_5/NimBLE_extended_scan/CMakeLists.txt
Normal file
7
examples/Bluetooth_5/NimBLE_extended_scan/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32c3 esp32s3 esp32c6 esp32h2 esp32c2)
|
||||
project(NimBLE_extended_scan)
|
|
@ -0,0 +1,4 @@
|
|||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
68
examples/Bluetooth_5/NimBLE_extended_scan/main/main.cpp
Normal file
68
examples/Bluetooth_5/NimBLE_extended_scan/main/main.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* NimBLE Extended Scanner Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x scanning capabilities of the NimBLE library.
|
||||
*
|
||||
* Created: on November 28, 2024
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static uint32_t scanTime = 10 * 1000; // In milliseconds, 0 = scan forever
|
||||
static NimBLEScan::Phy scanPhy = NimBLEScan::Phy::SCAN_ALL;
|
||||
|
||||
// Define a class to handle the callbacks when advertisements are received
|
||||
class scanCallbacks: public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device found: %s\n PHY1: %d\n PHY2: %d\n", advertisedDevice->toString().c_str(),
|
||||
advertisedDevice->getPrimaryPhy(), advertisedDevice->getSecondaryPhy());
|
||||
}
|
||||
|
||||
// Callback to process the results of the completed scan or restart it
|
||||
void onScanEnd(const NimBLEScanResults& scanResults, int reason) {
|
||||
printf("Scan Ended, reason: %d; found %d devices\n", reason, scanResults.getCount());
|
||||
|
||||
// Try Different PHY's
|
||||
switch (scanPhy) {
|
||||
case NimBLEScan::Phy::SCAN_ALL:
|
||||
printf("Scanning only 1M PHY\n");
|
||||
scanPhy = NimBLEScan::Phy::SCAN_1M;
|
||||
break;
|
||||
case NimBLEScan::Phy::SCAN_1M:
|
||||
printf("Scanning only CODED PHY\n");
|
||||
scanPhy = NimBLEScan::Phy::SCAN_CODED;
|
||||
break;
|
||||
case NimBLEScan::Phy::SCAN_CODED:
|
||||
printf("Scanning all PHY's\n");
|
||||
scanPhy = NimBLEScan::Phy::SCAN_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setPhy(scanPhy);
|
||||
pScan->start(scanTime);
|
||||
}
|
||||
} scanCb;
|
||||
|
||||
extern "C" void app_main (void) {
|
||||
printf("Starting Extended Scanner\n");
|
||||
|
||||
// Initialize NimBLE, no device name specified as we are not advertising
|
||||
NimBLEDevice::init("");
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
// Set the callbacks that the scanner will call on events.
|
||||
pScan->setScanCallbacks(&scanCb);
|
||||
|
||||
// Use active scanning to obtain scan response data from advertisers
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
// Set the initial PHY's to scan on, default is SCAN_ALL
|
||||
pScan->setPhy(scanPhy);
|
||||
|
||||
// Start scanning for scanTime, 0 = forever
|
||||
pScan->start(scanTime);
|
||||
printf("Scanning for peripherals\n");
|
||||
}
|
13
examples/Bluetooth_5/NimBLE_extended_scan/sdkconfig.defaults
Normal file
13
examples/Bluetooth_5/NimBLE_extended_scan/sdkconfig.defaults
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
|
@ -32,7 +32,6 @@ NimBLEScan::NimBLEScan()
|
|||
: m_pScanCallbacks{&defaultScanCallbacks},
|
||||
// default interval + window, no whitelist scan filter,not limited scan, no scan response, filter_duplicates
|
||||
m_scanParams{0, 0, BLE_HCI_SCAN_FILT_NO_WL, 0, 1, 1},
|
||||
m_duration{BLE_HS_FOREVER},
|
||||
m_pTaskData{nullptr},
|
||||
m_maxResults{0xFF} {}
|
||||
|
||||
|
@ -173,11 +172,14 @@ void NimBLEScan::setActiveScan(bool active) {
|
|||
/**
|
||||
* @brief Set whether or not the BLE controller should only report results
|
||||
* from devices it has not already seen.
|
||||
* @param [in] enabled If true, scanned devices will only be reported once.
|
||||
* @details The controller has a limited buffer and will start reporting
|
||||
* duplicate devices once the limit is reached.
|
||||
* @param [in] enabled If set to 1 (true), scanned devices will only be reported once.
|
||||
* If set to 0 duplicates will be reported each time they are seen.
|
||||
* If using extended scanning this can be set to 2 which will reset the duplicate filter
|
||||
* at the end of each scan period if the scan period is set.
|
||||
* @note The controller has a limited buffer and will start reporting
|
||||
duplicate devices once the limit is reached.
|
||||
*/
|
||||
void NimBLEScan::setDuplicateFilter(bool enabled) {
|
||||
void NimBLEScan::setDuplicateFilter(uint8_t enabled) {
|
||||
m_scanParams.filter_duplicates = enabled;
|
||||
} // setDuplicateFilter
|
||||
|
||||
|
@ -219,7 +221,7 @@ void NimBLEScan::setFilterPolicy(uint8_t filter) {
|
|||
*/
|
||||
void NimBLEScan::setMaxResults(uint8_t maxResults) {
|
||||
m_maxResults = maxResults;
|
||||
}
|
||||
} // setMaxResults
|
||||
|
||||
/**
|
||||
* @brief Set the call backs to be invoked.
|
||||
|
@ -237,18 +239,20 @@ void NimBLEScan::setScanCallbacks(NimBLEScanCallbacks* pScanCallbacks, bool want
|
|||
|
||||
/**
|
||||
* @brief Set the interval to scan.
|
||||
* @param [in] intervalMSecs The scan interval (how often) in milliseconds.
|
||||
* @param [in] intervalMs The scan interval in milliseconds.
|
||||
* @details The interval is the time between the start of two consecutive scan windows.
|
||||
* When a new interval starts the controller changes the channel it's scanning on.
|
||||
*/
|
||||
void NimBLEScan::setInterval(uint16_t intervalMSecs) {
|
||||
m_scanParams.itvl = (intervalMSecs * 16) / 10;
|
||||
void NimBLEScan::setInterval(uint16_t intervalMs) {
|
||||
m_scanParams.itvl = (intervalMs * 16) / 10;
|
||||
} // setInterval
|
||||
|
||||
/**
|
||||
* @brief Set the window to actively scan.
|
||||
* @param [in] windowMSecs How long during the interval to actively scan.
|
||||
* @param [in] windowMs How long during the interval to actively scan in milliseconds.
|
||||
*/
|
||||
void NimBLEScan::setWindow(uint16_t windowMSecs) {
|
||||
m_scanParams.window = (windowMSecs * 16) / 10;
|
||||
void NimBLEScan::setWindow(uint16_t windowMs) {
|
||||
m_scanParams.window = (windowMs * 16) / 10;
|
||||
} // setWindow
|
||||
|
||||
/**
|
||||
|
@ -259,6 +263,29 @@ bool NimBLEScan::isScanning() {
|
|||
return ble_gap_disc_active();
|
||||
}
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Set the PHYs to scan.
|
||||
* @param [in] phyMask The PHYs to scan, a bit mask of:
|
||||
* * NIMBLE_CPP_SCAN_1M
|
||||
* * NIMBLE_CPP_SCAN_CODED
|
||||
*/
|
||||
void NimBLEScan::setPhy(Phy phyMask) {
|
||||
m_phy = phyMask;
|
||||
} // setScanPhy
|
||||
|
||||
/**
|
||||
* @brief Set the extended scanning period.
|
||||
* @param [in] periodMs The scan period in milliseconds
|
||||
* @details The period is the time between the start of two consecutive scan periods.
|
||||
* This works as a timer to restart scanning at the specified amount of time in periodMs.
|
||||
* @note The duration used when this is set must be less than period.
|
||||
*/
|
||||
void NimBLEScan::setPeriod(uint32_t periodMs) {
|
||||
m_period = (periodMs + 500) / 1280; // round up 1.28 second units
|
||||
} // setScanPeriod
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief Start scanning.
|
||||
* @param [in] duration The duration in milliseconds for which to scan. 0 == scan forever.
|
||||
|
@ -269,35 +296,24 @@ bool NimBLEScan::isScanning() {
|
|||
*/
|
||||
bool NimBLEScan::start(uint32_t duration, bool isContinue, bool restart) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start: duration=%" PRIu32, duration);
|
||||
|
||||
if (ble_gap_conn_active()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection in progress, cannot start scan");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isScanning()) {
|
||||
if (restart) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Scan already in progress, restarting it");
|
||||
if (!stop()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
NIMBLE_LOGI(LOG_TAG, "Scan already in progress");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isContinue) {
|
||||
clearResults();
|
||||
}
|
||||
|
||||
// Save the duration in the case that the host is reset so we can reuse it.
|
||||
m_duration = duration;
|
||||
|
||||
// If 0 duration specified then we assume a continuous scan is desired.
|
||||
if (duration == 0) {
|
||||
duration = BLE_HS_FOREVER;
|
||||
}
|
||||
} else { // Don't clear results while scanning is active
|
||||
if (!isContinue) {
|
||||
clearResults();
|
||||
}
|
||||
}
|
||||
|
||||
// If scanning is already active, call the functions anyway as the parameters can be changed.
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
ble_gap_ext_disc_params scan_params;
|
||||
|
@ -305,17 +321,21 @@ bool NimBLEScan::start(uint32_t duration, bool isContinue, bool restart) {
|
|||
scan_params.itvl = m_scanParams.itvl;
|
||||
scan_params.window = m_scanParams.window;
|
||||
int rc = ble_gap_ext_disc(NimBLEDevice::m_ownAddrType,
|
||||
duration / 10,
|
||||
0,
|
||||
duration / 10, // 10ms units
|
||||
m_period,
|
||||
m_scanParams.filter_duplicates,
|
||||
m_scanParams.filter_policy,
|
||||
m_scanParams.limited,
|
||||
&scan_params,
|
||||
&scan_params,
|
||||
m_phy & SCAN_1M ? &scan_params : NULL,
|
||||
m_phy & SCAN_CODED ? &scan_params : NULL,
|
||||
NimBLEScan::handleGapEvent,
|
||||
NULL);
|
||||
# else
|
||||
int rc = ble_gap_disc(NimBLEDevice::m_ownAddrType, duration, &m_scanParams, NimBLEScan::handleGapEvent, NULL);
|
||||
int rc = ble_gap_disc(NimBLEDevice::m_ownAddrType,
|
||||
duration ? duration : BLE_HS_FOREVER,
|
||||
&m_scanParams,
|
||||
NimBLEScan::handleGapEvent,
|
||||
NULL);
|
||||
# endif
|
||||
switch (rc) {
|
||||
case 0:
|
||||
|
@ -403,9 +423,7 @@ void NimBLEScan::erase(const NimBLEAdvertisedDevice* device) {
|
|||
* If the application was scanning indefinitely with a callback, restart it.
|
||||
*/
|
||||
void NimBLEScan::onHostSync() {
|
||||
if (m_duration == 0 && m_pScanCallbacks != &defaultScanCallbacks) {
|
||||
start(0, false);
|
||||
}
|
||||
m_pScanCallbacks->onScanEnd(m_scanResults, BLE_HS_ENOTSYNCED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
* Created on: Jul 1, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#ifndef COMPONENTS_NIMBLE_SCAN_H_
|
||||
#define COMPONENTS_NIMBLE_SCAN_H_
|
||||
#ifndef NIMBLE_CPP_SCAN_H_
|
||||
#define NIMBLE_CPP_SCAN_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
@ -66,9 +66,9 @@ class NimBLEScan {
|
|||
bool isScanning();
|
||||
void setScanCallbacks(NimBLEScanCallbacks* pScanCallbacks, bool wantDuplicates = false);
|
||||
void setActiveScan(bool active);
|
||||
void setInterval(uint16_t intervalMSecs);
|
||||
void setWindow(uint16_t windowMSecs);
|
||||
void setDuplicateFilter(bool enabled);
|
||||
void setInterval(uint16_t intervalMs);
|
||||
void setWindow(uint16_t windowMs);
|
||||
void setDuplicateFilter(uint8_t enabled);
|
||||
void setLimitedOnly(bool enabled);
|
||||
void setFilterPolicy(uint8_t filter);
|
||||
bool stop();
|
||||
|
@ -79,6 +79,12 @@ class NimBLEScan {
|
|||
void erase(const NimBLEAddress& address);
|
||||
void erase(const NimBLEAdvertisedDevice* device);
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
enum Phy { SCAN_1M = 0x01, SCAN_CODED = 0x02, SCAN_ALL = 0x03 };
|
||||
void setPhy(Phy phyMask);
|
||||
void setPeriod(uint32_t periodMs);
|
||||
# endif
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
|
||||
|
@ -90,9 +96,13 @@ class NimBLEScan {
|
|||
NimBLEScanCallbacks* m_pScanCallbacks;
|
||||
ble_gap_disc_params m_scanParams;
|
||||
NimBLEScanResults m_scanResults;
|
||||
uint32_t m_duration;
|
||||
NimBLETaskData* m_pTaskData;
|
||||
uint8_t m_maxResults;
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
uint8_t m_phy{SCAN_ALL};
|
||||
uint16_t m_period{0};
|
||||
# endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -122,5 +132,5 @@ class NimBLEScanCallbacks {
|
|||
virtual void onScanEnd(const NimBLEScanResults& scanResults, int reason);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
#endif /* COMPONENTS_NIMBLE_SCAN_H_ */
|
||||
#endif // CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||
#endif // NIMBLE_CPP_SCAN_H_
|
||||
|
|
Loading…
Reference in a new issue